From eb8dd44d5e1dac370506324c3904d1de269cc7c0 Mon Sep 17 00:00:00 2001 From: aidasberesinevicius <31065713+aidasberesinevicius@users.noreply.github.com> Date: Mon, 29 Jul 2024 20:51:53 +0300 Subject: [PATCH] [Shopify] Connector - Different shipping charges types (#26708) This pull request does not have a related issue as it's part of delivery for development agreed directly with @AndreiPanko Quick summary: The Shopify Shipping Method Mapping page/table was extended to include a new Shipping Charges Type field, allowing users to select from GL, Item, or Item Charge. Depending on this selection, the Shipping Charges No. field opens the related table (item, GL, or item charges), and when an order is created, the shipping charge line reflects the new type and number. For Item Charges, a default allocation process is run for all item lines. The settings in the Shopify Shipping Method Mapping now take priority over those in the Shopify Shop - GL Account settings. Additionally, if the Shipping Agent Code and Shipping Agent Service fields are populated, they are automatically populated in the sales order as well. Fixes #26819 [AB#449477](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/449477) --------- Co-authored-by: aidasberesinevicius Co-authored-by: Tine Staric --- .../Codeunits/ShpfyOrderEvents.Codeunit.al | 19 +++ .../Codeunits/ShpfyOrderMapping.Codeunit.al | 22 ++++ .../Codeunits/ShpfyProcessOrder.Codeunit.al | 117 +++++++++++++++++- .../Order handling/Pages/ShpfyOrder.Page.al | 10 ++ .../Tables/ShpfyOrderHeader.Table.al | 16 +++ .../Pages/ShpfyShipmentMethodsMapping.Page.al | 21 ++++ .../ShpfyShipmentMethodMapping.Table.al | 52 ++++++++ 7 files changed, 253 insertions(+), 4 deletions(-) diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al index 7ec64dae1c..ada8e63e93 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderEvents.Codeunit.al @@ -78,6 +78,25 @@ codeunit 30162 "Shpfy Order Events" begin end; + [IntegrationEvent(false, false)] + /// + /// Description for OnBeforeMapShipmentAgent. + /// + /// Parameter of type Record "Shopify Order Header". + /// Parameter of type Boolean. + internal procedure OnBeforeMapShipmentAgent(var ShopifyOrderHeader: Record "Shpfy Order Header"; var Handled: Boolean) + begin + end; + + [IntegrationEvent(false, false)] + /// + /// Description for OnAfterMapShipmentAgent. + /// + /// Parameter of type Record "Shopify Order Header". + internal procedure OnAfterMapShipmentAgent(var ShopifyOrderHeader: Record "Shpfy Order Header") + begin + end; + [IntegrationEvent(false, false)] /// /// Description for OnBeforeMapPaymentMethod. diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al index ca765c3291..0193e9c612 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyOrderMapping.Codeunit.al @@ -127,6 +127,7 @@ codeunit 30163 "Shpfy Order Mapping" end; MapShippingMethodCode(OrderHeader); + MapShippingAgent(OrderHeader); MapPaymentMethodCode(OrderHeader); OrderHeader.Modify(); exit((OrderHeader."Bill-to Customer No." <> '') and (OrderHeader."Sell-to Customer No." <> '')); @@ -163,6 +164,7 @@ codeunit 30163 "Shpfy Order Mapping" end; MapShippingMethodCode(OrderHeader); + MapShippingAgent(OrderHeader); MapPaymentMethodCode(OrderHeader); OrderHeader.Modify(); exit((OrderHeader."Bill-to Customer No." <> '') and (OrderHeader."Sell-to Customer No." <> '')); @@ -247,6 +249,26 @@ codeunit 30163 "Shpfy Order Mapping" end; end; + local procedure MapShippingAgent(var OrderHeader: Record "Shpfy Order Header") + var + OrderShippingCharges: Record "Shpfy Order Shipping Charges"; + ShipmentMethodMapping: Record "Shpfy Shipment Method Mapping"; + IsHandled: Boolean; + begin + if OrderHeader."Shipping Agent Code" = '' then begin + OrderEvents.OnBeforeMapShipmentAgent(OrderHeader, IsHandled); + if not IsHandled then begin + OrderShippingCharges.SetRange("Shopify Order Id", OrderHeader."Shopify Order Id"); + if OrderShippingCharges.FindFirst() then + if ShipmentMethodMapping.Get(OrderHeader."Shop Code", OrderShippingCharges.Title) then begin + OrderHeader."Shipping Agent Code" := ShipmentMethodMapping."Shipping Agent Code"; + OrderHeader."Shipping Agent Service Code" := ShipmentMethodMapping."Shipping Agent Service Code"; + end; + OrderEvents.OnAfterMapShipmentAgent(OrderHeader); + end; + end; + end; + local procedure MapPaymentMethodCode(var OrderHeader: Record "Shpfy Order Header") var OrderTransaction: Record "Shpfy Order Transaction"; diff --git a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al index a9ea62de6b..c2dadeb483 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al +++ b/Apps/W1/Shopify/app/src/Order handling/Codeunits/ShpfyProcessOrder.Codeunit.al @@ -1,6 +1,7 @@ namespace Microsoft.Integration.Shopify; using Microsoft.Inventory.Item; +using Microsoft.Finance.Currency; using Microsoft.Sales.Document; using Microsoft.Foundation.Address; using Microsoft.Sales.History; @@ -118,6 +119,10 @@ codeunit 30166 "Shpfy Process Order" SalesHeader.Validate("Tax Area Code", ShopifyTaxArea."Tax Area Code"); if ShopifyOrderHeader."Shipping Method Code" <> '' then SalesHeader.Validate("Shipment Method Code", ShopifyOrderHeader."Shipping Method Code"); + if ShopifyOrderHeader."Shipping Agent Code" <> '' then begin + SalesHeader.Validate("Shipping Agent Code", ShopifyOrderHeader."Shipping Agent Code"); + SalesHeader.Validate("Shipping Agent Service Code", ShopifyOrderHeader."Shipping Agent Service Code"); + end; if ShopifyOrderHeader."Payment Method Code" <> '' then SalesHeader.Validate("Payment Method Code", ShopifyOrderHeader."Payment Method Code"); @@ -173,8 +178,10 @@ codeunit 30166 "Shpfy Process Order" ShopifyOrderLine: Record "Shpfy Order Line"; OrderShippingCharges: Record "Shpfy Order Shipping Charges"; ShopLocation: Record "Shpfy Shop Location"; + ShipmentMethodMapping: Record "Shpfy Shipment Method Mapping"; SuppressAsmWarning: Codeunit "Shpfy Suppress Asm Warning"; IsHandled: Boolean; + ShipmentChargeType: Boolean; ShopfyOrderNoLbl: Label 'Shopify Order No.: %1', Comment = '%1 = Order No.'; begin BindSubscription(SuppressAsmWarning); @@ -230,12 +237,21 @@ codeunit 30166 "Shpfy Process Order" OrderShippingCharges.Reset(); OrderShippingCharges.SetRange("Shopify Order Id", ShopifyOrderHeader."Shopify Order Id"); OrderShippingCharges.SetFilter(Amount, '>0'); - if OrderShippingCharges.FindSet() then begin - ShopifyShop.TestField("Shipping Charges Account"); + if OrderShippingCharges.FindSet() then repeat IsHandled := false; OrderEvents.OnBeforeCreateShippingCostSalesLine(ShopifyOrderHeader, OrderShippingCharges, SalesHeader, SalesLine, IsHandled); if not IsHandled then begin + + if ShipmentMethodMapping.Get(ShopifyShop.Code, OrderShippingCharges.Title) then + if ShipmentMethodMapping."Shipping Charges Type" <> ShipmentMethodMapping."Shipping Charges Type"::" " then begin + ShipmentMethodMapping.TestField("Shipping Charges No."); + ShipmentChargeType := true; + end; + + if not ShipmentChargeType then + ShopifyShop.TestField("Shipping Charges Account"); + SalesLine.Init(); SalesLine.SetHideValidationDialog(true); SalesLine.Validate("Document Type", SalesHeader."Document Type"); @@ -243,18 +259,111 @@ codeunit 30166 "Shpfy Process Order" SalesLine.Validate("Line No.", GetNextLineNo(SalesHeader)); SalesLine.Insert(true); - SalesLine.Validate(Type, SalesLine.Type::"G/L Account"); - SalesLine.Validate("No.", ShopifyShop."Shipping Charges Account"); + if ShipmentChargeType then begin + SalesLine.Validate(Type, ShipmentMethodMapping."Shipping Charges Type"); + SalesLine.Validate("No.", ShipmentMethodMapping."Shipping Charges No."); + end else begin + SalesLine.Validate(Type, SalesLine.Type::"G/L Account"); + SalesLine.Validate("No.", ShopifyShop."Shipping Charges Account"); + end; + + SalesLine.Validate("Shipping Agent Code", ShipmentMethodMapping."Shipping Agent Code"); + SalesLine.Validate("Shipping Agent Service Code", ShipmentMethodMapping."Shipping Agent Service Code"); SalesLine.Validate(Quantity, 1); SalesLine.Validate(Description, OrderShippingCharges.Title); SalesLine.Validate("Unit Price", OrderShippingCharges.Amount); SalesLine.Validate("Line Discount Amount", OrderShippingCharges."Discount Amount"); SalesLine."Shpfy Order No." := ShopifyOrderHeader."Shopify Order No."; SalesLine.Modify(true); + + if SalesLine.Type = SalesLine.Type::"Charge (Item)" then + AssignItemCharges(SalesHeader, SalesLine); end; OrderEvents.OnAfterCreateShippingCostSalesLine(ShopifyOrderHeader, OrderShippingCharges, SalesHeader, SalesLine); until OrderShippingCharges.Next() = 0; + end; + + local procedure AssignItemCharges(SalesHeader: Record "Sales Header"; SalesLine: Record "Sales Line") + var + AssignItemChargeSales: Codeunit "Item Charge Assgnt. (Sales)"; + ItemChargeAssgntLineAmt: Decimal; + AssignableQty: Decimal; + begin + SalesLine.TestField("No."); + SalesLine.TestField(Quantity); + + PrepareAssignItemChargesLines(SalesHeader, SalesLine, AssignableQty, ItemChargeAssgntLineAmt); + AssignItemChargeSales.AssignItemCharges(SalesLine, AssignableQty, ItemChargeAssgntLineAmt, AssignableQty, ItemChargeAssgntLineAmt, AssignItemChargeSales.AssignEquallyMenuText()); + end; + + local procedure PrepareAssignItemChargesLines( + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + var AssignableQty: Decimal; + var ItemChargeAssgntLineAmt: Decimal + ) + var + ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)"; + begin + GetItemChargeAssgntLineAmt(SalesHeader, SalesLine, ItemChargeAssgntSales, ItemChargeAssgntLineAmt); + GetAssignableQty(SalesLine, ItemChargeAssgntSales, AssignableQty); + end; + + local procedure GetItemChargeAssgntLineAmt( + SalesHeader: Record "Sales Header"; + SalesLine: Record "Sales Line"; + var ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)"; + var ItemChargeAssgntLineAmt: Decimal + ) + var + Currency: Record Currency; + begin + SalesHeader := SalesLine.GetSalesHeader(); + Currency.Initialize(SalesHeader."Currency Code"); + if (SalesLine."Inv. Discount Amount" = 0) and (SalesLine."Line Discount Amount" = 0) and + (not SalesHeader."Prices Including VAT") + then + ItemChargeAssgntLineAmt := SalesLine."Line Amount" + else + if SalesHeader."Prices Including VAT" then + ItemChargeAssgntLineAmt := + Round(SalesLine.CalcLineAmount() / (1 + SalesLine."VAT %" / 100), Currency."Amount Rounding Precision") + else + ItemChargeAssgntLineAmt := SalesLine.CalcLineAmount(); + + ItemChargeAssgntSales.Reset(); + ItemChargeAssgntSales.SetRange("Document Type", SalesLine."Document Type"); + ItemChargeAssgntSales.SetRange("Document No.", SalesLine."Document No."); + ItemChargeAssgntSales.SetRange("Document Line No.", SalesLine."Line No."); + ItemChargeAssgntSales.SetRange("Item Charge No.", SalesLine."No."); + if not ItemChargeAssgntSales.FindLast() then begin + ItemChargeAssgntSales."Document Type" := SalesLine."Document Type"; + ItemChargeAssgntSales."Document No." := SalesLine."Document No."; + ItemChargeAssgntSales."Document Line No." := SalesLine."Line No."; + ItemChargeAssgntSales."Item Charge No." := SalesLine."No."; + ItemChargeAssgntSales."Unit Cost" := + Round(ItemChargeAssgntLineAmt / SalesLine.Quantity, Currency."Unit-Amount Rounding Precision"); end; + + ItemChargeAssgntLineAmt := + Round(ItemChargeAssgntLineAmt * (SalesLine."Qty. to Invoice" / SalesLine.Quantity), Currency."Amount Rounding Precision"); + end; + + local procedure GetAssignableQty( + SalesLine: Record "Sales Line"; + ItemChargeAssgntSales: Record "Item Charge Assignment (Sales)"; + var AssignableQty: Decimal + ) + var + AssignItemChargeSales: Codeunit "Item Charge Assgnt. (Sales)"; + begin + if SalesLine.IsCreditDocType() then + AssignItemChargeSales.CreateDocChargeAssgn(ItemChargeAssgntSales, SalesLine."Return Receipt No.") + else + AssignItemChargeSales.CreateDocChargeAssgn(ItemChargeAssgntSales, SalesLine."Shipment No."); + + SalesLine.CalcFields("Qty. to Assign", "Item Charge Qty. to Handle", "Qty. Assigned"); + AssignableQty := SalesLine."Qty. to Invoice" + SalesLine."Quantity Invoiced" - SalesLine."Qty. Assigned"; end; /// diff --git a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al index 53c7b012c8..17e7fa6610 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al +++ b/Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al @@ -62,6 +62,16 @@ page 30113 "Shpfy Order" ApplicationArea = All; ToolTip = 'Specifies how items on the Shopify Order are shipped to the customer.'; } + field(ShippingAgentCode; Rec."Shipping Agent Code") + { + ApplicationArea = All; + ToolTip = 'Specifies which shipping agent is used to transport the items on the Shopify Order to the customer.'; + } + field(ShippingAgentServiceCode; Rec."Shipping Agent Service Code") + { + ApplicationArea = All; + ToolTip = 'Specifies the code that represents the default shipping agent service you are using for this Shopify Order.'; + } field("Payment Method"; Rec."Payment Method Code") { ApplicationArea = All; diff --git a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al index b71f4c1934..e31860f410 100644 --- a/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al +++ b/Apps/W1/Shopify/app/src/Order handling/Tables/ShpfyOrderHeader.Table.al @@ -735,6 +735,22 @@ table 30118 "Shpfy Order Header" Caption = 'Has Order State Error'; DataClassification = SystemMetadata; } + field(1021; "Shipping Agent Code"; Code[10]) + { + Caption = 'Shipping Agent Code'; + TableRelation = "Shipping Agent"; + + trigger OnValidate() + begin + if "Shipping Agent Code" <> xRec."Shipping Agent Code" then + Clear("Shipping Agent Service Code"); + end; + } + field(1022; "Shipping Agent Service Code"; Code[10]) + { + Caption = 'Shipping Agent Service Code'; + TableRelation = "Shipping Agent Services".Code where("Shipping Agent Code" = field("Shipping Agent Code")); + } } keys { diff --git a/Apps/W1/Shopify/app/src/Shipping/Pages/ShpfyShipmentMethodsMapping.Page.al b/Apps/W1/Shopify/app/src/Shipping/Pages/ShpfyShipmentMethodsMapping.Page.al index 70b28df117..cf26927279 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Pages/ShpfyShipmentMethodsMapping.Page.al +++ b/Apps/W1/Shopify/app/src/Shipping/Pages/ShpfyShipmentMethodsMapping.Page.al @@ -26,6 +26,27 @@ page 30129 "Shpfy Shipment Methods Mapping" ApplicationArea = All; ToolTip = 'Specifies the shipping method in D365BC.'; } + field("Shipping Charges Type"; Rec."Shipping Charges Type") + { + ApplicationArea = All; + ToolTip = 'Specifies the value of the Shipping Charges Type field.'; + } + field("Shipping Charges No."; Rec."Shipping Charges No.") + { + ApplicationArea = All; + ShowMandatory = Rec."Shipping Charges Type" <> Rec."Shipping Charges Type"::" "; + ToolTip = 'Specifies the value of the Shipping Charges No. field.'; + } + field("Shipping Agent Code"; Rec."Shipping Agent Code") + { + ApplicationArea = All; + ToolTip = 'Specifies the code for the shipping agent who is transporting the items.'; + } + field("Shipping Agent Service Code"; Rec."Shipping Agent Service Code") + { + ApplicationArea = All; + ToolTip = 'Specifies the code for the service, such as a one-day delivery, that is offered by the shipping agent.'; + } } } } diff --git a/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyShipmentMethodMapping.Table.al b/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyShipmentMethodMapping.Table.al index ea91386f18..89819deeeb 100644 --- a/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyShipmentMethodMapping.Table.al +++ b/Apps/W1/Shopify/app/src/Shipping/Tables/ShpfyShipmentMethodMapping.Table.al @@ -1,6 +1,9 @@ namespace Microsoft.Integration.Shopify; using Microsoft.Foundation.Shipping; +using Microsoft.Sales.Document; +using Microsoft.Finance.GeneralLedger.Account; +using Microsoft.Inventory.Item; /// /// Table Shpfy Shipment Method Mapping (ID 30131). @@ -31,6 +34,55 @@ table 30131 "Shpfy Shipment Method Mapping" DataClassification = CustomerContent; TableRelation = "Shipment Method"; } + field(4; "Shipping Charges Type"; Enum "Sales Line Type") + { + Caption = 'Shipping Charges Type'; + DataClassification = CustomerContent; + ValuesAllowed = " ", "G/L Account", Item, "Charge (Item)"; + + trigger OnValidate() + begin + if "Shipping Charges Type" <> xRec."Shipping Charges Type" then + Clear("Shipping Charges No."); + end; + } + field(5; "Shipping Charges No."; Code[20]) + { + Caption = 'Shipping Charges No.'; + TableRelation = if ("Shipping Charges Type" = const("G/L Account")) "G/L Account" + else + if ("Shipping Charges Type" = const(Item)) Item + else + if ("Shipping Charges Type" = const("Charge (Item)")) "Item Charge"; + + trigger OnValidate() + var + GLAccount: Record "G/L Account"; + ShpfyShop: Record "Shpfy Shop"; + begin + if "Shipping Charges Type" = "Shipping Charges Type"::"G/L Account" then + if GLAccount.Get("Shipping Charges No.") then + ShpfyShop.CheckGLAccount(GLAccount); + end; + } + field(6; "Shipping Agent Code"; Code[10]) + { + AccessByPermission = TableData "Shipping Agent Services" = R; + Caption = 'Shipping Agent Code'; + TableRelation = "Shipping Agent"; + + trigger OnValidate() + begin + if "Shipping Agent Code" <> xRec."Shipping Agent Code" then + Clear("Shipping Agent Service Code"); + end; + } + field(7; "Shipping Agent Service Code"; Code[10]) + { + AccessByPermission = TableData "Shipping Agent Services" = R; + Caption = 'Shipping Agent Service Code'; + TableRelation = "Shipping Agent Services".Code where("Shipping Agent Code" = field("Shipping Agent Code")); + } } keys