优化结构

This commit is contained in:
Yvan
2026-08-29 02:58:00 +08:00
parent 3d108ebdfe
commit b6d25c1a0f
24 changed files with 1657 additions and 224 deletions
+146 -28
View File
@@ -146,7 +146,17 @@ func (r *paymentOrderRepo) CreatePaymentOrder(ctx context.Context, order *bizpay
if !errors.Is(err, gorm.ErrRecordNotFound) {
return nil, false, err
}
if err = db.Create(po).Error; err == nil {
err = db.Transaction(func(tx *gorm.DB) error {
if createErr := tx.Create(po).Error; createErr != nil {
return createErr
}
return appendPaymentEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventOrderCreated, Source: "client", Status: po.PaymentStatus,
Amount: po.Amount, Currency: po.Currency, ClientIP: order.ClientIP,
UserAgent: order.UserAgent, DeviceID: order.DeviceID,
})
})
if err == nil {
return toBizPaymentOrder(po), true, nil
}
if lookupErr := db.Where("provider = ? AND trade_no = ?", po.Provider, po.TradeNo).First(&current).Error; lookupErr == nil {
@@ -167,25 +177,7 @@ func (r *paymentOrderRepo) FindPaymentOrder(ctx context.Context, provider, trade
}
func (r *paymentOrderRepo) ListPaymentOrders(ctx context.Context, page, pageSize int, filter bizpayment.PaymentOrderFilter) ([]*bizpayment.PaymentOrder, int64, error) {
db := r.data.DB().WithContext(ctx).Model(&paymentOrderPO{})
if value := strings.TrimSpace(filter.Provider); value != "" {
db = db.Where("provider = ?", value)
}
if value := strings.TrimSpace(filter.TradeNo); value != "" {
db = db.Where("trade_no LIKE ?", "%"+value+"%")
}
if value := strings.TrimSpace(filter.BusinessType); value != "" {
db = db.Where("business_type = ?", value)
}
if value := strings.TrimSpace(filter.BusinessID); value != "" {
db = db.Where("business_id LIKE ?", "%"+value+"%")
}
if value := strings.TrimSpace(filter.PaymentStatus); value != "" {
db = db.Where("payment_status = ?", value)
}
if value := strings.TrimSpace(filter.RefundStatus); value != "" {
db = db.Where("refund_status = ?", value)
}
db := r.filteredPaymentOrders(ctx, filter)
var total int64
if err := db.Count(&total).Error; err != nil {
return nil, 0, err
@@ -201,6 +193,105 @@ func (r *paymentOrderRepo) ListPaymentOrders(ctx context.Context, page, pageSize
return items, total, nil
}
func (r *paymentOrderRepo) filteredPaymentOrders(ctx context.Context, filter bizpayment.PaymentOrderFilter) *gorm.DB {
db := r.data.DB().WithContext(ctx).Model(&paymentOrderPO{})
if value := strings.TrimSpace(filter.Provider); value != "" {
db = db.Where("provider = ?", value)
}
if value := strings.TrimSpace(filter.TradeNo); value != "" {
db = db.Where("trade_no LIKE ?", "%"+value+"%")
}
if value := strings.TrimSpace(filter.ProviderTradeNo); value != "" {
db = db.Where("provider_trade_no LIKE ?", "%"+value+"%")
}
if value := strings.TrimSpace(filter.Keyword); value != "" {
like := "%" + value + "%"
db = db.Where("trade_no LIKE ? OR provider_trade_no LIKE ? OR business_id LIKE ? OR subject LIKE ?", like, like, like, like)
}
if value := strings.TrimSpace(filter.BusinessType); value != "" {
db = db.Where("business_type = ?", value)
}
if value := strings.TrimSpace(filter.BusinessID); value != "" {
db = db.Where("business_id LIKE ?", "%"+value+"%")
}
if value := strings.TrimSpace(filter.PaymentStatus); value != "" {
db = db.Where("payment_status = ?", value)
}
if value := strings.TrimSpace(filter.RefundStatus); value != "" {
db = db.Where("refund_status = ?", value)
}
if filter.CreatedFrom != nil {
db = db.Where("created_at >= ?", filter.CreatedFrom.UTC())
}
if filter.CreatedTo != nil {
db = db.Where("created_at < ?", filter.CreatedTo.UTC())
}
if filter.PaidFrom != nil {
db = db.Where("paid_at >= ?", filter.PaidFrom.UTC())
}
if filter.PaidTo != nil {
db = db.Where("paid_at < ?", filter.PaidTo.UTC())
}
if filter.IssueOnly {
db = db.Where("payment_status = ? OR fulfillment_status = ? OR refund_status = ? OR last_error <> ''",
bizpayment.PaymentStatusFailed, bizpayment.FulfillmentStatusFailed, bizpayment.RefundStatusFailed)
}
return db
}
func (r *paymentOrderRepo) SummarizePaymentOrders(ctx context.Context, filter bizpayment.PaymentOrderFilter) (*bizpayment.PaymentOrderSummary, error) {
type countRow struct {
OrderCount int64
PendingCount int64
PaidCount int64
RefundedCount int64
IssueCount int64
}
var counts countRow
if err := r.filteredPaymentOrders(ctx, filter).Select(`
COUNT(*) AS order_count,
COALESCE(SUM(CASE WHEN payment_status IN ? THEN 1 ELSE 0 END), 0) AS pending_count,
COALESCE(SUM(CASE WHEN payment_status IN ? THEN 1 ELSE 0 END), 0) AS paid_count,
COALESCE(SUM(CASE WHEN refunded_amount > 0 THEN 1 ELSE 0 END), 0) AS refunded_count,
COALESCE(SUM(CASE WHEN payment_status = ? OR fulfillment_status = ? OR refund_status = ? OR last_error <> '' THEN 1 ELSE 0 END), 0) AS issue_count`,
[]string{bizpayment.PaymentStatusInitialized, bizpayment.PaymentStatusPending},
[]string{bizpayment.PaymentStatusPaid, bizpayment.PaymentStatusPartiallyRefunded, bizpayment.PaymentStatusRefunded},
bizpayment.PaymentStatusFailed, bizpayment.FulfillmentStatusFailed, bizpayment.RefundStatusFailed,
).Scan(&counts).Error; err != nil {
return nil, err
}
type currencyRow struct {
Currency string
OrderAmount int64
PaidAmount int64
RefundedAmount int64
SettlementAmount int64
}
var rows []currencyRow
if err := r.filteredPaymentOrders(ctx, filter).
Select(`currency,
COALESCE(SUM(amount), 0) AS order_amount,
COALESCE(SUM(paid_amount), 0) AS paid_amount,
COALESCE(SUM(refunded_amount), 0) AS refunded_amount,
COALESCE(SUM(CASE WHEN settlement_amount > 0 THEN settlement_amount ELSE paid_amount END), 0) AS settlement_amount`).
Group("currency").Order("currency ASC").Scan(&rows).Error; err != nil {
return nil, err
}
summary := &bizpayment.PaymentOrderSummary{
OrderCount: counts.OrderCount, PendingCount: counts.PendingCount, PaidCount: counts.PaidCount,
RefundedCount: counts.RefundedCount, IssueCount: counts.IssueCount,
Currencies: make([]bizpayment.PaymentCurrencySummary, 0, len(rows)),
}
for _, row := range rows {
summary.Currencies = append(summary.Currencies, bizpayment.PaymentCurrencySummary{
Currency: row.Currency, OrderAmount: row.OrderAmount, PaidAmount: row.PaidAmount,
RefundedAmount: row.RefundedAmount, SettlementAmount: row.SettlementAmount,
NetAmount: row.SettlementAmount - row.RefundedAmount,
})
}
return summary, nil
}
func (r *paymentOrderRepo) RecordPaymentCreate(ctx context.Context, provider, tradeNo string, update *bizpayment.PaymentProviderUpdate) (*bizpayment.PaymentOrder, error) {
return r.withLockedOrder(ctx, provider, tradeNo, func(tx *gorm.DB, po *paymentOrderPO) error {
if update == nil {
@@ -224,7 +315,11 @@ func (r *paymentOrderRepo) RecordPaymentCreate(ctx context.Context, provider, tr
po.PaymentStatus = status
}
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventProviderCreated, Source: update.EventSource, Status: po.PaymentStatus,
ProviderStatus: po.ProviderStatus, Message: update.EventMessage, EventID: update.EventID,
PayloadHash: update.PayloadHash, Amount: po.Amount, Currency: po.Currency,
})
})
}
@@ -279,7 +374,15 @@ func (r *paymentOrderRepo) ApplyPaymentResult(ctx context.Context, provider, tra
}
}
po.Version++
return tx.Save(po).Error
eventType := update.EventType
if eventType == "" {
eventType = bizpayment.PaymentEventPaymentSynchronized
}
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: eventType, Source: update.EventSource, Status: po.PaymentStatus,
ProviderStatus: po.ProviderStatus, Message: update.EventMessage, EventID: update.EventID,
PayloadHash: update.PayloadHash, Amount: po.PaidAmount, Currency: po.Currency,
})
})
}
@@ -308,7 +411,9 @@ func (r *paymentOrderRepo) BeginPaymentFulfillment(ctx context.Context, provider
po.FulfillmentLeaseUntil = &until
po.LastError = ""
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventFulfillmentStarted, Status: po.FulfillmentStatus,
})
})
return order, token, duplicate, err
}
@@ -329,7 +434,9 @@ func (r *paymentOrderRepo) CompletePaymentFulfillment(ctx context.Context, provi
po.FulfillmentStatus = bizpayment.FulfillmentStatusFailed
}
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventFulfillmentFinished, Status: po.FulfillmentStatus, Message: message,
})
})
}
@@ -378,7 +485,9 @@ func (r *paymentOrderRepo) BeginPaymentRefund(ctx context.Context, provider, tra
po.RefundLeaseUntil = &until
po.LastError = ""
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventRefundStarted, Status: po.RefundStatus, Amount: amount, Currency: po.Currency,
})
})
return order, token, err
}
@@ -399,7 +508,10 @@ func (r *paymentOrderRepo) CompletePaymentRefundRequest(ctx context.Context, pro
po.RefundNo = ""
}
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventRefundSubmitted, Status: po.RefundStatus, Message: message,
Amount: po.RefundRequestedAmount, Currency: po.Currency,
})
})
}
@@ -414,7 +526,10 @@ func (r *paymentOrderRepo) ConfirmPaymentRefund(ctx context.Context, provider, t
po.RefundStatus = bizpayment.RefundStatusFailed
po.RefundNo = ""
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventRefundConfirmed, Status: po.RefundStatus, Message: message,
Amount: amount, Currency: po.Currency,
})
}
po.RefundedAmount += amount
if po.RefundedAmount >= po.Amount {
@@ -428,7 +543,10 @@ func (r *paymentOrderRepo) ConfirmPaymentRefund(ctx context.Context, provider, t
now := time.Now().UTC()
po.RefundedAt = &now
po.Version++
return tx.Save(po).Error
return savePaymentOrderWithEvent(ctx, tx, po, &bizpayment.PaymentEvent{
Type: bizpayment.PaymentEventRefundConfirmed, Status: po.RefundStatus, Message: message,
Amount: amount, Currency: po.Currency,
})
})
}