149 lines
11 KiB
Go
149 lines
11 KiB
Go
package payment
|
|
|
|
import (
|
|
"fmt"
|
|
bizpayment "kra/internal/biz/payment"
|
|
"time"
|
|
|
|
"github.com/google/uuid"
|
|
"gorm.io/gorm"
|
|
)
|
|
|
|
const DemoTradePrefix = "DEMO-PAY-"
|
|
|
|
type DemoSeedResult struct {
|
|
Orders int
|
|
Events int
|
|
}
|
|
|
|
// SeedDemoOrders replaces only DEMO-PAY-* records with a representative set
|
|
// of payment operations for administration-page review.
|
|
func SeedDemoOrders(db *gorm.DB, now time.Time) (*DemoSeedResult, error) {
|
|
if db == nil {
|
|
return nil, fmt.Errorf("demo payment database is nil")
|
|
}
|
|
if !db.Migrator().HasTable(&paymentOrderPO{}) || !db.Migrator().HasTable(&paymentEventPO{}) {
|
|
return nil, fmt.Errorf("payment tables are not migrated")
|
|
}
|
|
if now.IsZero() {
|
|
now = time.Now().UTC().Truncate(time.Second)
|
|
} else {
|
|
now = now.UTC().Truncate(time.Second)
|
|
}
|
|
|
|
type demoOrder struct {
|
|
order paymentOrderPO
|
|
events []paymentEventPO
|
|
}
|
|
makeOrder := func(index int, provider, subject, status, fulfillment, refund string, amount int64, currency string, created time.Time) paymentOrderPO {
|
|
tradeNo := fmt.Sprintf("%s%02d", DemoTradePrefix, index)
|
|
return paymentOrderPO{
|
|
TradeNo: tradeNo, Provider: provider, BusinessType: bizpayment.DemoBusinessType, BusinessID: fmt.Sprintf("DEMO-LICENSE-%02d", index),
|
|
Subject: subject, PaymentMode: bizpayment.PaymentModeExternal, OriginalAmount: amount, Amount: amount,
|
|
Currency: currency, PaymentStatus: status, FulfillmentStatus: fulfillment, RefundStatus: refund,
|
|
ConfirmationID: uuid.NewString(), RequestFingerprint: fmt.Sprintf("demo-fingerprint-%02d", index),
|
|
CreatePayload: "{}", Extra: "{}", Version: 1, CreatedAt: created, UpdatedAt: created,
|
|
}
|
|
}
|
|
makeEvent := func(order paymentOrderPO, eventType, source, status, providerStatus, message string, amount int64, at time.Time) paymentEventPO {
|
|
event := paymentEventPO{
|
|
Provider: order.Provider, TradeNo: order.TradeNo, Type: eventType, Source: source, Status: status,
|
|
ProviderStatus: providerStatus, Message: message, Amount: amount, Currency: order.Currency, CreatedAt: at,
|
|
}
|
|
if source == "client" {
|
|
event.ClientIP, event.UserAgent, event.DeviceID = "111.29.161.79", "Kra-Demo/1.2 Android/16", fmt.Sprintf("DEMO-DEVICE-%s", order.TradeNo)
|
|
}
|
|
if source == "admin" {
|
|
event.OperatorID, event.OperatorName = 1, "demo-admin"
|
|
}
|
|
return event
|
|
}
|
|
providerDate := now.Format("20060102")
|
|
|
|
created1, paid1, fulfilled1 := now.Add(-35*time.Minute), now.Add(-34*time.Minute), now.Add(-33*time.Minute)
|
|
paid := makeOrder(1, bizpayment.PaymentAlipay, "专业版 7 天授权", bizpayment.PaymentStatusPaid, bizpayment.FulfillmentStatusSucceeded, bizpayment.RefundStatusNone, 940, "CNY", created1)
|
|
providerTrade1 := fmt.Sprintf("DEMO-ALIPAY-%s%04d", providerDate, 1)
|
|
paid.ProviderTradeNo = &providerTrade1
|
|
paid.ProviderStatus, paid.PaidAmount, paid.PayerPaidAmount, paid.CashPaidAmount, paid.SettlementAmount = "TRADE_SUCCESS", 940, 940, 940, 934
|
|
paid.AmountBreakdownKnown, paid.PaidAt, paid.FulfilledAt, paid.UpdatedAt = true, &paid1, &fulfilled1, fulfilled1
|
|
|
|
pendingCreated := now.Add(-28 * time.Minute)
|
|
pending := makeOrder(2, bizpayment.PaymentWechatV3, "专业版 30 天授权", bizpayment.PaymentStatusPending, bizpayment.FulfillmentStatusPending, bizpayment.RefundStatusNone, 2990, "CNY", pendingCreated)
|
|
pending.ProviderStatus = "NOTPAY"
|
|
pending.UpdatedAt = now.Add(-27 * time.Minute)
|
|
|
|
failedCreated := now.Add(-24 * time.Minute)
|
|
failed := makeOrder(3, bizpayment.PaymentPayPal, "海外数字商品", bizpayment.PaymentStatusFailed, bizpayment.FulfillmentStatusPending, bizpayment.RefundStatusNone, 1299, "USD", failedCreated)
|
|
failed.ProviderStatus, failed.LastError = "DECLINED", "付款方式被渠道拒绝"
|
|
failed.UpdatedAt = now.Add(-23 * time.Minute)
|
|
|
|
fulfillCreated, fulfillPaid := now.Add(-20*time.Minute), now.Add(-19*time.Minute)
|
|
fulfillFailed := makeOrder(4, bizpayment.PaymentAlipayV3, "企业版 90 天授权", bizpayment.PaymentStatusPaid, bizpayment.FulfillmentStatusFailed, bizpayment.RefundStatusNone, 8990, "CNY", fulfillCreated)
|
|
providerTrade4 := fmt.Sprintf("DEMO-ALIPAY-%s%04d", providerDate, 4)
|
|
fulfillFailed.ProviderTradeNo, fulfillFailed.ProviderStatus = &providerTrade4, "TRADE_SUCCESS"
|
|
fulfillFailed.PaidAmount, fulfillFailed.SettlementAmount, fulfillFailed.PaidAt = 8990, 8936, &fulfillPaid
|
|
fulfillFailed.LastError, fulfillFailed.UpdatedAt = "业务授权服务暂时不可用,可人工重试发货", now.Add(-18*time.Minute)
|
|
|
|
partialCreated, partialPaid, partialRefunded := now.Add(-16*time.Minute), now.Add(-15*time.Minute), now.Add(-12*time.Minute)
|
|
partial := makeOrder(5, bizpayment.PaymentWechatV3, "团队版 30 天授权", bizpayment.PaymentStatusPartiallyRefunded, bizpayment.FulfillmentStatusSucceeded, bizpayment.RefundStatusPartial, 5000, "CNY", partialCreated)
|
|
providerTrade5 := fmt.Sprintf("DEMO-WECHAT-%s%04d", providerDate, 5)
|
|
partial.ProviderTradeNo, partial.ProviderStatus = &providerTrade5, "SUCCESS"
|
|
partial.PaidAmount, partial.SettlementAmount, partial.RefundedAmount = 5000, 4970, 1200
|
|
partial.PaidAt, partial.FulfilledAt, partial.RefundedAt, partial.UpdatedAt = &partialPaid, &partialPaid, &partialRefunded, partialRefunded
|
|
|
|
refundCreated, refundPaid := now.Add(-11*time.Minute), now.Add(-10*time.Minute)
|
|
refundPending := makeOrder(6, bizpayment.PaymentAlipay, "增值服务包", bizpayment.PaymentStatusPaid, bizpayment.FulfillmentStatusSucceeded, bizpayment.RefundStatusPending, 1880, "CNY", refundCreated)
|
|
providerTrade6 := fmt.Sprintf("DEMO-ALIPAY-%s%04d", providerDate, 6)
|
|
refundPending.ProviderTradeNo, refundPending.ProviderStatus = &providerTrade6, "TRADE_SUCCESS"
|
|
refundPending.PaidAmount, refundPending.SettlementAmount, refundPending.RefundRequestedAmount = 1880, 1869, 600
|
|
refundPending.RefundNo, refundPending.PaidAt, refundPending.FulfilledAt, refundPending.UpdatedAt = "DEMO-REFUND-06", &refundPaid, &refundPaid, now.Add(-8*time.Minute)
|
|
|
|
refundedCreated, refundedPaid, refundedAt := now.Add(-9*time.Minute), now.Add(-8*time.Minute), now.Add(-5*time.Minute)
|
|
refunded := makeOrder(7, bizpayment.PaymentWechatV3, "体验卡 7 天", bizpayment.PaymentStatusRefunded, bizpayment.FulfillmentStatusSucceeded, bizpayment.RefundStatusSucceeded, 500, "CNY", refundedCreated)
|
|
providerTrade7 := fmt.Sprintf("DEMO-WECHAT-%s%04d", providerDate, 7)
|
|
refunded.ProviderTradeNo, refunded.ProviderStatus = &providerTrade7, "REFUND_SUCCESS"
|
|
refunded.PaidAmount, refunded.SettlementAmount, refunded.RefundedAmount = 500, 497, 500
|
|
refunded.PaidAt, refunded.FulfilledAt, refunded.RefundedAt, refunded.UpdatedAt = &refundedPaid, &refundedPaid, &refundedAt, refundedAt
|
|
|
|
internalCreated, internalPaid := now.Add(-4*time.Minute), now.Add(-3*time.Minute)
|
|
internal := makeOrder(8, bizpayment.PaymentInternal, "积分兑换月卡", bizpayment.PaymentStatusPaid, bizpayment.FulfillmentStatusSucceeded, bizpayment.RefundStatusNone, 1200, "POINT", internalCreated)
|
|
internal.PaymentMode, internal.ProviderStatus = bizpayment.PaymentModeInternal, "AUTHORIZED"
|
|
internal.PaidAmount, internal.PointPaidAmount, internal.SettlementAmount, internal.AmountBreakdownKnown = 1200, 1200, 1200, true
|
|
internal.PaidAt, internal.FulfilledAt, internal.UpdatedAt = &internalPaid, &internalPaid, internalPaid
|
|
|
|
demos := []demoOrder{
|
|
{paid, []paymentEventPO{makeEvent(paid, bizpayment.PaymentEventOrderCreated, "client", bizpayment.PaymentStatusInitialized, "", "客户端创建订单", paid.Amount, created1), makeEvent(paid, bizpayment.PaymentEventPaymentCallback, bizpayment.PaymentAlipay, bizpayment.PaymentStatusPaid, paid.ProviderStatus, "支付宝异步通知验签并主动查单成功", paid.PaidAmount, paid1), makeEvent(paid, bizpayment.PaymentEventFulfillmentFinished, "system", bizpayment.FulfillmentStatusSucceeded, "", "授权自动激活成功,有效期 7 天", 0, fulfilled1)}},
|
|
{pending, []paymentEventPO{makeEvent(pending, bizpayment.PaymentEventOrderCreated, "client", bizpayment.PaymentStatusInitialized, "", "客户端创建订单", pending.Amount, pendingCreated), makeEvent(pending, bizpayment.PaymentEventProviderCreated, bizpayment.PaymentWechatV3, bizpayment.PaymentStatusPending, pending.ProviderStatus, "预支付订单已创建,等待买家付款", pending.Amount, pending.UpdatedAt)}},
|
|
{failed, []paymentEventPO{makeEvent(failed, bizpayment.PaymentEventOrderCreated, "client", bizpayment.PaymentStatusInitialized, "", "客户端创建订单", failed.Amount, failedCreated), makeEvent(failed, bizpayment.PaymentEventPaymentSynchronized, "admin", bizpayment.PaymentStatusFailed, failed.ProviderStatus, failed.LastError, 0, failed.UpdatedAt)}},
|
|
{fulfillFailed, []paymentEventPO{makeEvent(fulfillFailed, bizpayment.PaymentEventPaymentCallback, bizpayment.PaymentAlipayV3, bizpayment.PaymentStatusPaid, fulfillFailed.ProviderStatus, "支付成功", fulfillFailed.PaidAmount, fulfillPaid), makeEvent(fulfillFailed, bizpayment.PaymentEventFulfillmentFinished, "system", bizpayment.FulfillmentStatusFailed, "", fulfillFailed.LastError, 0, fulfillFailed.UpdatedAt)}},
|
|
{partial, []paymentEventPO{makeEvent(partial, bizpayment.PaymentEventPaymentCallback, bizpayment.PaymentWechatV3, bizpayment.PaymentStatusPaid, partial.ProviderStatus, "支付成功并完成发货", partial.PaidAmount, partialPaid), makeEvent(partial, bizpayment.PaymentEventRefundConfirmed, bizpayment.PaymentWechatV3, bizpayment.RefundStatusPartial, "SUCCESS", "售后部分退款 12.00 CNY", partial.RefundedAmount, partialRefunded)}},
|
|
{refundPending, []paymentEventPO{makeEvent(refundPending, bizpayment.PaymentEventPaymentCallback, bizpayment.PaymentAlipay, bizpayment.PaymentStatusPaid, refundPending.ProviderStatus, "支付成功并完成发货", refundPending.PaidAmount, refundPaid), makeEvent(refundPending, bizpayment.PaymentEventRefundSubmitted, "admin", bizpayment.RefundStatusPending, "", "客户重复购买,退款已提交渠道", refundPending.RefundRequestedAmount, refundPending.UpdatedAt)}},
|
|
{refunded, []paymentEventPO{makeEvent(refunded, bizpayment.PaymentEventPaymentCallback, bizpayment.PaymentWechatV3, bizpayment.PaymentStatusPaid, "SUCCESS", "支付成功并完成发货", refunded.PaidAmount, refundedPaid), makeEvent(refunded, bizpayment.PaymentEventRefundConfirmed, bizpayment.PaymentWechatV3, bizpayment.RefundStatusSucceeded, refunded.ProviderStatus, "原路全额退款成功", refunded.RefundedAmount, refundedAt)}},
|
|
{internal, []paymentEventPO{makeEvent(internal, bizpayment.PaymentEventOrderCreated, "client", bizpayment.PaymentStatusInitialized, "", "创建积分支付订单", internal.Amount, internalCreated), makeEvent(internal, bizpayment.PaymentEventPaymentSynchronized, bizpayment.PaymentInternal, bizpayment.PaymentStatusPaid, internal.ProviderStatus, "积分扣减与授权发放成功", internal.PaidAmount, internalPaid)}},
|
|
}
|
|
|
|
result := &DemoSeedResult{}
|
|
err := db.Transaction(func(tx *gorm.DB) error {
|
|
if err := tx.Where("trade_no LIKE ?", DemoTradePrefix+"%").Delete(&paymentEventPO{}).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := tx.Where("trade_no LIKE ?", DemoTradePrefix+"%").Delete(&paymentOrderPO{}).Error; err != nil {
|
|
return err
|
|
}
|
|
for i := range demos {
|
|
if err := tx.Create(&demos[i].order).Error; err != nil {
|
|
return err
|
|
}
|
|
result.Orders++
|
|
if len(demos[i].events) > 0 {
|
|
if err := tx.Create(&demos[i].events).Error; err != nil {
|
|
return err
|
|
}
|
|
result.Events += len(demos[i].events)
|
|
}
|
|
}
|
|
return nil
|
|
})
|
|
return result, err
|
|
}
|