优化结构
This commit is contained in:
@@ -72,6 +72,8 @@ type PaymentRequest struct {
|
||||
BusinessID string `json:"businessId"`
|
||||
PaymentMode string `json:"paymentMode"`
|
||||
OriginalAmount int64 `json:"originalAmount"`
|
||||
UserAgent string `json:"-"`
|
||||
DeviceID string `json:"-"`
|
||||
}
|
||||
|
||||
// PaymentRefundRequest carries the durable provider identities needed to
|
||||
@@ -415,6 +417,23 @@ func (uc *PaymentUsecase) Orders(ctx context.Context, page, pageSize int, filter
|
||||
return uc.orders.ListPaymentOrders(ctx, page, pageSize, filter)
|
||||
}
|
||||
|
||||
func (uc *PaymentUsecase) OrderSummary(ctx context.Context, filter PaymentOrderFilter) (*PaymentOrderSummary, error) {
|
||||
if uc.orders == nil {
|
||||
return nil, errors.New("支付订单仓储未接入")
|
||||
}
|
||||
return uc.orders.SummarizePaymentOrders(ctx, filter)
|
||||
}
|
||||
|
||||
func (uc *PaymentUsecase) OrderEvents(ctx context.Context, provider, tradeNo string, limit int) ([]*PaymentEvent, error) {
|
||||
if uc.orders == nil {
|
||||
return nil, errors.New("支付订单仓储未接入")
|
||||
}
|
||||
if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) {
|
||||
return nil, errors.New("支付订单事件查询参数不完整")
|
||||
}
|
||||
return uc.orders.ListPaymentEvents(ctx, provider, tradeNo, limit)
|
||||
}
|
||||
|
||||
func (uc *PaymentUsecase) Create(ctx context.Context, req *PaymentRequest) (*PaymentResult, error) {
|
||||
if req == nil || !validPaymentText(req.Provider, 64) || !validPaymentText(req.TradeNo, 128) || !validPaymentText(req.BusinessType, 64) || !validPaymentText(req.BusinessID, 128) {
|
||||
return nil, errors.New("支付参数不完整")
|
||||
@@ -644,6 +663,9 @@ func (uc *PaymentUsecase) createWithOrder(ctx context.Context, req *PaymentReque
|
||||
ConfirmationID: paymentConfirmationID(req.Provider, req.TradeNo),
|
||||
RequestFingerprint: paymentOrderFingerprint(req, extra),
|
||||
Extra: extra,
|
||||
ClientIP: req.ClientIP,
|
||||
UserAgent: req.UserAgent,
|
||||
DeviceID: req.DeviceID,
|
||||
}
|
||||
order, created, err := uc.orders.CreatePaymentOrder(ctx, order)
|
||||
if err != nil {
|
||||
@@ -691,7 +713,9 @@ func (uc *PaymentUsecase) createWithOrder(ctx context.Context, req *PaymentReque
|
||||
if err = validatePaymentBreakdown(result); err != nil {
|
||||
return nil, fmt.Errorf("内部支付金额拆分无效: %w", err)
|
||||
}
|
||||
if _, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, paymentProviderUpdate(result)); err != nil {
|
||||
update := paymentProviderUpdate(result)
|
||||
update.EventSource = PaymentInternal
|
||||
if _, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, update); err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return uc.reconcilePaymentResult(ctx, result, nil)
|
||||
@@ -707,7 +731,9 @@ func (uc *PaymentUsecase) createWithOrder(ctx context.Context, req *PaymentReque
|
||||
uc.logger.Error(ctx, "payment.order.provider_create_invalid", "provider", req.Provider, "trade_no", req.TradeNo, "error", err)
|
||||
return nil, err
|
||||
}
|
||||
order, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, paymentProviderUpdate(result))
|
||||
update := paymentProviderUpdate(result)
|
||||
update.EventSource = req.Provider
|
||||
order, err = uc.orders.RecordPaymentCreate(ctx, req.Provider, req.TradeNo, update)
|
||||
if err != nil {
|
||||
uc.logger.Error(ctx, "payment.order.provider_create_record_failed", "provider", req.Provider, "trade_no", req.TradeNo, "error", err)
|
||||
return nil, err
|
||||
@@ -773,7 +799,17 @@ func (uc *PaymentUsecase) reconcilePaymentResult(ctx context.Context, result, ca
|
||||
return fail(err)
|
||||
}
|
||||
}
|
||||
order, err = uc.orders.ApplyPaymentResult(ctx, result.Provider, result.TradeNo, paymentProviderUpdate(result))
|
||||
update := paymentProviderUpdate(result)
|
||||
operation := PaymentOperationFromContext(ctx)
|
||||
update.EventSource = operation.Source
|
||||
update.EventType = PaymentEventPaymentSynchronized
|
||||
if callbackSource != nil {
|
||||
update.EventType = PaymentEventPaymentCallback
|
||||
if update.EventSource == "" {
|
||||
update.EventSource = result.Provider
|
||||
}
|
||||
}
|
||||
order, err = uc.orders.ApplyPaymentResult(ctx, result.Provider, result.TradeNo, update)
|
||||
if err != nil {
|
||||
uc.logger.Error(ctx, "payment.order.result_record_failed", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
|
||||
return fail(err)
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
package payment
|
||||
|
||||
import (
|
||||
"context"
|
||||
"strings"
|
||||
"time"
|
||||
)
|
||||
|
||||
const (
|
||||
PaymentEventOrderCreated = "order_created"
|
||||
PaymentEventProviderCreated = "provider_created"
|
||||
PaymentEventPaymentSynchronized = "payment_synchronized"
|
||||
PaymentEventPaymentCallback = "payment_callback"
|
||||
PaymentEventFulfillmentStarted = "fulfillment_started"
|
||||
PaymentEventFulfillmentFinished = "fulfillment_finished"
|
||||
PaymentEventRefundStarted = "refund_started"
|
||||
PaymentEventRefundSubmitted = "refund_submitted"
|
||||
PaymentEventRefundConfirmed = "refund_confirmed"
|
||||
)
|
||||
|
||||
// PaymentOperation describes who or what initiated a payment state change.
|
||||
// It is carried in context so repo method signatures remain focused on domain
|
||||
// state while event persistence can still retain transport-level attribution.
|
||||
type PaymentOperation struct {
|
||||
Source string
|
||||
Reason string
|
||||
OperatorID uint
|
||||
OperatorName string
|
||||
ClientIP string
|
||||
UserAgent string
|
||||
DeviceID string
|
||||
}
|
||||
|
||||
type paymentOperationContextKey struct{}
|
||||
|
||||
func WithPaymentOperation(ctx context.Context, operation PaymentOperation) context.Context {
|
||||
if ctx == nil {
|
||||
ctx = context.Background()
|
||||
}
|
||||
return context.WithValue(ctx, paymentOperationContextKey{}, operation)
|
||||
}
|
||||
|
||||
func PaymentOperationFromContext(ctx context.Context) PaymentOperation {
|
||||
if ctx == nil {
|
||||
return PaymentOperation{}
|
||||
}
|
||||
operation, _ := ctx.Value(paymentOperationContextKey{}).(PaymentOperation)
|
||||
operation.Source = strings.TrimSpace(operation.Source)
|
||||
operation.Reason = strings.TrimSpace(operation.Reason)
|
||||
operation.OperatorName = strings.TrimSpace(operation.OperatorName)
|
||||
operation.ClientIP = strings.TrimSpace(operation.ClientIP)
|
||||
operation.UserAgent = strings.TrimSpace(operation.UserAgent)
|
||||
operation.DeviceID = strings.TrimSpace(operation.DeviceID)
|
||||
return operation
|
||||
}
|
||||
|
||||
type PaymentEvent struct {
|
||||
ID uint64
|
||||
Provider string
|
||||
TradeNo string
|
||||
Type string
|
||||
Source string
|
||||
Status string
|
||||
ProviderStatus string
|
||||
Message string
|
||||
EventID string
|
||||
PayloadHash string
|
||||
Amount int64
|
||||
Currency string
|
||||
OperatorID uint
|
||||
OperatorName string
|
||||
ClientIP string
|
||||
UserAgent string
|
||||
DeviceID string
|
||||
CreatedAt time.Time
|
||||
}
|
||||
|
||||
type PaymentCurrencySummary struct {
|
||||
Currency string
|
||||
OrderAmount int64
|
||||
PaidAmount int64
|
||||
RefundedAmount int64
|
||||
SettlementAmount int64
|
||||
NetAmount int64
|
||||
}
|
||||
|
||||
type PaymentOrderSummary struct {
|
||||
OrderCount int64
|
||||
PendingCount int64
|
||||
PaidCount int64
|
||||
RefundedCount int64
|
||||
IssueCount int64
|
||||
Currencies []PaymentCurrencySummary
|
||||
}
|
||||
@@ -88,6 +88,9 @@ type PaymentOrder struct {
|
||||
RefundedAt *time.Time
|
||||
FulfillmentLeaseUntil *time.Time
|
||||
RefundLeaseUntil *time.Time
|
||||
ClientIP string
|
||||
UserAgent string
|
||||
DeviceID string
|
||||
}
|
||||
|
||||
type PaymentProviderUpdate struct {
|
||||
@@ -109,21 +112,33 @@ type PaymentProviderUpdate struct {
|
||||
EventID string
|
||||
PayloadHash string
|
||||
CreatePayload json.RawMessage
|
||||
EventType string
|
||||
EventSource string
|
||||
EventMessage string
|
||||
}
|
||||
|
||||
type PaymentOrderFilter struct {
|
||||
Provider string
|
||||
TradeNo string
|
||||
BusinessType string
|
||||
BusinessID string
|
||||
PaymentStatus string
|
||||
RefundStatus string
|
||||
Provider string
|
||||
TradeNo string
|
||||
ProviderTradeNo string
|
||||
Keyword string
|
||||
BusinessType string
|
||||
BusinessID string
|
||||
PaymentStatus string
|
||||
RefundStatus string
|
||||
CreatedFrom *time.Time
|
||||
CreatedTo *time.Time
|
||||
PaidFrom *time.Time
|
||||
PaidTo *time.Time
|
||||
IssueOnly bool
|
||||
}
|
||||
|
||||
type PaymentOrderRepo interface {
|
||||
CreatePaymentOrder(context.Context, *PaymentOrder) (order *PaymentOrder, created bool, err error)
|
||||
FindPaymentOrder(context.Context, string, string) (*PaymentOrder, error)
|
||||
ListPaymentOrders(context.Context, int, int, PaymentOrderFilter) ([]*PaymentOrder, int64, error)
|
||||
SummarizePaymentOrders(context.Context, PaymentOrderFilter) (*PaymentOrderSummary, error)
|
||||
ListPaymentEvents(context.Context, string, string, int) ([]*PaymentEvent, error)
|
||||
RecordPaymentCreate(context.Context, string, string, *PaymentProviderUpdate) (*PaymentOrder, error)
|
||||
ApplyPaymentResult(context.Context, string, string, *PaymentProviderUpdate) (*PaymentOrder, error)
|
||||
BeginPaymentFulfillment(context.Context, string, string, time.Duration) (order *PaymentOrder, token string, duplicate bool, err error)
|
||||
|
||||
@@ -52,6 +52,16 @@ func (r *paymentOrderRepoStub) ListPaymentOrders(context.Context, int, int, Paym
|
||||
}
|
||||
return []*PaymentOrder{r.order}, 1, nil
|
||||
}
|
||||
func (r *paymentOrderRepoStub) SummarizePaymentOrders(context.Context, PaymentOrderFilter) (*PaymentOrderSummary, error) {
|
||||
count := int64(0)
|
||||
if r.order != nil {
|
||||
count = 1
|
||||
}
|
||||
return &PaymentOrderSummary{OrderCount: count}, nil
|
||||
}
|
||||
func (r *paymentOrderRepoStub) ListPaymentEvents(context.Context, string, string, int) ([]*PaymentEvent, error) {
|
||||
return []*PaymentEvent{}, nil
|
||||
}
|
||||
func (r *paymentOrderRepoStub) RecordPaymentCreate(_ context.Context, _, _ string, update *PaymentProviderUpdate) (*PaymentOrder, error) {
|
||||
r.order.PaymentStatus = PaymentStatusPending
|
||||
r.order.CreatePayload = append(r.order.CreatePayload[:0], update.CreatePayload...)
|
||||
|
||||
Reference in New Issue
Block a user