Skip to content

Commit

Permalink
[Shopify] Connector - Different shipping charges types (#26708)
Browse files Browse the repository at this point in the history
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 <[email protected]>
Co-authored-by: Tine Staric <[email protected]>
  • Loading branch information
3 people authored Jul 29, 2024
1 parent 096df31 commit eb8dd44
Show file tree
Hide file tree
Showing 7 changed files with 253 additions and 4 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,25 @@ codeunit 30162 "Shpfy Order Events"
begin
end;

[IntegrationEvent(false, false)]
/// <summary>
/// Description for OnBeforeMapShipmentAgent.
/// </summary>
/// <param name="ShopifyOrderHeader">Parameter of type Record "Shopify Order Header".</param>
/// <param name="Handled">Parameter of type Boolean.</param>
internal procedure OnBeforeMapShipmentAgent(var ShopifyOrderHeader: Record "Shpfy Order Header"; var Handled: Boolean)
begin
end;

[IntegrationEvent(false, false)]
/// <summary>
/// Description for OnAfterMapShipmentAgent.
/// </summary>
/// <param name="ShopifyOrderHeader">Parameter of type Record "Shopify Order Header".</param>
internal procedure OnAfterMapShipmentAgent(var ShopifyOrderHeader: Record "Shpfy Order Header")
begin
end;

[IntegrationEvent(false, false)]
/// <summary>
/// Description for OnBeforeMapPaymentMethod.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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." <> ''));
Expand Down Expand Up @@ -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." <> ''));
Expand Down Expand Up @@ -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";
Expand Down
Original file line number Diff line number Diff line change
@@ -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;
Expand Down Expand Up @@ -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");

Expand Down Expand Up @@ -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);
Expand Down Expand Up @@ -230,31 +237,133 @@ 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");
SalesLine.Validate("Document No.", SalesHeader."No.");
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;

/// <summary>
Expand Down
10 changes: 10 additions & 0 deletions Apps/W1/Shopify/app/src/Order handling/Pages/ShpfyOrder.Page.al
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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.';
}
}
}
}
Expand Down
Original file line number Diff line number Diff line change
@@ -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;

/// <summary>
/// Table Shpfy Shipment Method Mapping (ID 30131).
Expand Down Expand Up @@ -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
Expand Down

0 comments on commit eb8dd44

Please sign in to comment.