Square client and dev mock: replay-by-key reconcile, refund classification, mock parity

ReplayPaymentByKey (POST /v2/payments re-issue with the same idempotency key
and a synthetic probe source token that can never process a real charge):
Square returns the ORIGINAL payment for a retained key and definitively
rejects an unknown/expired one, so the stale-pending sweep can rescue
lost-response charges without ever issuing a second payment. ErrReplayKeyNotRetained
marks a probe rejection as proof the charge never happened.

Refund classification: zero-amount refunds are now rejected (Square requires
amount_money) instead of lenient full-refund; REFUND_ALREADY_PENDING is
classified as already-processed to match the real contract.

Dev mock parity: SquarePayID == payment ID (was fabricated 'sqp_' prefix),
ForceCheckoutState for IN_PROGRESS/CANCEL_REQUESTED terminal states,
replay-by-key support, aligned refund error codes.
This commit is contained in:
2026-08-22 00:34:49 +01:00
parent 197d4c4b9b
commit 01ac211408
5 changed files with 310 additions and 33 deletions
+4
View File
@@ -35,6 +35,10 @@ func (p *ProdClient) GetPayment(ctx context.Context, paymentID string) (*Payment
return getPaymentHTTP(ctx, paymentID)
}
func (p *ProdClient) ReplayPaymentByKey(ctx context.Context, idempotencyKey string, amount int64) (*PaymentResult, error) {
return replayPaymentByKeyHTTP(ctx, idempotencyKey, amount)
}
func (p *ProdClient) CreateCustomer(ctx context.Context, name, email string) (*CustomerResult, error) {
return createCustomerHTTP(ctx, name, email)
}