Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,9 @@ codeunit 30161 "Shpfy Import Order"
OrderEvents: Codeunit "Shpfy Order Events";
OrderFulfillments: Codeunit "Shpfy Order Fulfillments";
ProcessedConflictErr: Label 'The order has already been processed in Business Central, but an edition was received from Shopify. Changes were not propagated to the processed order in Business Central. Update the processed documents to match the received data from Shopify.';
DuplicateISOCodeTelemetryLbl: Label 'Multiple currencies found with ISO Code %1. Count: %2.', Locked = true;
CurrencyNotFoundTelemetryLbl: Label 'No currency found with ISO Code %1.', Locked = true;
CategoryTok: Label 'Shopify Integration', Locked = true;

local procedure ImportOrderAndCreateOrUpdate(ShopCode: Code[20]; OrderId: BigInteger)
var
Expand Down Expand Up @@ -651,15 +654,31 @@ codeunit 30161 "Shpfy Import Order"
GeneralLedgerSetup: Record "General Ledger Setup";
CurrencyCode: Code[10];
begin
if ShopifyCurrencyCode = '' then

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟡\ Medium\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Currency filter excludes empty ISO code incorrectly

The filter Currency.SetFilter("ISO Code", '<>%1&%2', '', CopyStr(ShopifyCurrencyCode, 1, 3)) uses & (AND) between the two conditions, which will never match any record because no ISO Code can simultaneously be both not-empty AND match the given currency code. The intended logic is likely OR, or a separate SetRange call.

Recommendation:

  • Use two separate filter calls or the correct operator. To find currencies matching the ISO code that are not blank: Currency.SetRange("ISO Code", CopyStr(ShopifyCurrencyCode, 1, 3));
Suggested change
if ShopifyCurrencyCode = '' then
Currency.SetRange("ISO Code", CopyStr(ShopifyCurrencyCode, 1, 3));

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

exit('');

GeneralLedgerSetup.Get();
if CopyStr(ShopifyCurrencyCode, 1, MaxStrLen(GeneralLedgerSetup."LCY Code")) = GeneralLedgerSetup."LCY Code" then
exit('');

Currency.SetLoadFields(Code);
Currency.SetRange("ISO Code", CopyStr(ShopifyCurrencyCode, 1, 3));
if Currency.FindFirst() then
if Currency.Count() = 1 then begin

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

$\textbf{🟠\ High\ Severity\ —\ Performance} \quad \color{gray}{\texttt{\small Iteration\ 1}}$

Currency.Count() called three times in one path

Currency.Count() is invoked on lines 666, 670, and again inside StrSubstNo on line 671 — each is a separate database round-trip. This function is called for every order imported from Shopify, so the redundant queries compound at scale.

Recommendation:

  • Cache the result of Currency.Count() in a local CurrencyCount: Integer variable before the if-else block, then reference the variable in all three places.
Suggested change
if Currency.Count() = 1 then begin
CurrencyCount := Currency.Count();
if CurrencyCount = 1 then begin
Currency.FindFirst();
CurrencyCode := Currency.Code;
end else begin
if CurrencyCount > 1 then begin
Session.LogMessage('0000S1A', StrSubstNo(DuplicateISOCodeTelemetryLbl, ShopifyCurrencyCode, CurrencyCount), Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', CategoryTok);
Currency.FindFirst();
CurrencyCode := Currency.Code;
end else
if Currency.Get(CopyStr(ShopifyCurrencyCode, 1, MaxStrLen(Currency.Code))) then
CurrencyCode := Currency.Code
else
Session.LogMessage('0000S1B', StrSubstNo(CurrencyNotFoundTelemetryLbl, ShopifyCurrencyCode), Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', CategoryTok);
end;

👍 useful · ❤️ especially valuable · 👎 wrong - reply with why

Currency.FindFirst();
CurrencyCode := Currency.Code;
GeneralLedgerSetup.Get();
if CurrencyCode = GeneralLedgerSetup."LCY Code" then
exit('')
else
exit(CurrencyCode);
end else begin
if Currency.Count() > 1 then begin
Session.LogMessage('0000S1A', StrSubstNo(DuplicateISOCodeTelemetryLbl, ShopifyCurrencyCode, Currency.Count()), Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', CategoryTok);
Currency.FindFirst();
CurrencyCode := Currency.Code;
end else
if Currency.Get(CopyStr(ShopifyCurrencyCode, 1, MaxStrLen(Currency.Code))) then
CurrencyCode := Currency.Code
else
Session.LogMessage('0000S1B', StrSubstNo(CurrencyNotFoundTelemetryLbl, ShopifyCurrencyCode), Verbosity::Warning, DataClassification::SystemMetadata, TelemetryScope::ExtensionPublisher, 'Category', CategoryTok);
end;

exit(CurrencyCode);
end;

local procedure ImportCustomAttributtes(ShopifyOrderId: BigInteger; JCustomAttributtes: JsonArray)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -93,6 +93,7 @@ codeunit 30194 "Shpfy Transactions"
JsonHelper.GetValueIntoField(JOrderTransaction, 'errorCode', RecordRef, OrderTransaction.FieldNo("Error Code"));
JsonHelper.GetValueIntoField(JOrderTransaction, 'paymentId', RecordRef, OrderTransaction.FieldNo("Payment Id"));
JsonHelper.GetValueIntoField(JOrderTransaction, 'amountSet.shopMoney.amount', RecordRef, OrderTransaction.FieldNo(Amount));
JsonHelper.GetValueIntoField(JOrderTransaction, 'amountSet.shopMoney.currencyCode', RecordRef, OrderTransaction.FieldNo(Currency));
JsonHelper.GetValueIntoField(JOrderTransaction, 'amountSet.presentmentMoney.amount', RecordRef, OrderTransaction.FieldNo("Presentment Amount"));
JsonHelper.GetValueIntoField(JOrderTransaction, 'amountSet.presentmentMoney.currencyCode', RecordRef, OrderTransaction.FieldNo("Presentment Currency"));
JsonHelper.GetValueIntoField(JOrderTransaction, 'amountRoundingSet.shopMoney.amount', RecordRef, OrderTransaction.FieldNo("Rounding Amount"));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,9 @@

namespace Microsoft.Integration.Shopify.Test;

using Microsoft.Finance.Currency;
using Microsoft.Finance.GeneralLedger.Account;
using Microsoft.Finance.GeneralLedger.Setup;
using Microsoft.Finance.VAT.Setup;
using Microsoft.Foundation.Enums;
using Microsoft.Foundation.Shipping;
Expand Down Expand Up @@ -353,6 +355,47 @@ codeunit 139546 "Shpfy Shipping Charges Test"
ShpfyShipmentMethodMapping."Shipping Charges No."
);
end;

[Test]
[HandlerFunctions('ShippingChargesHttpHandler')]
procedure UnitTestTransactionCurrencyIsSetFromOrderImport()
var
OrderHeader: Record "Shpfy Order Header";
OrderTransaction: Record "Shpfy Order Transaction";
GeneralLedgerSetup: Record "General Ledger Setup";
ImportOrder: Codeunit "Shpfy Import Order";
begin
// [SCENARIO] When importing a Shopify order, the transaction currency is correctly populated from the JSON response.
Initialize();

// [GIVEN] Shopify Shop
Shop := CommunicationMgt.GetShopRecord();

// [GIVEN] Register Expected Outbound API Requests.
OutboundHttpRequests.Clear();
OutboundHttpRequests.Enqueue('Transactions');

// [GIVEN] Shopify order is imported
ImportOrder.SetShop(Shop.Code);
ImportShopifyOrder(Shop, OrderHeader, ImportOrder, false);

// [THEN] Transaction is created with the correct currency from shopMoney.currencyCode (DKK from resource file)
OrderTransaction.SetRange("Shopify Order Id", OrderHeader."Shopify Order Id");
OrderTransaction.SetRange(Status, "Shpfy Transaction Status"::Success);
LibraryAssert.IsTrue(OrderTransaction.FindFirst(), 'Transaction should be created');

GeneralLedgerSetup.Get();
if 'DKK' = GeneralLedgerSetup."LCY Code" then
LibraryAssert.AreEqual('', OrderTransaction.Currency, 'Currency should be empty when DKK is LCY')
else
LibraryAssert.AreEqual('DKK', OrderTransaction.Currency, 'Currency should be DKK from shopMoney.currencyCode');

// [THEN] Presentment currency is also set correctly
if 'DKK' = GeneralLedgerSetup."LCY Code" then
LibraryAssert.AreEqual('', OrderTransaction."Presentment Currency", 'Presentment Currency should be empty when DKK is LCY')
else
LibraryAssert.AreEqual('DKK', OrderTransaction."Presentment Currency", 'Presentment Currency should be DKK from presentmentMoney.currencyCode');
end;
#endregion

[HttpClientHandler]
Expand Down Expand Up @@ -386,6 +429,7 @@ codeunit 139546 "Shpfy Shipping Charges Test"
#region Local Procedures
local procedure Initialize()
var
Currency: Record Currency;
ShippingTime: DateFormula;
AccessToken: SecretText;
begin
Expand All @@ -403,6 +447,17 @@ codeunit 139546 "Shpfy Shipping Charges Test"
LibraryInventory.CreateShippingAgent(ShippingAgent);
LibraryInventory.CreateShippingAgentService(ShippingAgentServices, ShippingAgent.Code, ShippingTime);

if not Currency.Get('DKK') then begin
Currency.Init();
Currency.Code := 'DKK';
Currency."ISO Code" := 'DKK';
Currency.Insert(true);
end else
if Currency."ISO Code" <> 'DKK' then begin
Currency."ISO Code" := 'DKK';
Currency.Modify();
end;

Commit();

IsInitialized := true;
Expand Down
Loading
Loading