[Bug]: "Shpfy Product Price Calc." (SingleInstance) leaks catalog parameters into shop base price calculation
Nobody has claimed this yet.
- Dominant language
- AL
- Stars
- 683
- Forks
- 459
- Avg merge
- 3d 26m
- Merged PRs (30d)
- 633
Description
Describe the issue
Codeunit 30182 "Shpfy Product Price Calc." is SingleInstance and caches a temporary sales header used to calculate prices. There are two related state-leak defects that cause base product prices to be calculated with catalog parameters (currency, customer, VAT/posting groups) when a catalog price sync and a product/price sync run in the same session:
Defect 1: SetShop does not re-initialize after SetShopAndCatalog
SetShop only rebuilds the cached temp sales header when the shop code changed, the shop record was modified, or (on current main) the work date changed:
internal procedure SetShop(ShopifyShop: Record "Shpfy Shop")
begin
if (Shop.Code <> ShopifyShop.Code) or (Shop.SystemModifiedAt < ShopifyShop.SystemModifiedAt) or (TempSalesHeader."Document Date" <> WorkDate()) then begin
...
CreateTempSalesHeader();
end;
end;
If SetShopAndCatalog was called earlier in the same session (catalog price sync, codeunit 30219 "Shpfy Sync Catalog Prices"), the temp sales header was built from the catalog's parameters — including "Currency Code" from the catalog. A subsequent SetShop call for the same shop (product export / price sync, ShpfyProductExport, or product creation, ShpfyCreateProduct) finds the shop unchanged and keeps the catalog-flavored header. All base prices are then calculated in the catalog currency (and with the catalog's customer/price group/VAT setup) but sent to Shopify as the shop's base price, where Shopify interprets the number in the shop currency.
Example: LCY = CZK, shop currency blank (= CZK), EUR market catalog. After a catalog price sync, a product price sync in the same session calculates e.g. 25 (EUR) and pushes it as 25 CZK. The corruption is silent and reproduces on every run that follows the same sequence.
Defect 2: CustomerNo is never cleared when switching back to shop parameters
SetParameters sets CustomerNo only in the Database::"Shpfy Catalog" branch; the Database::"Shpfy Shop" branch does not reset it. Once any catalog with a non-empty "Customer No." (B2B catalog) has been processed in the session, every subsequently created shop header is built via the CustomerNo <> '' branch of CreateTempSalesHeader() — i.e. with that customer's price group, discount group and line-discount setting instead of the shop's. This defect survives even the cases where the header itself is correctly rebuilt (shop modified, work date changed).
Preconditions
Both defects require the catalog sync and the shop-based calculation to run in the same session. That happens whenever the syncs execute in the foreground, i.e. EnqueueJobEntry falls through to Report.Execute(ReportId, XmlParameters):
- Shop
"Allow Background Syncs"= false, or TaskScheduler.CanCreateTask()= false (e.g. some sandbox/upgrade/test contexts).
Job-queue (background) execution isolates the runs in separate sessions and hides the problem, which makes it intermittent-looking in the field.
Expected behavior
SetShop must guarantee the cached temp sales header reflects the shop parameters, regardless of whether a catalog was processed earlier in the session. CustomerNo must not leak from a catalog into shop-based price calculation.
Steps to reproduce
Data setup (W1, LCY = any, e.g. CZK):
- Shopify shop with
"Currency Code"= '' (blank = LCY) and"Allow Background Syncs"= false. - Item with a sales price, mapped to a Shopify product.
- Market catalog for the shop with
"Currency Code"= EUR (imported via Get Catalogs, EUR currency has ISO Code filled) and"Sync Prices"= true; the product is part of the catalog's publication in Shopify.
Repro:
- In one client session run Sync catalog prices (report 30116 "Shpfy Sync Catalog Prices") — runs foreground.
- In the same session run Sync prices from the Shopify Products page (report 30108 with Only sync prices) — runs foreground.
- Inspect the price sent by step 5 (or the calculated
Priceon the Shopify variant record).
Actual: the base price is calculated in EUR (catalog currency) — the EUR amount is stored/sent as the shop-currency base price.
Expected: the base price is calculated in the shop currency.
Unit-level repro (simpler, no Shopify round-trip): in a test codeunit call ProductPriceCalc.SetShopAndCatalog(Shop, CatalogWithEurAndCustomer), then ProductPriceCalc.SetShop(Shop), then CalcPrice(...) — GetCurrencyCode() still returns the catalog currency, and the temp header is built for the catalog's customer.
Suggested fix
In SetParameters, Database::"Shpfy Shop" branch: add CustomerNo := ''; (fixes defect 2).
For defect 1, SetShop must detect that the last initialization came from a catalog, e.g. track a InitializedFromCatalog: Boolean set by SetShopAndCatalog/cleared by SetShop, and include it in the re-init condition:
if InitializedFromCatalog or (Shop.Code <> ShopifyShop.Code) or (Shop.SystemModifiedAt < ShopifyShop.SystemModifiedAt) or (TempSalesHeader."Document Date" <> WorkDate()) then ...
(Alternatively Clear(Catalog) in SetShop plus comparing against Catalog.Id <> 0.) A regression test fits naturally into ShpfyProductPriceCalcTest.Codeunit.al.
Affected versions
- Verified in v28 (28.3,
releases/28.x) —SetShopthere lacks the work-date condition but has the same two defects. - Verified still present on
main(v29 dev) as of 2026-07-20.
Additional context
Codeunit is Access = Internal; partners cannot work around this other than by forcing background syncs. The failure mode is silently wrong prices in Shopify, with no entry in Shopify Skipped Records.
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Research direction
Start with Codeunit 30182 "Shpfy Product Price Calc." and trace SetShopAndCatalog, SetShop, SetParameters, and CreateTempSalesHeader in the catalog-then-shop sequence described. Add the regression coverage in ShpfyProductPriceCalcTest.Codeunit.al, verifying that shop calculations use the shop currency and customer settings after catalog processing and that the existing price calculation behavior remains correct.
Written by the indexing model from the issue text.
Assessment
- Domain
- backend
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Clearly specified
- Newbie friendliness
- 68/100