diff --git a/veza-backend-api/internal/handlers/admin_transfer_handler_test.go b/veza-backend-api/internal/handlers/admin_transfer_handler_test.go index c15db2551..8b0d878a2 100644 --- a/veza-backend-api/internal/handlers/admin_transfer_handler_test.go +++ b/veza-backend-api/internal/handlers/admin_transfer_handler_test.go @@ -164,7 +164,7 @@ func TestGetTransfers_FilterBySeller(t *testing.T) { func TestRetryTransfer_Success(t *testing.T) { db := setupAdminTransferTestDB(t) logger := zap.NewNop() - mock := &mockTransferServiceAdmin{} + mock := &mockTransferServiceAdmin{stripeTransferID: "tr_admin_retry_ok"} handler := NewAdminTransferHandler(db, mock, 0.10, logger) transferID := uuid.New() @@ -192,6 +192,11 @@ func TestRetryTransfer_Success(t *testing.T) { var updated marketplace.SellerTransfer require.NoError(t, db.First(&updated, transferID).Error) assert.Equal(t, "completed", updated.Status) + // v1.0.7 item A: admin-triggered retry also persists the Stripe + // transfer id. The worker and processSellerTransfers paths are + // already covered by their own tests; this is the third path into + // the same behavior. + assert.Equal(t, "tr_admin_retry_ok", updated.StripeTransferID) } func TestRetryTransfer_NotFailed(t *testing.T) { diff --git a/veza-backend-api/internal/services/stripe_connect_service.go b/veza-backend-api/internal/services/stripe_connect_service.go index b75b033c1..839034e50 100644 --- a/veza-backend-api/internal/services/stripe_connect_service.go +++ b/veza-backend-api/internal/services/stripe_connect_service.go @@ -208,5 +208,12 @@ func (s *StripeConnectService) CreateTransfer(ctx context.Context, sellerUserID if err != nil { return "", fmt.Errorf("create stripe transfer: %w", err) } + // Defensive: Stripe's Go SDK should never return (tr, nil) with an empty + // tr.ID, but the invariant is load-bearing for item B (reversal needs a + // real id to target). If it's ever violated we'd rather fail the transfer + // than persist an empty string and leave the row permanently un-reversible. + if tr.ID == "" { + return "", fmt.Errorf("create stripe transfer: provider returned empty transfer id") + } return tr.ID, nil }