fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471)#13147
fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment (shadow diff #17471)#1314710X-GRACE wants to merge 1 commit into
Conversation
Changed Files
|
Automated Review Summary✅ Positive: Correct amount/currency handling for MITFile: The implementation correctly handles the amount conversion from let original_payment_authorized_amount = router_data
.recurring_mandate_payment_data
.as_ref()
.and_then(|data| {
data.original_payment_authorized_amount
.zip(data.original_payment_authorized_currency)
})
.map(|(minor_amount, original_currency)| {
payments_grpc::Currency::foreign_try_from(original_currency)
.map(|currency| payments_grpc::Money { minor_amount, currency: currency.into() })
})
.transpose()?;Why this is correct:
✅ DocumentationThe inline comment explains the Cybersource MIT context well. 📊 PR Stats
Automated review by XyneSpaces |
Also resolves #17487 (cybersource/repeat_payment, flowbird) — validatedShadow-validation issue #17487 is a byte-for-byte sibling of #17471 (same merchant Before (issue #17487, req Facet C2: Grafana (prod, LIVE-confirmed, still in retention): RP_05 golden log for req Verification: classification ucs-only; code-parity confirmed against hyperswitch main No new PR opened for #17487 — this PR (C2) + prism #1805 (C1) + merged prism #1740 (A/B) fully cover it. |
Automated Review SummaryPR: fix(cybersource): populate original_payment_authorized_amount for UCS repeat_payment AnalysisThis PR fixes the UCS (Unified Checkout Service) payment flow by populating the Changes ReviewedFile: The change extracts Potential Issues[:warning:] Error propagation path: The [:bulb:] Suggestion: Consider adding a debug/trace log line when the original payment amount is successfully populated, to aid observability during MIT (Merchant Initiated Transaction) flows. Verdict✅ Approachable — The fix correctly addresses the shadow diff requirement. The logic mirrors the Direct gateway implementation pattern. Recommend adding a test case in This is an automated review. Human review is still recommended for merge approval. |
Re-validated against shadow diff #17498 (duplicate of #17471/#17487)This PR's Grafana CONFIRMED LIVE — req
Branch is current on |
Validated against another confirmed sibling: shadow-diff #17548 (cybersource / repeat_payment / flowbird)This PR (populating Grafana RCA (HIGH confidence — exact x-request-id matched in prod Loki):
Before (issue #17548 diff signature): After / attribution:
Verification on current main (hs
No creds / no |
647e0a4 to
adfc147
Compare
Shadow diff #17564 — also covered by this PR (cybersource / repeat_payment / flowbird)Validated on current Grafana RCA: exact prod x-request-id absent from accessible Loki (expected for this class); in-window flowbird cybersource shadow traffic confirmed on prod build Before (issue #17564 diff signature): After: This PR populates Re-validated: rebased this branch onto current |
… repeat_payment The UCS client built RecurringPaymentServiceChargeRequest with original_payment_authorized_amount: None, so the shadow UCS leg omitted the Cybersource MIT authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmount that the Direct gateway sends. Populate it from router_data.recurring_mandate_payment_data (the same source the Direct gateway reads), mapping the original amount + currency into the existing proto Money field. No proto change or rev-pin — the field already exists in the pinned connector-service proto. Fixes shadow-validation request_diff #17471. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
adfc147 to
fbcf9f1
Compare
Re-validated on current
|
Also covers shadow diff #17831 (duplicate of #17471) — re-validated on current
|
| Field | HS Direct | Shadow UCS (pre-fix prod build) |
|---|---|---|
...merchantInitiatedTransaction.originalAuthorizedAmount |
"2.00" |
null ← this PR |
authorizationOptions.initiator |
{type:"merchant", storedCredentialUsed:true} |
null (paired prism #1805) |
merchantDefinedInformation[0]/[1] / [3] |
correct | swapped / key-renamed (fixed by merged prism #1740) |
The originalAuthorizedAmount = null facet is exactly what this PR closes: the UCS client now maps
router_data.recurring_mandate_payment_data.original_payment_authorized_amount (+ currency) into
the existing proto Money field (field 23 — no proto change / no rev-pin).
What I did
- Confirmed this branch is current with
main(db02b4f06a) — 0 commits behind; the fix applies
cleanly on top ofmain. - Confirmed the diff's MDI facets are already resolved by merged prism fix(connector): deserialization error due to latest_charge stripe #1740 and the
initiatorfacet by prism feat(connector): [Adyen] implement PaySafe #1805; this PR handles the third facet (originalAuthorizedAmount).
Together with merged prism #1740 and prism #1805, all five diffing fields of #17831 are accounted
for. CI is green except REVIEW_REQUIRED (human review) and a pre-existing spell-check/linked-issue
nit unrelated to the fix. (Prod divergence is shadow-only/benign — the serving Direct leg sent the
correct body and got 201 AUTHORIZED.)
Re-validated against shadow diff #17848 (cybersource / repeat_payment / flowbird)New sibling shadow diff #17848 is byte-identical to #17471 (and #17583/#17831 …), so this PR covers it. Re-validated on current Before (issue #17848 diff signature — Facet ownership (unchanged from #17471):
After / verification:
Grafana prod RCA (HIGH confidence): decoded x-request-id UUIDv7 → true wire time 2026-06-30T15:08:23.534Z (68 min before the shadow-diff detection window 20:16–20:46Z — detection-vs-txn gotcha). Prod pod No new PR opened (this PR + prism #1805 fully cover #17848). No creds / |
Re-validated against shadow diff #17863 (cybersource / repeat_payment, DUP of #17471 family)Shadow-validation issue #17863 (merchant Before (prod diff signature, #17863)This PR's facetOn clean Grafana prod RCA (HIGH confidence)Decoded x-request-id UUIDv7 AfterWith merged prism #1740 (MDI, ancestor of StatusPR is 0 commits behind |
Re-validated against shadow diff #17880 (cybersource / repeat_payment, DUP of #17471 family)Shadow-validation issue #17880 (merchant Before (prod diff signature, #17880)Root cause (3 independent facets)
After
Grafana prod RCA (HIGH confidence)Decoded x-request-id UUIDv7 StatusPR is 0 commits behind |
Re-validated against shadow diff #17897 (cybersource / repeat_payment / flowbird / prod)Issue #17897 ( Before — prod diff signature (issue #17897): Grafana RCA (HIGH confidence). x-request-id decoded (UUIDv7) → true wire time 2026-06-30T15:36:10.055Z (issue First-Seen 20:46Z is the shadow-diff detection bucket, not wire time). Exact request found in prod UCS Loki ( After — resolution mapping (all three facets covered, no gap):
PR state: rebased 0-behind current |
Shadow-diff #17901 — cybersource / repeat_payment / flowbird (prod) — re-validated, covered by this PRIssue #17901 ( Grafana RCA (HIGH confidence). x-request-id UUIDv7 → real wire time 2026-06-30T15:38:50.568Z (issue First-Seen 20:46Z is the shadow-diff detection bucket). Exact outbound UCS request found in prod Loki Before (prod UCS body — the facet this PR fixes): (full diff signature also had the MDI brand/kind swap + Three facets — split across the family fixes:
After / PR status: this PR is 0 commits behind current hs main, No creds / no |
Re-validated against shadow diff #17906 (cybersource / repeat_payment / flowbird / prod)This open PR also covers the newly-filed #17906 (same flowbird cybersource Grafana RCA (prod, HIGH confidence)
Before (issue #17906 diff signature) After / status
PR is 0 commits behind main, MERGEABLE. CI: compilation + tests green; the only 2 red checks are pre-existing/unrelated (Spell check = santander |
Re-validated against shadow diff #17914 (cybersource / repeat_payment / flowbird / prod)This open PR also covers the newly-filed #17914 — same flowbird cybersource Grafana RCA (prod Loki, 2026-07-04T09:51:32Z):
Before (issue diff signature): Fix (this PR, After: with this PR applied UCS emits the same Status: PR is 0 commits behind |
Re-validated against current
|
Re-validated against shadow diff #17954 (cybersource / repeat_payment / flowbird, prod)This PR also resolves shadow diff #17954 — a duplicate of the same cybersource Grafana RCA (prod): sample Before (issue #17954 diff signature, relevant facet): After (this PR): Sibling facets in this diff are owned elsewhere: PR state: MERGEABLE with green CI (compilation on MSRV + stable tests pass); the changed file is disjoint from newer main commits so there's no conflict. Code re-verified against current hs main — no new PR needed for #17954. |
What
Paired hyperswitch-side fix for shadow-validation request_diff #17471
(
prod/ flowbird / cybersource / repeat_payment).The UCS client built
RecurringPaymentServiceChargeRequestwithoriginal_payment_authorized_amount: None, so the shadow UCS leg omitted the Cybersource MITprocessingInformation.authorizationOptions.merchantInitiatedTransaction.originalAuthorizedAmountthat the Direct gateway sends (as a string).
This populates the proto field from
router_data.recurring_mandate_payment_data— the sameRouterDatasource the Direct gateway reads (hyperswitch_connectors/.../cybersource/transformers.rs,ConnectorMandateId arm) — mapping the original amount + currency into the existing proto
Moneyfield:No proto change / no rev-pin —
original_payment_authorized_amount(field 23) already exists inthe pinned connector-service proto (
tag = 2026.07.02.1); only the client mapping was missing. Sothis is a normal PR, not a draft.
Root cause (RCA)
019f17b7-a5d0-76e1-b2e1-cbc78384f95b(2026-06-30T08:48:59Z), 2.60 EUR, flowbird,pay_SNJf2ptr0y2HCCcAZY47, off-session recurring MIT.authorizationOptionsfields.Before
After
original_payment_authorized_amountin the proto request; prism's cybersourcetransformer already consumes it and emits
merchantInitiatedTransaction.originalAuthorizedAmount,byte-matching Direct.
authorizationOptions.initiator = nullfacet is fixed in prism PRfix(cybersource): set MIT initiator for repeat_payment ConnectorMandateId (shadow diff #17471) hyperswitch-prism#1805.
Verification
cargo build -p router→ exit 0 (compiles against pinned connector-servicetag = 2026.07.02.1).recurring_mandate_payment_data.No creds;
config/development.tomlexcluded.