Combine Sales and Transfer Orders on a Single Business Central Page

tyefender Avatar



Screenshot of Business Central interface showing the combined Sales and Transfer Orders page.

In the world of Microsoft Dynamics 365 Business Central customization, creating solutions that streamline operations is key to enhancing business efficiency. This blog post explores a unique customization that Combine Sales and Transfer Orders in Business Central. This advanced solution, not widely discussed online, aims to foster operational harmony and efficiency. Dive into our journey from conceptualization to implementation and discover how it might benefit your operations.

Project Background and Objectives

In this Business Central customization project, our objective was to transform traditional, manual scheduling processes into a digital, efficient, and visually appealing system. Below is an image of the traditional whiteboard used before our enhancements:

Before image showing the traditional whiteboard used for scheduling sales and transfer orders.

By displaying Sales Orders (Table 36) and Transfer Orders (Table 5740) on the same page, we aimed to provide the Operations Manager with a comprehensive view for effective weekly scheduling, enhancing decision-making and resource allocation.

The Solution

Creating a Temporary Table

We started by developing a temporary table to aggregate selected data fields from Sales Header and Transfer Order records, ensuring a seamless integration of information. Here’s how we set it up:

table 50210 "Combined Orders Overview" // This temporary table is used to aggregate and display a combined view of sales and transfer orders for the Combined Orders Overview. { DataClassification = ToBeClassified; TableType = Temporary; fields { // Stores the unique identifier for each order field(1; "Order No."; Code[8]) { DataClassification = CustomerContent; } // Stores the name of the customer or the branch for the order field(2; "Customer Name"; Text[100]) { DataClassification = CustomerContent; } // Stores the date when the order is expected to be shipped field(3; "Shipment Date"; Date) { DataClassification = CustomerContent; } // Your Reference and Transfer Notes (Transfer Notes is a custom field in this environment) field(4; "Reference"; Text[100]) { DataClassification = CustomerContent; } // Package Tracking No and BNE Notes (BNE Notes is a custom field in this environment) field(5; "Tracking No"; Text[100]) { DataClassification = CustomerContent; } field(6; "External Document No"; Text[100]) { DataClassification = CustomerContent; } // Enum used to differentiate between Sales or Transfer field(7; "Order Type"; Enum "Order Type") { DataClassification = CustomerContent; } // For text formatting field(8; "SetColourBasedOnDate"; Text[100]) { DataClassification = CustomerContent; } } keys { key(PK; "Order No.") //primary key { Clustered = false; } } // For formatting the tile view // See: fieldgroups { fieldgroup(Brick; "Order No.", "Customer Name", "Shipment Date", "Reference", "External Document No", "Tracking No") { } } } enum 50210 "Order Type" { value(0; "SalesOrder") { Caption = 'Sales Order'; } value(1; "TransferOrder") { Caption = 'Transfer Order'; } }

Codeunit Development

Next, we developed a codeunit object responsible for populating the temporary table with the necessary data, considering specific business logic and requirements.

codeunit 50210 "Populate Orders Overview" // Populates the temporary table with orders based on filters and conditions { procedure PopulateOrdersTempTable(var TempCombinedOrdersOverview: Record "Combined Orders Overview" temporary) var SalesHeader: Record "Sales Header"; TransferOrderHeader: Record "Transfer Header"; DimensionSetEntry: Record "Dimension Set Entry"; DateFilter: Text; DimensionCode: Code[20]; DimensionValue: Code[20]; DimensionFilter: Text; begin DateFilter := ''; // Adjust this filter as necessary. DimensionFilter := 'W'; DimensionCode := 'DIVISION'; Clear(TempCombinedOrdersOverview); // Populate from Sales Orders SalesHeader.SetRange("Document Type", SalesHeader."Document Type"::Order); SalesHeader.SetFilter("Shipment Date", DateFilter); if SalesHeader.FindSet() then repeat if CheckSalesOrderDimension(SalesHeader."Dimension Set ID", DimensionCode, DimensionFilter) then begin TempCombinedOrdersOverview.Init(); TempCombinedOrdersOverview."Order No." := SalesHeader."No."; TempCombinedOrdersOverview."Order Type" := TempCombinedOrdersOverview."Order Type"::SalesOrder; TempCombinedOrdersOverview."Shipment Date" := SalesHeader."Shipment Date"; TempCombinedOrdersOverview."Customer Name" := SalesHeader."Ship-to Name"; TempCombinedOrdersOverview."External Document No" := SalesHeader."External Document No."; TempCombinedOrdersOverview."Reference" := SalesHeader."Your Reference"; TempCombinedOrdersOverview."Tracking No" := SalesHeader."Package Tracking No."; if SalesHeader."Shipment Date" = Today() then TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Favorable' else if SalesHeader."Shipment Date" < Today() then TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Attention' else TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Standard'; TempCombinedOrdersOverview.Insert(); end; until SalesHeader.Next() = 0; // Populate from Transfer Orders TransferOrderHeader.SetFilter("Shipment Date", DateFilter); if TransferOrderHeader.FindSet() then repeat TempCombinedOrdersOverview.Init(); TempCombinedOrdersOverview."Order No." := TransferOrderHeader."No."; TempCombinedOrdersOverview."Order Type" := TempCombinedOrdersOverview."Order Type"::TransferOrder; TempCombinedOrdersOverview."Shipment Date" := TransferOrderHeader."Shipment Date"; TempCombinedOrdersOverview."Customer Name" := TransferOrderHeader."Transfer-to Name"; TempCombinedOrdersOverview."Reference" := TransferOrderHeader."Transfer Notes"; TempCombinedOrdersOverview."Tracking No" := TransferOrderHeader."Brisbane Notes"; if TransferOrderHeader."Shipment Date" = Today() then TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Favorable' else if TransferOrderHeader."Shipment Date" < Today() then TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Attention' else TempCombinedOrdersOverview."SetColourBasedOnDate" := 'Standard'; TempCombinedOrdersOverview.Insert(); until TransferOrderHeader.Next() = 0; end; // Checks if a sales order matches the specified dimension criteria local procedure CheckSalesOrderDimension(DimensionSetID: Integer; DimensionCode: Code[20]; DimensionValue: Code[20]): Boolean var DimensionSetEntry: Record "Dimension Set Entry"; begin DimensionSetEntry.SetRange("Dimension Set ID", DimensionSetID); if DimensionSetEntry.FindSet() then repeat if (DimensionSetEntry."Dimension Code" = DimensionCode) and (DimensionSetEntry."Dimension Value Code" = DimensionValue) then exit(true); until DimensionSetEntry.Next() = 0; exit(false); end; }

User Interface Design

To present the combined data, we designed a Business Central page that not only displays the Sales and Transfer Orders together but also includes direct actions to open orders from the interface, enhancing user experience and efficiency. The design is colour-coded based on shipment dates, indicating overdue, current, or future shipments.

One of the key enhancements in our Business Central customization is the integration of a user-friendly feature—an action button that allows users to open orders directly from the newly created page. This addition significantly improves user interaction and efficiency, providing quick access to detailed order information.

// Create the page to show the temporary table page 50212 "Combined Orders Schedule" { PageType = List; SourceTable = "Combined Orders Overview"; ApplicationArea = All; UsageCategory = Lists; Caption = 'Combined Orders Schedule'; layout { area(content) { repeater(General) { field("Order No."; Rec."Order No.") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Order Number'; Tooltip = 'The Ship-to Name of the customer or Branch for the order.'; } field("Customer Name"; Rec."Customer Name") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Customer Name'; ToolTip = 'Customer or Branch Name'; } field("Shipment Date"; Rec."Shipment Date") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Shipment Date'; ToolTip = 'Shipment Date'; } field("Reference"; Rec."Reference") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Reference'; ToolTip = '"Your Reference" field on Sales Orders and "Transfer Notes" field on Transfer Orders.'; } field("Brisbane Notes"; Rec."Tracking No") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Tracking No'; ToolTip = '"Package Tracking No." field on Sales Orders and "Brisbane Notes" field on Transfer Orders'; } field("External Document No"; Rec."External Document No") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'External Document No.'; ToolTip = 'External Document No.'; } field("Order Type"; Rec."Order Type") { ApplicationArea = All; StyleExpr = (Rec."SetColourBasedOnDate"); Caption = 'Order Type'; ToolTip = 'Specificies if the Order is a Sale or Transfer'; } } } } // Create an action to enable opening the Sale or Transfer Order directly from the page actions { area(processing) { action("Open Related Order") { ApplicationArea = All; Caption = 'Open Order'; ToolTip = 'Open the selected order.'; Image = MakeOrder; Promoted = true; PromotedCategory = Process; PromotedIsBig = true; trigger OnAction() begin OpenRelatedOrder(Rec); end; } } } trigger OnOpenPage(); var PopulateOrdersCodeunit: Codeunit "Populate Orders Overview"; begin Rec.SetCurrentKey("Shipment Date"); PopulateOrdersCodeunit.PopulateOrdersTempTable(Rec); end; local procedure OpenRelatedOrder(OrderRec: Record "Combined Orders Overview") var SalesOrderRec: Record "Sales Header"; TransferOrderRec: Record "Transfer Header"; PageManagement: Codeunit "Page Management"; begin if OrderRec."Order Type" = OrderRec."Order Type"::SalesOrder then begin if SalesOrderRec.Get(SalesOrderRec."Document Type"::Order, OrderRec."Order No.") then Page.Run(Page::"Sales Order", SalesOrderRec); end else if OrderRec."Order Type" = OrderRec."Order Type"::TransferOrder then begin if TransferOrderRec.Get(OrderRec."Order No.") then Page.Run(Page::"Transfer Order", TransferOrderRec); end; end; }

Digital Dashboard Implementation

Finalizing the customization, we implemented a digital dashboard displayed on a TV, powered by a Raspberry Pi 5, to visually manage and schedule orders. This modern approach not only enhances workspace aesthetics but also boosts team engagement with Business Central functionalities. Below is an image of the new digital dashboard in action:

After image of a digital dashboard displaying sales and transfer orders on a TV screen, powered by Business Central.

The simple and temporary approach is to use multiple browser windows and Business Central List Views. In a future project with the same client, we will create a customized Role Centre which will display all of the information on the Business Central home page!

To keep the dashboard live and running continuously, we installed auto refresh plus extension on the browser to prevent Business Central from timing out.

Conclusion: The Impact and Your Feedback

To wrap up, our innovative approach to combine Sales and Transfer Orders in Business Central has markedly improved our operational efficiency and enhanced the daily experiences of our team. This project is a testament to what can be achieved with thoughtful customization and a deep understanding of user needs. Do you have similar stories of transformation or tips to share? Drop a comment below—we’d love to hear about your successes and exchange ideas to further harness the power of Business Central.

Computer displaying the words "do more".

Schedule a Free Consultation

Ready to optimize your Business Central setup? Schedule your free consultation today and take the first step towards seamless business operations!

Please enable JavaScript in your browser to complete this form.