Skip to content

[releases/28.x] [Shopify] Tolerate legacy bulk-operation request data missing unitCost key#8636

Open
onbuyuka wants to merge 1 commit into
releases/28.xfrom
bugs/638798-backport
Open

[releases/28.x] [Shopify] Tolerate legacy bulk-operation request data missing unitCost key#8636
onbuyuka wants to merge 1 commit into
releases/28.xfrom
bugs/638798-backport

Conversation

@onbuyuka

@onbuyuka onbuyuka commented Jun 16, 2026

Copy link
Copy Markdown
Contributor

Summary

Backport of bug #637250 to releases/28.x.

Guards the bulk-operation rollback unitCost read with JsonObject.Contains('unitCost') in both call sites (ShpfyBulkUpdateProductPrice.RevertRequests and ShpfyProductExport.RevertVariantChanges), so a request-data blob persisted before the unitCost key was added (e.g. a bulk operation queued before the BC28 upgrade) no longer throws "There are no properties with the key 'unitCost' on the JSON object" on revert.

Fixes AB#638798

Notes

…t key (#8386)

Bulk variant price updates persist a JSON `Request Data` blob on `Shpfy
Bulk Operation` so the rollback path can restore the previous Price /
Compare-at-Price / Updated At / Unit Cost values when Shopify's async
callback reports failure.

PR #6155 added a new `unitCost` key to that blob and a matching reader
on the rollback path, but the reader uses `JsonObject.GetDecimal` which
throws if the key is missing. Any bulk operation queued **before** the
upgrade (no `unitCost` in the blob) and reverted **after** the upgrade
crashes with:

> There are no properties with the key 'unitCost' on the JSON object

The same stale rows can keep retrying, so the error surfaces repeatedly
even though the upgrade happened once.

The Shopify API payload itself is unaffected — it still correctly sends
`inventoryItem.cost`. The crash is purely on the BC-side rollback
reader.

**Production code**
- `ShpfyBulkUpdateProductPrice.RevertRequests` and
`ShpfyProductExport.RevertVariantChanges`: guard the `unitCost` read
with `JsonObject.Contains('unitCost')`. If absent (legacy blob), Unit
Cost is left untouched, matching the pre-PR-#6155 behaviour.

**Test code**
- `TestBulkOperationRevertFailedWithLegacyRequestDataMissingUnitCost`:
new regression test that builds a request-data blob without the
`unitCost` key (via a `GenerateLegacyRequestDataWithoutUnitCost` helper)
and asserts that the rollback completes without throwing, reverts Price
/ Compare-at-Price correctly, and leaves Unit Cost untouched.

The other keys (`id`, `price`, `compareAtPrice`, `updatedAt`) have been
written by `ShpfyVariantAPI.UpdateProductPrice` since the connector was
first migrated to BCApps — there is no version that ever persisted a
`Request Data` blob without them. A missing
`price`/`compareAtPrice`/`updatedAt`/`id` is therefore not a legitimate
"legacy blob" scenario; it would be a real upstream bug (regressed
writer, corrupted blob, forgotten `JRequest.Add`). `GetDecimal`'s throw
is the correct behaviour there — surfacing the bug loudly is better than
silently skipping a rollback (which would leave variants showing the
wrong price in BC, or no-op the revert with zero diagnostic).

`unitCost` is the one and only key that was added later, so it's the one
key where a key-missing scenario has both a legitimate root cause
(legacy persisted blob) and a safe fallback (leave the field untouched).

Customers hitting this on the current BC28 build can self-mitigate by
opening the **Shopify Bulk Operations** page and running **Delete
Entries Older Than 7 Days**. The deletion bypasses the rollback trigger,
removing the stale pre-upgrade rows without re-throwing. Bulk operations
queued after the upgrade are written in the new layout and are
unaffected.

Main only — rare upgrade-window race condition with a self-service
mitigation available. Not backported.

Fixes
[AB#637250](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/637250)

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@onbuyuka onbuyuka requested a review from a team as a code owner June 16, 2026 10:34
@github-actions github-actions Bot added the AL: Apps (W1) Add-on apps for W1 label Jun 16, 2026
@github-actions github-actions Bot added this to the Version 28.3 milestone Jun 16, 2026
@onbuyuka onbuyuka enabled auto-merge (squash) June 16, 2026 10:47
@github-actions

Copy link
Copy Markdown
Contributor

⚠️ Stale Status Check Deleted

The Pull Request Build workflow run for this PR was older than 72 hours and has been deleted.

📋 Why was it deleted?

Status checks that are too old may no longer reflect the current state of the target branch. To ensure this PR is validated against the latest code and passes up-to-date checks, a fresh build is required.


🔄 How to trigger a new status check:

  1. 📤 Push a new commit to the PR branch, or
  2. 🔁 Close and reopen the PR

This will automatically trigger a new Pull Request Build workflow run.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

AL: Apps (W1) Add-on apps for W1

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant