Skip to content

Commit 33ead2e

Browse files
authored
[Shopify][BC Idea]: Enhancing Shopify Connector for Accurate Price Synchronization with Business Central based on Customer (#26981)
#### Summary Added Customer No to the table 30152 "Shpfy Catalog" page 30159 "Shpfy Catalogs" Added logic to use customer specific pricing from catalog codeunit 30182 "Shpfy Product Price Calc." Fixes #26980 Fixes [AB#544010](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/544010)
1 parent 1690178 commit 33ead2e

File tree

5 files changed

+330
-21
lines changed

5 files changed

+330
-21
lines changed

Apps/W1/Shopify/app/src/Catalogs/Pages/ShpfyCatalogs.Page.al

+6
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,12 @@ page 30159 "Shpfy Catalogs"
2525
ToolTip = 'Specifies the unique identifier for the catalog in Shopify.';
2626
Editable = false;
2727
}
28+
field("Customer No."; Rec."Customer No.")
29+
{
30+
ApplicationArea = All;
31+
Visible = false;
32+
ToolTip = 'Specifies the customer''s no. When Customer No. is Selected: Parameters like ''Customer Discount Group'', ''Customer Price Group'', and ''Allow Line Discount'' on the customer card take precedence over catalog settings';
33+
}
2834
field(Name; Rec.Name)
2935
{
3036
ApplicationArea = All;

Apps/W1/Shopify/app/src/Catalogs/Tables/ShpfyCatalog.Table.al

+6
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,12 @@ table 30152 "Shpfy Catalog"
111111
Caption = 'Sync Prices';
112112
DataClassification = CustomerContent;
113113
}
114+
field(17; "Customer No."; Code[20])
115+
{
116+
Caption = 'Customer No.';
117+
DataClassification = CustomerContent;
118+
TableRelation = "Customer";
119+
}
114120
}
115121
keys
116122
{

Apps/W1/Shopify/app/src/Products/Codeunits/ShpfyProductPriceCalc.Codeunit.al

+20-5
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,7 @@ codeunit 30182 "Shpfy Product Price Calc."
3131
TaxLiable: Boolean;
3232
VATCountryRegionCode: Code[10];
3333
CustomerPriceGroup: Code[10];
34+
CustomerNo: Code[20];
3435
CustomerDiscGroup: Code[20];
3536
CustomerPostingGroup: Code[20];
3637
PricesIncludingVAT: Boolean;
@@ -91,22 +92,35 @@ codeunit 30182 "Shpfy Product Price Calc."
9192
/// Create Temp Sales Header.
9293
/// </summary>
9394
local procedure CreateTempSalesHeader()
95+
var
96+
Customer: Record Customer;
9497
begin
9598
Clear(TempSalesHeader);
9699
TempSalesHeader."Document Type" := TempSalesHeader."Document Type"::Quote;
97100
TempSalesHeader."No." := Shop.Code;
98-
TempSalesHeader."Sell-to Customer No." := Shop.Code;
99-
TempSalesHeader."Bill-to Customer No." := Shop.Code;
101+
if CustomerNo <> '' then begin
102+
Customer.GET(CustomerNo);
103+
TempSalesHeader."Sell-to Customer No." := CustomerNo;
104+
TempSalesHeader."Bill-to Customer No." := CustomerNo;
105+
TempSalesHeader."Customer Price Group" := Customer."Customer Price Group";
106+
TempSalesHeader."Customer Disc. Group" := Customer."Customer Disc. Group";
107+
TempSalesHeader."Allow Line Disc." := Customer."Allow Line Disc.";
108+
end
109+
else begin
110+
TempSalesHeader."Sell-to Customer No." := Shop.Code;
111+
TempSalesHeader."Bill-to Customer No." := Shop.Code;
112+
TempSalesHeader."Customer Price Group" := CustomerPriceGroup;
113+
TempSalesHeader."Customer Disc. Group" := CustomerDiscGroup;
114+
TempSalesHeader."Allow Line Disc." := AllowLineDisc;
115+
end;
116+
100117
TempSalesHeader."Gen. Bus. Posting Group" := GenBusPostingGroup;
101118
TempSalesHeader."VAT Bus. Posting Group" := VATBusPostingGroup;
102119
TempSalesHeader."Tax Area Code" := TaxAreaCode;
103120
TempSalesHeader."Tax Liable" := TaxLiable;
104121
TempSalesHeader."VAT Country/Region Code" := VATCountryRegionCode;
105-
TempSalesHeader."Customer Price Group" := CustomerPriceGroup;
106-
TempSalesHeader."Customer Disc. Group" := CustomerDiscGroup;
107122
TempSalesHeader."Customer Posting Group" := CustomerPostingGroup;
108123
TempSalesHeader."Prices Including VAT" := PricesIncludingVAT;
109-
TempSalesHeader."Allow Line Disc." := AllowLineDisc;
110124
TempSalesHeader.Validate("Document Date", WorkDate());
111125
TempSalesHeader.Validate("Order Date", WorkDate());
112126
TempSalesHeader.Validate("Currency Code", Shop."Currency Code");
@@ -206,6 +220,7 @@ codeunit 30182 "Shpfy Product Price Calc."
206220
CustomerPostingGroup := ShopifyCatalog."Customer Posting Group";
207221
PricesIncludingVAT := ShopifyCatalog."Prices Including VAT";
208222
AllowLineDisc := ShopifyCatalog."Allow Line Disc.";
223+
CustomerNo := ShopifyCatalog."Customer No.";
209224
end;
210225
end;
211226
end;

Apps/W1/Shopify/test/Catalogs/ShpfyCatalogPricesTest.Codeunit.al

+238
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,7 @@ codeunit 139646 "Shpfy Catalog Prices Test"
5959

6060
// [GIVEN] Update the Catalog."Customer Discount Group" field and set the catalog to the calculation codeunit.
6161
Catalog."Customer Discount Group" := CustomerDiscountGroup.Code;
62+
Catalog."Allow Line Disc." := true;
6263
Catalog.Modify();
6364
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
6465

@@ -72,4 +73,241 @@ codeunit 139646 "Shpfy Catalog Prices Test"
7273
// [THEN] InitPrice - InitDiscountPerc = Price
7374
LibraryAssert.AreNearlyEqual(InitPrice * (1 - InitDiscountPerc / 100), Price, 0.01, 'Discount Price');
7475
end;
76+
77+
[Test]
78+
procedure UnitTestCalcCatalogPriceAllCustomers()
79+
var
80+
Shop: Record "Shpfy Shop";
81+
LibrarySales: Codeunit "Library - Sales";
82+
Catalog: Record "Shpfy Catalog";
83+
ShopifyCompany: Record "Shpfy Company";
84+
Item: Record Item;
85+
CustomerDiscountGroup: Record "Customer Discount Group";
86+
Customer: Record Customer;
87+
InitializeTest: Codeunit "Shpfy Initialize Test";
88+
ProductInitTest: Codeunit "Shpfy Product Init Test";
89+
CatalogInitialize: Codeunit "Shpfy Catalog Initialize";
90+
CompanyInitialize: Codeunit "Shpfy Company Initialize";
91+
ProductPriceCalculation: Codeunit "Shpfy Product Price Calc.";
92+
InitUnitCost: Decimal;
93+
InitPrice: Decimal;
94+
InitDiscountPerc: Decimal;
95+
UnitCost: Decimal;
96+
Price: Decimal;
97+
ComparePrice: Decimal;
98+
begin
99+
// [GIVEN] Initializing test environment and creating necessary test records.
100+
Shop := InitializeTest.CreateShop();
101+
CompanyInitialize.CreateShopifyCompany(ShopifyCompany);
102+
Catalog := CatalogInitialize.CreateCatalog(ShopifyCompany);
103+
CatalogInitialize.CopyParametersFromShop(Catalog, Shop);
104+
InitUnitCost := Any.DecimalInRange(10, 100, 1);
105+
InitPrice := Any.DecimalInRange(2 * InitUnitCost, 4 * InitUnitCost, 1);
106+
InitDiscountPerc := Any.DecimalInRange(5, 20, 1);
107+
Item := ProductInitTest.CreateItem(Shop."Item Templ. Code", InitUnitCost, InitPrice);
108+
109+
// Creating a customer entry, though it is generic as discounts apply to all customers.
110+
LibrarySales.CreateCustomer(Customer);
111+
112+
// [WHEN] Calculating initial prices without any discounts applied.
113+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
114+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
115+
116+
// [THEN] Confirm initial price calculations match expectations.
117+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Initial unit cost should match expected.');
118+
LibraryAssert.AreEqual(InitPrice, Price, 'Initial price should match expected before discount application.');
119+
120+
// [GIVEN] Updating the catalog to apply a universal discount to all customers.
121+
#if CLEAN23
122+
ProductInitTest.CreateAllCustomerPriceList(Shop.Code, Item."No.", InitPrice, InitDiscountPerc);
123+
Catalog."Customer No." := Customer."No.";
124+
Catalog.Modify();
125+
126+
// [WHEN] Recalculating prices after applying the discount.
127+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
128+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
129+
130+
// [THEN] Validate the results reflect the universal discount.
131+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Unit cost should remain consistent after discount application.');
132+
LibraryAssert.AreEqual(InitPrice, ComparePrice, 'Compare price should reflect the original price prior to any discounts.');
133+
LibraryAssert.AreNearlyEqual(InitPrice * (1 - InitDiscountPerc / 100), Price, 0.01, 'The final price should accurately reflect the applied discount for all customers.');
134+
#endif
135+
end;
136+
137+
[Test]
138+
procedure UnitTestCalcCustomerCatalogPrice()
139+
var
140+
Shop: Record "Shpfy Shop";
141+
LibrarySales: Codeunit "Library - Sales";
142+
Catalog: Record "Shpfy Catalog";
143+
ShopifyCompany: Record "Shpfy Company";
144+
Item: Record Item;
145+
CustomerDiscountGroup: Record "Customer Discount Group";
146+
Customer: Record Customer;
147+
InitializeTest: Codeunit "Shpfy Initialize Test";
148+
ProductInitTest: Codeunit "Shpfy Product Init Test";
149+
CatalogInitialize: Codeunit "Shpfy Catalog Initialize";
150+
CompanyInitialize: Codeunit "Shpfy Company Initialize";
151+
ProductPriceCalculation: Codeunit "Shpfy Product Price Calc.";
152+
InitUnitCost: Decimal;
153+
InitPrice: Decimal;
154+
InitDiscountPerc: Decimal;
155+
UnitCost: Decimal;
156+
Price: Decimal;
157+
ComparePrice: Decimal;
158+
CustDiscPerc: Decimal;
159+
begin
160+
// [GIVEN] Setting up the test environment: Shop, Catalog, Item, and Customer with specific pricing and discount.
161+
Shop := InitializeTest.CreateShop();
162+
CompanyInitialize.CreateShopifyCompany(ShopifyCompany);
163+
Catalog := CatalogInitialize.CreateCatalog(ShopifyCompany);
164+
CatalogInitialize.CopyParametersFromShop(Catalog, Shop);
165+
InitUnitCost := Any.DecimalInRange(10, 100, 1);
166+
InitPrice := Any.DecimalInRange(2 * InitUnitCost, 4 * InitUnitCost, 1);
167+
CustDiscPerc := Any.DecimalInRange(5, 20, 1);
168+
Item := ProductInitTest.CreateItem(Shop."Item Templ. Code", InitUnitCost, InitPrice);
169+
170+
// [WHEN] Calculating prices without and then with customer-specific discounts.
171+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
172+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
173+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Verify initial unit cost matches setup.');
174+
LibraryAssert.AreEqual(InitPrice, Price, 'Verify initial price matches setup before discount.');
175+
#if CLEAN23
176+
// Creating a customer entry, though it is generic as discounts apply to all customers.
177+
LibrarySales.CreateCustomer(Customer);
178+
// [GIVEN] Applying customer-specific discounts.
179+
ProductInitTest.CreateCustomerPriceList(Shop.Code, Item."No.", InitPrice, CustDiscPerc, Customer);
180+
Catalog."Customer No." := Customer."No.";
181+
Catalog.Modify();
182+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
183+
184+
// [WHEN] Recalculating prices with customer-specific discounts.
185+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
186+
187+
// [THEN] Confirming pricing accuracy with applied discounts.
188+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Unit cost should remain unchanged after applying discounts.');
189+
LibraryAssert.AreEqual(InitPrice, ComparePrice, 'Compare price should reflect the original price pre-discount.');
190+
LibraryAssert.AreNearlyEqual(InitPrice * (1 - CustDiscPerc / 100), Price, 0.01, 'Discounted price should be accurately calculated.');
191+
#endif
192+
end;
193+
194+
[Test]
195+
procedure UnitTestCalcCustomerCatalogPriceAllCustomers()
196+
var
197+
Shop: Record "Shpfy Shop";
198+
LibrarySales: Codeunit "Library - Sales";
199+
Catalog: Record "Shpfy Catalog";
200+
ShopifyCompany: Record "Shpfy Company";
201+
Item: Record Item;
202+
CustomerDiscountGroup: Record "Customer Discount Group";
203+
Customer: Record Customer;
204+
InitializeTest: Codeunit "Shpfy Initialize Test";
205+
ProductInitTest: Codeunit "Shpfy Product Init Test";
206+
CatalogInitialize: Codeunit "Shpfy Catalog Initialize";
207+
CompanyInitialize: Codeunit "Shpfy Company Initialize";
208+
ProductPriceCalculation: Codeunit "Shpfy Product Price Calc.";
209+
InitUnitCost: Decimal;
210+
InitPrice: Decimal;
211+
InitPerc: Decimal;
212+
CustDiscPerc: Decimal;
213+
UnitCost: Decimal;
214+
Price: Decimal;
215+
ComparePrice: Decimal;
216+
begin
217+
// [GIVEN] Setting up shop, catalog, item, and customer-specific pricing.
218+
Shop := InitializeTest.CreateShop();
219+
CompanyInitialize.CreateShopifyCompany(ShopifyCompany);
220+
Catalog := CatalogInitialize.CreateCatalog(ShopifyCompany);
221+
CatalogInitialize.CopyParametersFromShop(Catalog, Shop);
222+
InitUnitCost := Any.DecimalInRange(10, 100, 1);
223+
InitPrice := Any.DecimalInRange(2 * InitUnitCost, 4 * InitUnitCost, 1);
224+
CustDiscPerc := Any.DecimalInRange(5, 20, 1);
225+
Item := ProductInitTest.CreateItem(Shop."Item Templ. Code", InitUnitCost, InitPrice);
226+
227+
// [WHEN] Calculating prices without discounts applied.
228+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
229+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
230+
231+
// [THEN] Verifying initial prices match expectations.
232+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Initial unit cost should match.');
233+
LibraryAssert.AreEqual(InitPrice, Price, 'Initial price should match before discount.');
234+
235+
#if CLEAN23
236+
// Creating a customer entry, though it is generic as discounts apply to all customers.
237+
LibrarySales.CreateCustomer(Customer);
238+
// [GIVEN] Applying a universal discount for all customers.
239+
ProductInitTest.CreateCustomerPriceList(Shop.Code, Item."No.", InitPrice, CustDiscPerc, Customer);
240+
ProductInitTest.CreateAllCustomerPriceList(Shop.Code, Item."No.", InitPrice, InitPerc);
241+
Catalog."Customer No." := Customer."No.";
242+
Catalog.Modify();
243+
244+
// [WHEN] Recalculating prices with discounts.
245+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
246+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
247+
248+
// [THEN] Confirming discounts are accurately reflected in the final prices.
249+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Unit cost should remain consistent.');
250+
LibraryAssert.AreEqual(InitPrice, ComparePrice, 'Compare price should reflect initial pricing.');
251+
LibraryAssert.AreNearlyEqual(InitPrice * (1 - CustDiscPerc / 100), Price, 0.01, 'Discounted price should be accurately calculated.');
252+
#endif
253+
end;
254+
255+
[Test]
256+
procedure UnitTestCalcCustomerDiscountCatalogPrice()
257+
var
258+
Shop: Record "Shpfy Shop";
259+
Catalog: Record "Shpfy Catalog";
260+
LibrarySales: Codeunit "Library - Sales";
261+
ShopifyCompany: Record "Shpfy Company";
262+
Item: Record Item;
263+
CustomerDiscountGroup: Record "Customer Discount Group";
264+
InitializeTest: Codeunit "Shpfy Initialize Test";
265+
ProductInitTest: Codeunit "Shpfy Product Init Test";
266+
CatalogInitialize: Codeunit "Shpfy Catalog Initialize";
267+
CompanyInitialize: Codeunit "Shpfy Company Initialize";
268+
ProductPriceCalculation: Codeunit "Shpfy Product Price Calc.";
269+
InitUnitCost: Decimal;
270+
InitPrice: Decimal;
271+
InitDiscountPerc: Decimal;
272+
UnitCost: Decimal;
273+
Price: Decimal;
274+
ComparePrice: Decimal;
275+
Customer: Record Customer;
276+
begin
277+
// [GIVEN] Creating shop, catalog, item, and setting customer discount details.
278+
Shop := InitializeTest.CreateShop();
279+
CompanyInitialize.CreateShopifyCompany(ShopifyCompany);
280+
Catalog := CatalogInitialize.CreateCatalog(ShopifyCompany);
281+
CatalogInitialize.CopyParametersFromShop(Catalog, Shop);
282+
InitUnitCost := Any.DecimalInRange(10, 100, 1);
283+
InitPrice := Any.DecimalInRange(2 * InitUnitCost, 4 * InitUnitCost, 1);
284+
InitDiscountPerc := Any.DecimalInRange(5, 20, 1);
285+
Item := ProductInitTest.CreateItem(Shop."Item Templ. Code", InitUnitCost, InitPrice);
286+
287+
// [WHEN] Calculating initial prices without any discounts applied.
288+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
289+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
290+
291+
// [THEN] Verifying initial price settings.
292+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Initial unit cost should match setup.');
293+
LibraryAssert.AreEqual(InitPrice, Price, 'Initial price should match setup without discounts.');
294+
#if CLEAN23
295+
LibrarySales.CreateCustomer(Customer);
296+
CustomerDiscountGroup := ProductInitTest.CreatePriceList(Shop.Code, Item."No.", InitPrice, InitDiscountPerc);
297+
// [GIVEN] Updating catalog with customer-specific discount group details.
298+
Catalog."Customer No." := Customer."No.";
299+
Customer."Customer Disc. Group" := CustomerDiscountGroup.Code;
300+
Customer.Modify();
301+
Catalog.Modify();
302+
303+
// [WHEN] Recalculating prices post-update.
304+
ProductPriceCalculation.SetShopAndCatalog(Shop, Catalog);
305+
ProductPriceCalculation.CalcPrice(Item, '', '', UnitCost, Price, ComparePrice);
306+
307+
// [THEN] Confirming accurate reflection of discount updates in final prices.
308+
LibraryAssert.AreEqual(InitUnitCost, UnitCost, 'Unit cost should remain unchanged post-update.');
309+
LibraryAssert.AreEqual(InitPrice, ComparePrice, 'Compare Price should match initial settings.');
310+
LibraryAssert.AreNearlyEqual(InitPrice * (1 - InitDiscountPerc / 100), Price, 0.01, 'Accurate calculation of discounted price should be verified.');
311+
#endif
312+
end;
75313
}

0 commit comments

Comments
 (0)