优化结构
This commit is contained in:
@@ -493,6 +493,30 @@ func (uc *PaymentUsecase) Refund(ctx context.Context, provider, tradeNo string,
|
||||
return uc.refundWithOrder(ctx, provider, tradeNo, amount)
|
||||
}
|
||||
|
||||
// Fulfill retries delivery for an already-paid order. It is intentionally
|
||||
// idempotent: the repository lease prevents concurrent attempts and a
|
||||
// succeeded order is returned as a duplicate without invoking the handler.
|
||||
func (uc *PaymentUsecase) Fulfill(ctx context.Context, provider, tradeNo string) (*PaymentResult, error) {
|
||||
if !validPaymentText(provider, 64) || !validPaymentText(tradeNo, 128) {
|
||||
return nil, errors.New("发货参数不完整")
|
||||
}
|
||||
if uc.orders == nil {
|
||||
return nil, errors.New("支付订单仓储未接入")
|
||||
}
|
||||
order, err := uc.orders.FindPaymentOrder(ctx, provider, tradeNo)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result := paymentResultFromOrder(order)
|
||||
if result == nil {
|
||||
return nil, ErrPaymentOrderNotFound
|
||||
}
|
||||
if order.PaymentStatus != PaymentStatusPaid {
|
||||
return nil, ErrPaymentOrderState
|
||||
}
|
||||
return uc.fulfillOrder(ctx, order, result)
|
||||
}
|
||||
|
||||
// Callback verifies the notification in the adapter, then always performs a
|
||||
// provider-side query before it can dispatch fulfillment. Callback payloads
|
||||
// are never trusted for amount, currency, or final payment state.
|
||||
@@ -671,10 +695,21 @@ func (uc *PaymentUsecase) reconcilePaymentResult(ctx context.Context, result, ca
|
||||
return result, nil
|
||||
}
|
||||
|
||||
fulfilled, err := uc.fulfillOrder(ctx, order, result)
|
||||
if err != nil {
|
||||
return fail(err)
|
||||
}
|
||||
return fulfilled, nil
|
||||
}
|
||||
|
||||
func (uc *PaymentUsecase) fulfillOrder(ctx context.Context, order *PaymentOrder, result *PaymentResult) (*PaymentResult, error) {
|
||||
if order == nil || result == nil {
|
||||
return nil, errors.New("支付发货订单为空")
|
||||
}
|
||||
order, token, duplicate, err := uc.orders.BeginPaymentFulfillment(ctx, result.Provider, result.TradeNo, 10*time.Minute)
|
||||
if err != nil {
|
||||
uc.logger.Error(ctx, "payment.order.fulfillment_begin_failed", "provider", result.Provider, "trade_no", result.TradeNo, "error", err)
|
||||
return fail(err)
|
||||
return nil, err
|
||||
}
|
||||
if duplicate {
|
||||
result.Duplicate = true
|
||||
@@ -685,29 +720,23 @@ func (uc *PaymentUsecase) reconcilePaymentResult(ctx context.Context, result, ca
|
||||
if handler == nil {
|
||||
err = fmt.Errorf("支付发货 handler 未注册: %s", order.BusinessType)
|
||||
_, _ = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, false, err.Error())
|
||||
uc.logger.Error(ctx, "payment.order.fulfillment_handler_missing", "provider", result.Provider, "trade_no", result.TradeNo, "business_type", order.BusinessType, "error", err)
|
||||
return fail(err)
|
||||
return nil, err
|
||||
}
|
||||
confirmation := &PaymentConfirmation{
|
||||
ID: order.ConfirmationID, Provider: order.Provider, TradeNo: order.TradeNo,
|
||||
ProviderTradeNo: result.ProviderTradeNo, BusinessType: order.BusinessType,
|
||||
BusinessID: order.BusinessID, Subject: order.Subject, Amount: order.Amount,
|
||||
OriginalAmount: order.OriginalAmount, PayerPaidAmount: order.PayerPaidAmount,
|
||||
CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
|
||||
confirmation := &PaymentConfirmation{ID: order.ConfirmationID, Provider: order.Provider, TradeNo: order.TradeNo,
|
||||
ProviderTradeNo: result.ProviderTradeNo, BusinessType: order.BusinessType, BusinessID: order.BusinessID,
|
||||
Subject: order.Subject, Amount: order.Amount, OriginalAmount: order.OriginalAmount,
|
||||
PayerPaidAmount: order.PayerPaidAmount, CashPaidAmount: order.CashPaidAmount, PointPaidAmount: order.PointPaidAmount,
|
||||
DiscountAmount: order.DiscountAmount, ProviderDiscountAmount: order.ProviderDiscountAmount,
|
||||
MerchantDiscountAmount: order.MerchantDiscountAmount, SettlementAmount: order.SettlementAmount,
|
||||
Currency: order.Currency, PayerCurrency: order.PayerCurrency, AmountBreakdownKnown: order.AmountBreakdownKnown,
|
||||
Payload: result.Payload, CreatedAt: time.Now().UTC(),
|
||||
}
|
||||
Payload: result.Payload, CreatedAt: time.Now().UTC()}
|
||||
if err = handler.Fulfill(ctx, confirmation); err != nil {
|
||||
_, _ = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, false, err.Error())
|
||||
uc.logger.Error(ctx, "payment.order.fulfillment_failed", "provider", result.Provider, "trade_no", result.TradeNo, "confirmation_id", confirmation.ID, "error", err)
|
||||
return fail(err)
|
||||
return nil, err
|
||||
}
|
||||
order, err = uc.orders.CompletePaymentFulfillment(ctx, result.Provider, result.TradeNo, token, true, "")
|
||||
if err != nil {
|
||||
uc.logger.Error(ctx, "payment.order.fulfillment_record_failed", "provider", result.Provider, "trade_no", result.TradeNo, "confirmation_id", confirmation.ID, "error", err)
|
||||
return fail(err)
|
||||
return nil, err
|
||||
}
|
||||
result.Status = "fulfilled"
|
||||
return attachOrderResult(result, order), nil
|
||||
|
||||
Reference in New Issue
Block a user