//go:build unit package service import ( "context" "errors" "fmt" "strconv" "testing" "time" dbent "github.com/Wei-Shaw/sub2api/ent" "github.com/Wei-Shaw/sub2api/ent/paymentauditlog" "github.com/Wei-Shaw/sub2api/internal/payment" infraerrors "github.com/Wei-Shaw/sub2api/internal/pkg/errors" "github.com/stretchr/testify/require" ) func TestValidateRefundRequestRejectsLegacyGuessedProviderInstance(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-legacy@example.com"). SetPasswordHash("hash"). SetUsername("refund-legacy-user"). Save(ctx) require.NoError(t, err) _, err = client.PaymentProviderInstance.Create(). SetProviderKey(payment.TypeAlipay). SetName("alipay-refund-instance"). SetConfig("{}"). SetSupportedTypes("alipay"). SetEnabled(true). SetAllowUserRefund(true). SetRefundEnabled(true). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(88). SetPayAmount(88). SetFeeRate(0). SetRechargeCode("REFUND-LEGACY-ORDER"). SetOutTradeNo("sub2_refund_legacy_order"). SetPaymentType(payment.TypeAlipay). SetPaymentTradeNo("trade-legacy-refund"). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusCompleted). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). Save(ctx) require.NoError(t, err) svc := &PaymentService{ entClient: client, } _, err = svc.validateRefundRequest(ctx, order.ID, user.ID) require.Error(t, err) require.Equal(t, "USER_REFUND_DISABLED", infraerrors.Reason(err)) } func TestPrepareRefundRejectsLegacyGuessedProviderInstance(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-legacy-admin@example.com"). SetPasswordHash("hash"). SetUsername("refund-legacy-admin-user"). Save(ctx) require.NoError(t, err) _, err = client.PaymentProviderInstance.Create(). SetProviderKey(payment.TypeAlipay). SetName("alipay-refund-admin-instance"). SetConfig("{}"). SetSupportedTypes("alipay"). SetEnabled(true). SetAllowUserRefund(true). SetRefundEnabled(true). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(188). SetPayAmount(188). SetFeeRate(0). SetRechargeCode("REFUND-LEGACY-ADMIN-ORDER"). SetOutTradeNo("sub2_refund_legacy_admin_order"). SetPaymentType(payment.TypeAlipay). SetPaymentTradeNo("trade-legacy-admin-refund"). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusCompleted). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). Save(ctx) require.NoError(t, err) svc := &PaymentService{ entClient: client, } plan, result, err := svc.PrepareRefund(ctx, order.ID, 0, "", false, false) require.Nil(t, plan) require.Nil(t, result) require.Error(t, err) require.Equal(t, "REFUND_DISABLED", infraerrors.Reason(err)) } func TestPrepDeductBalanceRequiresForceWhenBalanceIsInsufficient(t *testing.T) { for _, tc := range []struct { name string balance float64 force bool wantDeduct float64 wantWarning bool }{ {name: "insufficient balance", balance: 40, wantWarning: true}, {name: "forced insufficient balance", balance: 40, force: true, wantDeduct: 40}, {name: "equal balance", balance: 100, wantDeduct: 100}, } { t.Run(tc.name, func(t *testing.T) { plan := &RefundPlan{RefundAmount: 100} svc := &PaymentService{userRepo: &mockUserRepo{getByIDUser: &User{Balance: tc.balance}}} result := svc.prepDeduct(context.Background(), &dbent.PaymentOrder{ UserID: 1, OrderType: payment.OrderTypeBalance, }, plan, tc.force) if tc.wantWarning { require.NotNil(t, result) require.False(t, result.Success) require.True(t, result.RequireForce) require.Equal(t, "user balance is insufficient for deduction, use force", result.Warning) require.Zero(t, plan.BalanceToDeduct) return } require.Nil(t, result) require.Equal(t, payment.DeductionTypeBalance, plan.DeductionType) require.Equal(t, tc.wantDeduct, plan.BalanceToDeduct) }) } } func TestExecuteRefundUsesActualAvailableBalanceDeduction(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-execute-clamp@example.com"). SetPasswordHash("hash"). SetUsername("refund-execute-clamp"). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(100). SetPayAmount(100). SetFeeRate(0). SetRechargeCode("REFUND-EXECUTE-CLAMP"). SetOutTradeNo("refund_execute_clamp"). SetPaymentType(payment.TypeStripe). SetPaymentTradeNo(""). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusCompleted). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). Save(ctx) require.NoError(t, err) repo := &mockUserRepo{deductAvailableBalanceFn: func(_ context.Context, id int64, amount float64) (float64, error) { require.Equal(t, user.ID, id) require.Equal(t, 100.0, amount) return 25, nil }} plan := &RefundPlan{ OrderID: order.ID, Order: order, RefundAmount: 100, GatewayAmount: 100, Reason: "concurrent spend", Force: true, DeductionType: payment.DeductionTypeBalance, BalanceToDeduct: 100, } result, err := (&PaymentService{entClient: client, userRepo: repo}).ExecuteRefund(ctx, plan) require.NoError(t, err) require.True(t, result.Success) require.Equal(t, 25.0, plan.BalanceToDeduct) require.Equal(t, 25.0, result.BalanceDeducted) audit, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Only(ctx) require.NoError(t, err) require.Contains(t, audit.Detail, `"balanceDeducted":25`) } func TestGwRefundRejectsAlipayMerchantIdentitySnapshotMismatch(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-snapshot-mismatch@example.com"). SetPasswordHash("hash"). SetUsername("refund-snapshot-mismatch-user"). Save(ctx) require.NoError(t, err) inst, err := client.PaymentProviderInstance.Create(). SetProviderKey(payment.TypeAlipay). SetName("alipay-refund-mismatch-instance"). SetConfig(encryptWebhookProviderConfig(t, map[string]string{ "appId": "runtime-alipay-app", "privateKey": "runtime-private-key", })). SetSupportedTypes("alipay"). SetEnabled(true). SetRefundEnabled(true). Save(ctx) require.NoError(t, err) instID := strconv.FormatInt(inst.ID, 10) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(88). SetPayAmount(88). SetFeeRate(0). SetRechargeCode("REFUND-SNAPSHOT-MISMATCH-ORDER"). SetOutTradeNo("sub2_refund_snapshot_mismatch_order"). SetPaymentType(payment.TypeAlipay). SetPaymentTradeNo("trade-refund-snapshot-mismatch"). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusCompleted). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). SetProviderInstanceID(instID). SetProviderKey(payment.TypeAlipay). SetProviderSnapshot(map[string]any{ "schema_version": 2, "provider_instance_id": instID, "provider_key": payment.TypeAlipay, "merchant_app_id": "expected-alipay-app", }). Save(ctx) require.NoError(t, err) svc := &PaymentService{ entClient: client, loadBalancer: newWebhookProviderTestLoadBalancer(client), } _, err = svc.gwRefund(ctx, &RefundPlan{ OrderID: order.ID, Order: order, RefundAmount: order.Amount, GatewayAmount: order.Amount, Reason: "snapshot mismatch", }) require.ErrorContains(t, err, "alipay app_id mismatch") } func TestCalculateGatewayRefundAmountUsesCurrencyPrecision(t *testing.T) { require.InDelta(t, 6.173, calculateGatewayRefundAmount(100, 12.345, 50, "KWD"), 1e-12) require.InDelta(t, 12.345, calculateGatewayRefundAmount(100, 12.345, 100, "KWD"), 1e-12) require.InDelta(t, 52, calculateGatewayRefundAmount(100, 103, 50, "JPY"), 1e-12) } func TestFormatGatewayRefundAmountUsesOrderCurrency(t *testing.T) { order := &dbent.PaymentOrder{ ProviderSnapshot: map[string]any{ "currency": "KWD", }, } require.Equal(t, "12.345", formatGatewayRefundAmount(12.345, order)) } func TestValidateRefundProviderResponseAcceptsPending(t *testing.T) { require.NoError(t, validateRefundProviderResponse(&payment.RefundResponse{Status: payment.ProviderStatusPending})) require.NoError(t, validateRefundProviderResponse(&payment.RefundResponse{Status: payment.ProviderStatusSuccess})) require.Error(t, validateRefundProviderResponse(&payment.RefundResponse{Status: payment.ProviderStatusFailed})) require.Error(t, validateRefundProviderResponse(nil)) } func TestFinishRefundPendingMarksOrderPendingAndRollsBackDeduction(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-pending@example.com"). SetPasswordHash("hash"). SetUsername("refund-pending-user"). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(100). SetPayAmount(100). SetFeeRate(0). SetRechargeCode("REFUND-PENDING-ORDER"). SetOutTradeNo("sub2_refund_pending_order"). SetPaymentType(payment.TypeStripe). SetPaymentTradeNo("pi_refund_pending"). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusRefunding). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). Save(ctx) require.NoError(t, err) var rolledBack float64 userRepo := &mockUserRepo{} userRepo.updateBalanceFn = func(ctx context.Context, id int64, amount float64) error { require.Equal(t, user.ID, id) rolledBack += amount return nil } svc := &PaymentService{ entClient: client, userRepo: userRepo, } plan := &RefundPlan{ OrderID: order.ID, Order: order, RefundAmount: 40, GatewayAmount: 40, Reason: "gateway accepted but not final", Force: true, DeductionType: payment.DeductionTypeBalance, BalanceToDeduct: 40, } result, err := svc.finishRefund(ctx, plan, &payment.RefundResponse{Status: payment.ProviderStatusPending}) require.NoError(t, err) require.NotNil(t, result) require.False(t, result.Success) require.Contains(t, result.Warning, "pending confirmation") require.Equal(t, 40.0, rolledBack) require.Zero(t, plan.BalanceToDeduct) reloaded, err := client.PaymentOrder.Get(ctx, order.ID) require.NoError(t, err) require.Equal(t, OrderStatusRefundPending, reloaded.Status) require.Equal(t, 40.0, reloaded.RefundAmount) require.NotNil(t, reloaded.RefundReason) require.Equal(t, "gateway accepted but not final", *reloaded.RefundReason) require.Nil(t, reloaded.RefundAt) pendingAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_PENDING")). Count(ctx) require.NoError(t, err) require.Equal(t, 1, pendingAudits) successAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Count(ctx) require.NoError(t, err) require.Zero(t, successAudits) } func TestFinishRefundSuccessStatusesFinalize(t *testing.T) { for _, status := range []string{payment.ProviderStatusSuccess, payment.ProviderStatusRefunded} { t.Run(status, func(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) user, err := client.User.Create(). SetEmail("refund-success-" + status + "@example.com"). SetPasswordHash("hash"). SetUsername("refund-success-" + status). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(100). SetPayAmount(100). SetFeeRate(0). SetRechargeCode("REFUND-SUCCESS-" + status). SetOutTradeNo("sub2_refund_success_" + status). SetPaymentType(payment.TypeStripe). SetPaymentTradeNo("pi_refund_success_" + status). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusRefunding). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). Save(ctx) require.NoError(t, err) svc := &PaymentService{entClient: client} plan := &RefundPlan{ OrderID: order.ID, Order: order, RefundAmount: 100, GatewayAmount: 100, Reason: "final success", DeductionType: payment.DeductionTypeBalance, BalanceToDeduct: 100, } result, err := svc.finishRefund(ctx, plan, &payment.RefundResponse{Status: status}) require.NoError(t, err) require.NotNil(t, result) require.True(t, result.Success) require.Equal(t, 100.0, result.BalanceDeducted) reloaded, err := client.PaymentOrder.Get(ctx, order.ID) require.NoError(t, err) require.Equal(t, OrderStatusRefunded, reloaded.Status) require.NotNil(t, reloaded.RefundAt) successAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Count(ctx) require.NoError(t, err) require.Equal(t, 1, successAudits) pendingAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_PENDING")). Count(ctx) require.NoError(t, err) require.Zero(t, pendingAudits) }) } } func TestQueryAndFinalizeRefundFinalizesProviderStatuses(t *testing.T) { for _, tc := range []struct { name string status string wantStatus string wantDeduct float64 available float64 }{ {name: "success", status: payment.ProviderStatusSuccess, wantStatus: OrderStatusRefunded, wantDeduct: 100, available: 100}, {name: "success clamps current balance", status: payment.ProviderStatusSuccess, wantStatus: OrderStatusRefunded, wantDeduct: 35, available: 35}, {name: "failed", status: payment.ProviderStatusFailed, wantStatus: OrderStatusRefundFailed}, {name: "pending", status: payment.ProviderStatusPending, wantStatus: OrderStatusRefundPending}, } { t.Run(tc.name, func(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) order := createPendingRefundOrderForTest(t, ctx, client, "query-finalize-"+tc.name) var deducted float64 svc := &PaymentService{ entClient: client, loadBalancer: &captureLoadBalancer{}, userRepo: &mockUserRepo{deductAvailableBalanceFn: func(ctx context.Context, id int64, amount float64) (float64, error) { deducted += tc.available return tc.available, nil }}, } restore := replacePaymentProviderFactoryForTest(t, &refundQueryProviderTestDouble{ refundResponse: &payment.RefundResponse{RefundID: "rf_test", Status: tc.status}, }) defer restore() result, err := svc.QueryAndFinalizeRefund(ctx, order.ID) require.NoError(t, err) require.NotNil(t, result) require.Equal(t, tc.status == payment.ProviderStatusSuccess, result.Success) require.Equal(t, tc.wantDeduct, deducted) if tc.status == payment.ProviderStatusSuccess { require.Equal(t, tc.wantDeduct, result.BalanceDeducted) audit, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Only(ctx) require.NoError(t, err) require.Contains(t, audit.Detail, fmt.Sprintf(`"balanceDeducted":%v`, tc.wantDeduct)) } reloaded, err := client.PaymentOrder.Get(ctx, order.ID) require.NoError(t, err) require.Equal(t, tc.wantStatus, reloaded.Status) }) } } func TestFinalizePendingRefundSuccessRejectsStaleCallerBeforeSecondDeduction(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) order := createPendingRefundOrderForTest(t, ctx, client, "finalize-stale") deductions := 0 svc := &PaymentService{ entClient: client, userRepo: &mockUserRepo{deductAvailableBalanceFn: func(ctx context.Context, id int64, amount float64) (float64, error) { require.NotNil(t, dbent.TxFromContext(ctx)) deductions++ return amount, nil }}, } first, err := svc.finalizePendingRefundSuccess(ctx, svc.refundFinalizePlan(order)) require.NoError(t, err) require.True(t, first.Success) second, err := svc.finalizePendingRefundSuccess(ctx, svc.refundFinalizePlan(order)) require.Nil(t, second) require.Error(t, err) require.Equal(t, "CONFLICT", infraerrors.Reason(err)) require.Equal(t, 1, deductions) successAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Count(ctx) require.NoError(t, err) require.Equal(t, 1, successAudits) } func TestFinalizePendingRefundSuccessRollsBackPostDeductionFailure(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) order := createPendingRefundOrderForTest(t, ctx, client, "finalize-rollback") _, err := client.User.UpdateOneID(order.UserID).SetBalance(100).Save(ctx) require.NoError(t, err) svc := &PaymentService{ entClient: client, userRepo: &mockUserRepo{deductAvailableBalanceFn: func(ctx context.Context, id int64, amount float64) (float64, error) { tx := dbent.TxFromContext(ctx) require.NotNil(t, tx) if _, updateErr := tx.Client().User.UpdateOneID(id).AddBalance(-amount).Save(ctx); updateErr != nil { return 0, updateErr } return 0, errors.New("injected failure after deduction") }}, } result, err := svc.finalizePendingRefundSuccess(ctx, svc.refundFinalizePlan(order)) require.Nil(t, result) require.ErrorContains(t, err, "injected failure after deduction") user, err := client.User.Get(ctx, order.UserID) require.NoError(t, err) require.Equal(t, 100.0, user.Balance) reloaded, err := client.PaymentOrder.Get(ctx, order.ID) require.NoError(t, err) require.Equal(t, OrderStatusRefundPending, reloaded.Status) successAudits, err := client.PaymentAuditLog.Query(). Where(paymentauditlog.OrderIDEQ(strconv.FormatInt(order.ID, 10)), paymentauditlog.ActionEQ("REFUND_SUCCESS")). Count(ctx) require.NoError(t, err) require.Zero(t, successAudits) } func TestQueryAndFinalizeRefundUnsupportedProviderReturnsClearError(t *testing.T) { ctx := context.Background() client := newPaymentConfigServiceTestClient(t) order := createPendingRefundOrderForTest(t, ctx, client, "query-finalize-unsupported") svc := &PaymentService{entClient: client, loadBalancer: &captureLoadBalancer{}} restore := replacePaymentProviderFactoryForTest(t, refundProviderTestDouble{}) defer restore() result, err := svc.QueryAndFinalizeRefund(ctx, order.ID) require.Nil(t, result) require.Error(t, err) require.Equal(t, "REFUND_QUERY_UNSUPPORTED", infraerrors.Reason(err)) } func createPendingRefundOrderForTest(t *testing.T, ctx context.Context, client *dbent.Client, suffix string) *dbent.PaymentOrder { t.Helper() user, err := client.User.Create(). SetEmail(suffix + "@example.com"). SetPasswordHash("hash"). SetUsername(suffix). Save(ctx) require.NoError(t, err) inst, err := client.PaymentProviderInstance.Create(). SetProviderKey(payment.TypeStripe). SetName(suffix + "-provider"). SetConfig("{}"). SetSupportedTypes("stripe"). SetEnabled(true). SetRefundEnabled(true). Save(ctx) require.NoError(t, err) order, err := client.PaymentOrder.Create(). SetUserID(user.ID). SetUserEmail(user.Email). SetUserName(user.Username). SetAmount(100). SetPayAmount(100). SetFeeRate(0). SetRechargeCode("REFUND-" + suffix). SetOutTradeNo("sub2_" + suffix). SetPaymentType(payment.TypeStripe). SetPaymentTradeNo("pi_" + suffix). SetOrderType(payment.OrderTypeBalance). SetStatus(OrderStatusRefundPending). SetRefundAmount(100). SetRefundReason("pending refund"). SetExpiresAt(time.Now().Add(time.Hour)). SetPaidAt(time.Now()). SetClientIP("127.0.0.1"). SetSrcHost("api.example.com"). SetProviderInstanceID(strconv.FormatInt(inst.ID, 10)). Save(ctx) require.NoError(t, err) _, err = client.PaymentAuditLog.Create(). SetOrderID(strconv.FormatInt(order.ID, 10)). SetAction("REFUND_PENDING"). SetOperator("admin"). SetDetail(`{"refundID":"rf_test","deductionRollbackOK":true}`). Save(ctx) require.NoError(t, err) return order } func replacePaymentProviderFactoryForTest(t *testing.T, prov payment.Provider) func() { t.Helper() original := createPaymentProviderFromInstance createPaymentProviderFromInstance = func(providerKey, instanceID string, config map[string]string) (payment.Provider, error) { return prov, nil } return func() { createPaymentProviderFromInstance = original } } type refundProviderTestDouble struct{} func (refundProviderTestDouble) Name() string { return "refund-test" } func (refundProviderTestDouble) ProviderKey() string { return payment.TypeStripe } func (refundProviderTestDouble) SupportedTypes() []payment.PaymentType { return []payment.PaymentType{payment.TypeStripe} } func (refundProviderTestDouble) CreatePayment(context.Context, payment.CreatePaymentRequest) (*payment.CreatePaymentResponse, error) { return nil, nil } func (refundProviderTestDouble) QueryOrder(context.Context, string) (*payment.QueryOrderResponse, error) { return nil, nil } func (refundProviderTestDouble) VerifyNotification(context.Context, string, map[string]string) (*payment.PaymentNotification, error) { return nil, nil } func (refundProviderTestDouble) Refund(context.Context, payment.RefundRequest) (*payment.RefundResponse, error) { return nil, nil } type refundQueryProviderTestDouble struct { refundProviderTestDouble refundResponse *payment.RefundResponse } func (p *refundQueryProviderTestDouble) QueryRefund(context.Context, payment.RefundQueryRequest) (*payment.RefundResponse, error) { return p.refundResponse, nil }