bug(payments): wallet card_network is null in V1 /payments/list but present in /payments/{id}
C-bugA-payments
## Summary
The V1 payments **list** API (`GET /payments/list`, consumed by the Control Center transaction list) returns `card_network` as `null` for wallet transactions (Google Pay / Apple Pay / Samsung Pay), while the payments **retrieve** API (`GET /payments/{id}`) correctly returns the wallet's underlying `card_network`. Plain card payments return `card_network` in both. The divergence is backend-only — the Control Center already reads `card_network` from the list payload, the value is simply `null`.
## Root cause
Both responses build `payment_method_data` from the same stored column (`payment_attempt.payment_method_data`, persisted as `AdditionalPaymentData`):
- **Retrieve** (`crates/router/src/core/payments/transformers.rs`): parses the column as `AdditionalPaymentData`, then converts via `PaymentMethodDataResponse::from(...)`. That `From` impl (`crates/api_models/src/payments.rs`) maps the wallet's `apple_pay` / `google_pay` data into `WalletAdditionalDataForCard.card_network`.
- **List** (`ForeignFrom<(PaymentIntent, PaymentAttempt)> for PaymentsResponse` in the same `transformers.rs`): deserialized the raw stored column **directly** into `PaymentMethodDataResponseWithBilling`, skipping the `AdditionalPaymentData` → response conversion. For the **Card** variant the serde field names coincide, so `card_network` survives. For the **Wallet** variant the serde shapes differ (`AdditionalPaymentData::Wallet { apple_pay, google_pay, samsung_pay }` vs the externally-tagged `WalletResponseData`), so the parse drops the wallet data and `card_network` becomes `null`. The failed parse is logged but swallowed.
## Expected
V1 `/payments/list` returns `payment_method_data.wallet.<wallet>.card_network` for wallet payments, matching the retrieve response for the same payment.
## Fix
In the V1 list `ForeignFrom` impl, build `payment_method_data` the same way retrieve does — parse the stored value as `AdditionalPaymentData` (via `check_and_get_payment_method_data_based_on_encryption_strategy()`) and convert through `PaymentMethodDataResponse::from`.
## Scope
- Backend only; no frontend change required.
- No API contract / DB schema change.
- ClickHouse analytics list is out of scope.
_Reproduced on a wallet payment for a merchant with this enabled (IDs redacted)._
0 条评论