优化结构
This commit is contained in:
+118
-53
@@ -6,14 +6,21 @@ import (
|
||||
)
|
||||
|
||||
type PaymentOrderListRequest struct {
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"pageSize"`
|
||||
Provider string `form:"provider"`
|
||||
TradeNo string `form:"tradeNo"`
|
||||
BusinessType string `form:"businessType"`
|
||||
BusinessID string `form:"businessId"`
|
||||
PaymentStatus string `form:"paymentStatus"`
|
||||
RefundStatus string `form:"refundStatus"`
|
||||
Page int `form:"page"`
|
||||
PageSize int `form:"pageSize"`
|
||||
Provider string `form:"provider"`
|
||||
TradeNo string `form:"tradeNo"`
|
||||
ProviderTradeNo string `form:"providerTradeNo"`
|
||||
Keyword string `form:"keyword"`
|
||||
BusinessType string `form:"businessType"`
|
||||
BusinessID string `form:"businessId"`
|
||||
PaymentStatus string `form:"paymentStatus"`
|
||||
RefundStatus string `form:"refundStatus"`
|
||||
CreatedFrom string `form:"createdFrom"`
|
||||
CreatedTo string `form:"createdTo"`
|
||||
PaidFrom string `form:"paidFrom"`
|
||||
PaidTo string `form:"paidTo"`
|
||||
IssueOnly bool `form:"issueOnly"`
|
||||
}
|
||||
|
||||
type PaymentRequest struct {
|
||||
@@ -30,29 +37,49 @@ type PaymentRequest struct {
|
||||
BusinessType string `json:"businessType"`
|
||||
BusinessID string `json:"businessId"`
|
||||
PaymentMode string `json:"paymentMode"`
|
||||
UserAgent string `json:"-"`
|
||||
DeviceID string `json:"-"`
|
||||
}
|
||||
type PaymentQueryRequest struct {
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
OperatorID uint `json:"-"`
|
||||
OperatorName string `json:"-"`
|
||||
ClientIP string `json:"-"`
|
||||
UserAgent string `json:"-"`
|
||||
DeviceID string `json:"-"`
|
||||
}
|
||||
type PaymentRefundRequest struct {
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Amount int64 `json:"amount"`
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Amount int64 `json:"amount"`
|
||||
Reason string `json:"reason"`
|
||||
OperatorID uint `json:"-"`
|
||||
OperatorName string `json:"-"`
|
||||
ClientIP string `json:"-"`
|
||||
UserAgent string `json:"-"`
|
||||
DeviceID string `json:"-"`
|
||||
}
|
||||
|
||||
type PaymentFulfillRequest struct {
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
OperatorID uint `json:"-"`
|
||||
OperatorName string `json:"-"`
|
||||
ClientIP string `json:"-"`
|
||||
UserAgent string `json:"-"`
|
||||
DeviceID string `json:"-"`
|
||||
}
|
||||
|
||||
// PaymentCallbackRequest is populated by the HTTP transport and converted to
|
||||
// the biz callback object inside service.
|
||||
type PaymentCallbackRequest struct {
|
||||
Provider string
|
||||
Headers map[string]string
|
||||
Body []byte
|
||||
Query map[string]string
|
||||
Provider string
|
||||
Headers map[string]string
|
||||
Body []byte
|
||||
Query map[string]string
|
||||
ClientIP string
|
||||
UserAgent string
|
||||
}
|
||||
|
||||
type PaymentCallbackAck struct {
|
||||
@@ -103,38 +130,76 @@ type PaymentTestResult struct {
|
||||
}
|
||||
|
||||
type PaymentOrderResponse struct {
|
||||
ID uint64 `json:"ID"`
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
ProviderTradeNo string `json:"providerTradeNo"`
|
||||
BusinessType string `json:"businessType"`
|
||||
BusinessID string `json:"businessId"`
|
||||
Subject string `json:"subject"`
|
||||
PaymentMode string `json:"paymentMode"`
|
||||
OriginalAmount int64 `json:"originalAmount"`
|
||||
Amount int64 `json:"amount"`
|
||||
PaidAmount int64 `json:"paidAmount"`
|
||||
PayerPaidAmount int64 `json:"payerPaidAmount"`
|
||||
CashPaidAmount int64 `json:"cashPaidAmount"`
|
||||
PointPaidAmount int64 `json:"pointPaidAmount"`
|
||||
DiscountAmount int64 `json:"discountAmount"`
|
||||
ProviderDiscountAmount int64 `json:"providerDiscountAmount"`
|
||||
MerchantDiscountAmount int64 `json:"merchantDiscountAmount"`
|
||||
SettlementAmount int64 `json:"settlementAmount"`
|
||||
Currency string `json:"currency"`
|
||||
PayerCurrency string `json:"payerCurrency,omitempty"`
|
||||
AmountBreakdownKnown bool `json:"amountBreakdownKnown"`
|
||||
PaymentStatus string `json:"paymentStatus"`
|
||||
ProviderStatus string `json:"providerStatus"`
|
||||
FulfillmentStatus string `json:"fulfillmentStatus"`
|
||||
RefundStatus string `json:"refundStatus"`
|
||||
RefundedAmount int64 `json:"refundedAmount"`
|
||||
RefundRequestedAmount int64 `json:"refundRequestedAmount"`
|
||||
RefundNo string `json:"refundNo,omitempty"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
PaidAt *time.Time `json:"paidAt,omitempty"`
|
||||
FulfilledAt *time.Time `json:"fulfilledAt,omitempty"`
|
||||
RefundedAt *time.Time `json:"refundedAt,omitempty"`
|
||||
ID uint64 `json:"ID"`
|
||||
Provider string `json:"provider"`
|
||||
TradeNo string `json:"tradeNo"`
|
||||
ProviderTradeNo string `json:"providerTradeNo"`
|
||||
BusinessType string `json:"businessType"`
|
||||
BusinessID string `json:"businessId"`
|
||||
Subject string `json:"subject"`
|
||||
PaymentMode string `json:"paymentMode"`
|
||||
OriginalAmount int64 `json:"originalAmount"`
|
||||
Amount int64 `json:"amount"`
|
||||
PaidAmount int64 `json:"paidAmount"`
|
||||
PayerPaidAmount int64 `json:"payerPaidAmount"`
|
||||
CashPaidAmount int64 `json:"cashPaidAmount"`
|
||||
PointPaidAmount int64 `json:"pointPaidAmount"`
|
||||
DiscountAmount int64 `json:"discountAmount"`
|
||||
ProviderDiscountAmount int64 `json:"providerDiscountAmount"`
|
||||
MerchantDiscountAmount int64 `json:"merchantDiscountAmount"`
|
||||
SettlementAmount int64 `json:"settlementAmount"`
|
||||
Currency string `json:"currency"`
|
||||
PayerCurrency string `json:"payerCurrency,omitempty"`
|
||||
AmountBreakdownKnown bool `json:"amountBreakdownKnown"`
|
||||
PaymentStatus string `json:"paymentStatus"`
|
||||
ProviderStatus string `json:"providerStatus"`
|
||||
FulfillmentStatus string `json:"fulfillmentStatus"`
|
||||
RefundStatus string `json:"refundStatus"`
|
||||
RefundedAmount int64 `json:"refundedAmount"`
|
||||
RefundRequestedAmount int64 `json:"refundRequestedAmount"`
|
||||
RefundNo string `json:"refundNo,omitempty"`
|
||||
LastError string `json:"lastError,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
UpdatedAt time.Time `json:"updatedAt"`
|
||||
PaidAt *time.Time `json:"paidAt,omitempty"`
|
||||
FulfilledAt *time.Time `json:"fulfilledAt,omitempty"`
|
||||
RefundedAt *time.Time `json:"refundedAt,omitempty"`
|
||||
Events []*PaymentEventResponse `json:"events,omitempty"`
|
||||
}
|
||||
|
||||
type PaymentEventResponse struct {
|
||||
ID uint64 `json:"id"`
|
||||
Type string `json:"type"`
|
||||
Source string `json:"source"`
|
||||
Status string `json:"status"`
|
||||
ProviderStatus string `json:"providerStatus,omitempty"`
|
||||
Message string `json:"message,omitempty"`
|
||||
EventID string `json:"eventId,omitempty"`
|
||||
PayloadHash string `json:"payloadHash,omitempty"`
|
||||
Amount int64 `json:"amount,omitempty"`
|
||||
Currency string `json:"currency,omitempty"`
|
||||
OperatorID uint `json:"operatorId,omitempty"`
|
||||
OperatorName string `json:"operatorName,omitempty"`
|
||||
ClientIP string `json:"clientIp,omitempty"`
|
||||
UserAgent string `json:"userAgent,omitempty"`
|
||||
DeviceID string `json:"deviceId,omitempty"`
|
||||
CreatedAt time.Time `json:"createdAt"`
|
||||
}
|
||||
|
||||
type PaymentCurrencySummaryResponse struct {
|
||||
Currency string `json:"currency"`
|
||||
OrderAmount int64 `json:"orderAmount"`
|
||||
PaidAmount int64 `json:"paidAmount"`
|
||||
RefundedAmount int64 `json:"refundedAmount"`
|
||||
SettlementAmount int64 `json:"settlementAmount"`
|
||||
NetAmount int64 `json:"netAmount"`
|
||||
}
|
||||
|
||||
type PaymentOrderSummaryResponse struct {
|
||||
OrderCount int64 `json:"orderCount"`
|
||||
PendingCount int64 `json:"pendingCount"`
|
||||
PaidCount int64 `json:"paidCount"`
|
||||
RefundedCount int64 `json:"refundedCount"`
|
||||
IssueCount int64 `json:"issueCount"`
|
||||
Currencies []*PaymentCurrencySummaryResponse `json:"currencies"`
|
||||
}
|
||||
|
||||
@@ -4,6 +4,8 @@ import (
|
||||
"context"
|
||||
"errors"
|
||||
paymentbiz "kra/internal/biz/payment"
|
||||
"strings"
|
||||
"time"
|
||||
|
||||
"kra/internal/service/dto"
|
||||
)
|
||||
@@ -16,7 +18,16 @@ func (s *PaymentService) Order(ctx context.Context, provider, tradeNo string) (*
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paymentOrderResponse(order)
|
||||
response, err := paymentOrderResponse(order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
events, err := s.uc.OrderEvents(ctx, provider, tradeNo, 100)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response.Events = paymentEventResponses(events)
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRequest) ([]*dto.PaymentOrderResponse, int64, int, int, error) {
|
||||
@@ -30,10 +41,11 @@ func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRe
|
||||
if pageSize <= 0 {
|
||||
pageSize = 10
|
||||
}
|
||||
items, total, err := s.uc.Orders(ctx, page, pageSize, paymentbiz.PaymentOrderFilter{
|
||||
Provider: req.Provider, TradeNo: req.TradeNo, BusinessType: req.BusinessType,
|
||||
BusinessID: req.BusinessID, PaymentStatus: req.PaymentStatus, RefundStatus: req.RefundStatus,
|
||||
})
|
||||
filter, err := paymentOrderFilter(req)
|
||||
if err != nil {
|
||||
return nil, 0, page, pageSize, err
|
||||
}
|
||||
items, total, err := s.uc.Orders(ctx, page, pageSize, filter)
|
||||
if err != nil {
|
||||
return nil, 0, page, pageSize, err
|
||||
}
|
||||
@@ -48,6 +60,113 @@ func (s *PaymentService) Orders(ctx context.Context, req *dto.PaymentOrderListRe
|
||||
return result, total, page, pageSize, nil
|
||||
}
|
||||
|
||||
func (s *PaymentService) OrderSummary(ctx context.Context, req *dto.PaymentOrderListRequest) (*dto.PaymentOrderSummaryResponse, error) {
|
||||
filter, err := paymentOrderFilter(req)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
summary, err := s.uc.OrderSummary(ctx, filter)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
response := &dto.PaymentOrderSummaryResponse{
|
||||
OrderCount: summary.OrderCount, PendingCount: summary.PendingCount, PaidCount: summary.PaidCount,
|
||||
RefundedCount: summary.RefundedCount, IssueCount: summary.IssueCount,
|
||||
Currencies: make([]*dto.PaymentCurrencySummaryResponse, 0, len(summary.Currencies)),
|
||||
}
|
||||
for _, item := range summary.Currencies {
|
||||
response.Currencies = append(response.Currencies, &dto.PaymentCurrencySummaryResponse{
|
||||
Currency: item.Currency, OrderAmount: item.OrderAmount, PaidAmount: item.PaidAmount,
|
||||
RefundedAmount: item.RefundedAmount, SettlementAmount: item.SettlementAmount, NetAmount: item.NetAmount,
|
||||
})
|
||||
}
|
||||
return response, nil
|
||||
}
|
||||
|
||||
func (s *PaymentService) OrderEvents(ctx context.Context, provider, tradeNo string, limit int) ([]*dto.PaymentEventResponse, error) {
|
||||
events, err := s.uc.OrderEvents(ctx, provider, tradeNo, limit)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return paymentEventResponses(events), nil
|
||||
}
|
||||
|
||||
func paymentOrderFilter(req *dto.PaymentOrderListRequest) (paymentbiz.PaymentOrderFilter, error) {
|
||||
if req == nil {
|
||||
return paymentbiz.PaymentOrderFilter{}, errors.New("支付订单筛选请求为空")
|
||||
}
|
||||
createdFrom, err := parsePaymentFilterTime(req.CreatedFrom, false)
|
||||
if err != nil {
|
||||
return paymentbiz.PaymentOrderFilter{}, err
|
||||
}
|
||||
createdTo, err := parsePaymentFilterTime(req.CreatedTo, true)
|
||||
if err != nil {
|
||||
return paymentbiz.PaymentOrderFilter{}, err
|
||||
}
|
||||
paidFrom, err := parsePaymentFilterTime(req.PaidFrom, false)
|
||||
if err != nil {
|
||||
return paymentbiz.PaymentOrderFilter{}, err
|
||||
}
|
||||
paidTo, err := parsePaymentFilterTime(req.PaidTo, true)
|
||||
if err != nil {
|
||||
return paymentbiz.PaymentOrderFilter{}, err
|
||||
}
|
||||
if createdFrom != nil && createdTo != nil && !createdFrom.Before(*createdTo) {
|
||||
return paymentbiz.PaymentOrderFilter{}, errors.New("订单创建时间范围无效")
|
||||
}
|
||||
if paidFrom != nil && paidTo != nil && !paidFrom.Before(*paidTo) {
|
||||
return paymentbiz.PaymentOrderFilter{}, errors.New("支付完成时间范围无效")
|
||||
}
|
||||
return paymentbiz.PaymentOrderFilter{
|
||||
Provider: req.Provider, TradeNo: req.TradeNo, ProviderTradeNo: req.ProviderTradeNo, Keyword: req.Keyword,
|
||||
BusinessType: req.BusinessType, BusinessID: req.BusinessID, PaymentStatus: req.PaymentStatus,
|
||||
RefundStatus: req.RefundStatus, CreatedFrom: createdFrom, CreatedTo: createdTo,
|
||||
PaidFrom: paidFrom, PaidTo: paidTo, IssueOnly: req.IssueOnly,
|
||||
}, nil
|
||||
}
|
||||
|
||||
func parsePaymentFilterTime(value string, endOfDate bool) (*time.Time, error) {
|
||||
value = strings.TrimSpace(value)
|
||||
if value == "" {
|
||||
return nil, nil
|
||||
}
|
||||
if parsed, err := time.Parse(time.RFC3339, value); err == nil {
|
||||
return &parsed, nil
|
||||
}
|
||||
parsed, err := time.ParseInLocation("2006-01-02", value, time.Local)
|
||||
if err != nil {
|
||||
return nil, errors.New("支付订单时间格式无效")
|
||||
}
|
||||
if endOfDate {
|
||||
parsed = parsed.AddDate(0, 0, 1)
|
||||
}
|
||||
return &parsed, nil
|
||||
}
|
||||
|
||||
func paymentEventResponses(events []*paymentbiz.PaymentEvent) []*dto.PaymentEventResponse {
|
||||
result := make([]*dto.PaymentEventResponse, 0, len(events))
|
||||
for _, event := range events {
|
||||
if event == nil {
|
||||
continue
|
||||
}
|
||||
result = append(result, &dto.PaymentEventResponse{
|
||||
ID: event.ID, Type: event.Type, Source: event.Source, Status: event.Status,
|
||||
ProviderStatus: event.ProviderStatus, Message: event.Message, EventID: event.EventID,
|
||||
PayloadHash: event.PayloadHash, Amount: event.Amount, Currency: event.Currency,
|
||||
OperatorID: event.OperatorID, OperatorName: event.OperatorName, ClientIP: event.ClientIP,
|
||||
UserAgent: event.UserAgent, DeviceID: event.DeviceID, CreatedAt: event.CreatedAt,
|
||||
})
|
||||
}
|
||||
return result
|
||||
}
|
||||
|
||||
func operationContext(ctx context.Context, source, reason string, operatorID uint, operatorName, clientIP, userAgent, deviceID string) context.Context {
|
||||
return paymentbiz.WithPaymentOperation(ctx, paymentbiz.PaymentOperation{
|
||||
Source: source, Reason: reason, OperatorID: operatorID, OperatorName: operatorName,
|
||||
ClientIP: clientIP, UserAgent: userAgent, DeviceID: deviceID,
|
||||
})
|
||||
}
|
||||
|
||||
func paymentOrderResponse(order *paymentbiz.PaymentOrder) (*dto.PaymentOrderResponse, error) {
|
||||
if order == nil {
|
||||
return nil, errors.New("支付订单为空")
|
||||
@@ -75,7 +194,7 @@ func (s *PaymentService) Create(ctx context.Context, req *dto.PaymentRequest) (*
|
||||
Amount: req.Amount, OriginalAmount: req.OriginalAmount, Currency: req.Currency,
|
||||
NotifyURL: req.NotifyURL, ReturnURL: req.ReturnURL, ClientIP: req.ClientIP,
|
||||
Extra: req.Extra, BusinessType: req.BusinessType, BusinessID: req.BusinessID,
|
||||
PaymentMode: req.PaymentMode,
|
||||
PaymentMode: req.PaymentMode, UserAgent: req.UserAgent, DeviceID: req.DeviceID,
|
||||
})
|
||||
return paymentResultResponse(result), err
|
||||
}
|
||||
@@ -83,6 +202,7 @@ func (s *PaymentService) Query(ctx context.Context, req *dto.PaymentQueryRequest
|
||||
if req == nil {
|
||||
return nil, errors.New("支付查询请求为空")
|
||||
}
|
||||
ctx = operationContext(ctx, "admin", "主动同步支付平台状态", req.OperatorID, req.OperatorName, req.ClientIP, req.UserAgent, req.DeviceID)
|
||||
result, err := s.uc.Query(ctx, req.Provider, req.TradeNo)
|
||||
return paymentResultResponse(result), err
|
||||
}
|
||||
@@ -90,6 +210,11 @@ func (s *PaymentService) Refund(ctx context.Context, req *dto.PaymentRefundReque
|
||||
if req == nil {
|
||||
return nil, errors.New("支付退款请求为空")
|
||||
}
|
||||
reason := strings.TrimSpace(req.Reason)
|
||||
if reason == "" {
|
||||
reason = "未填写退款原因"
|
||||
}
|
||||
ctx = operationContext(ctx, "admin", reason, req.OperatorID, req.OperatorName, req.ClientIP, req.UserAgent, req.DeviceID)
|
||||
result, err := s.uc.Refund(ctx, req.Provider, req.TradeNo, req.Amount)
|
||||
return paymentResultResponse(result), err
|
||||
}
|
||||
@@ -111,6 +236,7 @@ func (s *PaymentService) Fulfill(ctx context.Context, req *dto.PaymentFulfillReq
|
||||
if req == nil {
|
||||
return nil, errors.New("支付发货请求为空")
|
||||
}
|
||||
ctx = operationContext(ctx, "admin", "人工执行或重试业务发货", req.OperatorID, req.OperatorName, req.ClientIP, req.UserAgent, req.DeviceID)
|
||||
result, err := s.uc.Fulfill(ctx, req.Provider, req.TradeNo)
|
||||
return paymentResultResponse(result), err
|
||||
}
|
||||
@@ -118,6 +244,7 @@ func (s *PaymentService) Callback(ctx context.Context, req *dto.PaymentCallbackR
|
||||
if req == nil {
|
||||
return paymentCallbackAckResponse(paymentbiz.DefaultPaymentCallbackAck("", false)), errors.New("支付回调请求为空")
|
||||
}
|
||||
ctx = operationContext(ctx, req.Provider, "支付平台异步通知", 0, "", req.ClientIP, req.UserAgent, "")
|
||||
result, err := s.uc.Callback(ctx, &paymentbiz.PaymentCallback{Provider: req.Provider, Headers: req.Headers, Body: req.Body, Query: req.Query})
|
||||
if err != nil {
|
||||
return paymentCallbackAckResponse(paymentbiz.CallbackFailure(err, paymentbiz.DefaultPaymentCallbackAck(req.Provider, false))), err
|
||||
|
||||
Reference in New Issue
Block a user