[Shopify] Skip refund credit memo while transaction is pending#9112
Merged
onbuyuka merged 3 commits intoJul 9, 2026
Conversation
When a Shopify refund is synced while its payment transaction is still pending, Shopify's totalRefundedSet returns 0, so the balancing line calculation produced a credit memo that zeroed out to a total of 0. This blocks credit memo/return order creation while the refund still has a pending transaction: the auto-sync path skips it silently and retries on the next sync (once the transaction succeeds), and the manual Create Sales Document path shows a clear error. Adds a HasPendingRefundTransactions helper plus tests. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Contributor
Copilot PR ReviewIteration 3 · Outcome: completed
Knowledge source: https://github.com/microsoft/BCQuality@822cae1b2771ac25f665f73369f69093bd4fd630 Orchestrator pre-filter (13 file(s) excluded)
Findings produced by the Copilot CLI agent against BCQuality at |
…lookup HasPendingRefundTransactions (and the pre-existing MapPaymentMethodCode / GetRoundingAmountFromTransactions) filter Shpfy Order Transaction by Refund Id, but no key had Refund Id as a leading field, forcing a scan on a table that grows unbounded. Add key (Refund Id, Type, Status) covering all three call sites and set it explicitly in HasPendingRefundTransactions. Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
onbuyuka
enabled auto-merge
July 6, 2026 08:40
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
darjoo
approved these changes
Jul 7, 2026
nikolakukrika
approved these changes
Jul 9, 2026
onbuyuka
added a commit
that referenced
this pull request
Jul 23, 2026
Fixes [AB#640432](https://dynamicssmb2.visualstudio.com/1fcb79e7-ab07-432a-a3c6-6cf5a88ba4a5/_workitems/edit/640432) When a Shopify refund is synced while its payment transaction is still **pending**, Shopify's `totalRefundedSet` returns 0 (it only counts `SUCCESS` transactions). If a credit memo is created at that moment, the balancing line in `CreateSalesLinesFromRemainingAmount` calculates `Unit Price = 0 - <item total>`, producing a credit memo whose total is 0 — a financially useless document. `ShpfyCreateSalesDocRefund.Codeunit.al` balances the document against `RefundHeader."Total Refunded Amount"`, which is 0 while the refund transaction is still pending, even though the item/return lines already sum to the real amount. Block credit memo / return order creation while the refund still has a pending transaction, mirroring the existing `"Can Create Credit Memo"` dual-guard pattern: - **`ShpfyRefundsAPI.Codeunit.al`** — new internal helper `HasPendingRefundTransactions(RefundId)` that checks for refund transactions with `Type = Refund` and `Status = Pending`. `VerifyRefundCanCreateCreditMemo` now throws a clear error when a pending transaction exists (manual **Create Sales Document** path). - **`ShpfyRetRefProcCrMemo.Codeunit.al`** — `CreateSalesDocument` now exits early (silent skip) when the refund still has a pending transaction (auto-sync path). The refund stays unprocessed and is retried on the next sync; once the transaction reaches `SUCCESS`, `totalRefundedSet` is final and the credit memo is created correctly. This is safe because the auto-processing loop (`ProcessShopifyRefunds`) retries all unprocessed refunds on every sync, and no data is guessed or approximated. Added to `ShpfyOrderRefundTest.Codeunit.al` (with a `CreateRefundTransaction` helper in `ShpfyOrderRefundsHelper.Codeunit.al`): - `UnitTestDoesNotCreateCrMemoFromRefundWithPendingTransaction` — no credit memo is created while the refund has a pending transaction. - `UnitTestCreatesCrMemoFromRefundWithSucceededTransaction` — the guard is specific to pending; a succeeded transaction still creates the credit memo. - `UnitTestVerifyRefundCanCreateCreditMemoErrorsWithPendingTransaction` — the manual path throws the pending-transaction error. --------- Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com> Copilot-Session: b1f006ac-3ace-495d-8b5c-9b76510cf117
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Fixes AB#640432
Summary
When a Shopify refund is synced while its payment transaction is still pending, Shopify's
totalRefundedSetreturns 0 (it only countsSUCCESStransactions). If a credit memo is created at that moment, the balancing line inCreateSalesLinesFromRemainingAmountcalculatesUnit Price = 0 - <item total>, producing a credit memo whose total is 0 — a financially useless document.Root cause
ShpfyCreateSalesDocRefund.Codeunit.albalances the document againstRefundHeader."Total Refunded Amount", which is 0 while the refund transaction is still pending, even though the item/return lines already sum to the real amount.Fix
Block credit memo / return order creation while the refund still has a pending transaction, mirroring the existing
"Can Create Credit Memo"dual-guard pattern:ShpfyRefundsAPI.Codeunit.al— new internal helperHasPendingRefundTransactions(RefundId)that checks for refund transactions withType = RefundandStatus = Pending.VerifyRefundCanCreateCreditMemonow throws a clear error when a pending transaction exists (manual Create Sales Document path).ShpfyRetRefProcCrMemo.Codeunit.al—CreateSalesDocumentnow exits early (silent skip) when the refund still has a pending transaction (auto-sync path). The refund stays unprocessed and is retried on the next sync; once the transaction reachesSUCCESS,totalRefundedSetis final and the credit memo is created correctly.This is safe because the auto-processing loop (
ProcessShopifyRefunds) retries all unprocessed refunds on every sync, and no data is guessed or approximated.Test plan
Added to
ShpfyOrderRefundTest.Codeunit.al(with aCreateRefundTransactionhelper inShpfyOrderRefundsHelper.Codeunit.al):UnitTestDoesNotCreateCrMemoFromRefundWithPendingTransaction— no credit memo is created while the refund has a pending transaction.UnitTestCreatesCrMemoFromRefundWithSucceededTransaction— the guard is specific to pending; a succeeded transaction still creates the credit memo.UnitTestVerifyRefundCanCreateCreditMemoErrorsWithPendingTransaction— the manual path throws the pending-transaction error.