feat(payment): allow cashier manual tx hash submission

This commit is contained in:
line-6000
2026-05-26 23:16:10 +08:00
parent 8bf2adad89
commit fca75a99ea
174 changed files with 427 additions and 262 deletions
+11
View File
@@ -39,6 +39,17 @@ type OrderProcessingRequest struct {
BlockTransactionId string
}
// ManualPaymentRequest 手动提交交易 hash 补单
type ManualPaymentRequest struct {
BlockTransactionId string `json:"block_transaction_id" validate:"required" example:"0xabc123def456..."`
}
func (r ManualPaymentRequest) Translates() map[string]string {
return validate.MS{
"BlockTransactionId": "交易哈希",
}
}
// SwitchNetworkRequest 切换支付网络
type SwitchNetworkRequest struct {
TradeId string `json:"trade_id" validate:"required" example:"T2026041612345678"`
+6
View File
@@ -20,3 +20,9 @@ type CheckStatusResponse struct {
// 订单状态 1=等待支付 2=支付成功 3=已过期
Status int `json:"status" enums:"1,2,3" example:"1"`
}
type ManualPaymentResponse struct {
TradeId string `json:"trade_id" example:"T2026041612345678"` // epusdt订单号
Status int `json:"status" enums:"1,2,3" example:"2"` // 订单状态 1=等待支付 2=支付成功 3=已过期
BlockTransactionId string `json:"block_transaction_id" example:"0xabc123def456..."` // 已验证并入账的交易哈希
}
+49
View File
@@ -339,6 +339,55 @@ func GetOrderInfoByTradeId(tradeId string) (*mdb.Orders, error) {
return order, nil
}
// SubmitManualPayment verifies a submitted transaction hash and marks the
// matching on-chain order paid using the same path as automatic chain scans.
func SubmitManualPayment(tradeId, blockTransactionId string) (*response.ManualPaymentResponse, error) {
tradeId = strings.TrimSpace(tradeId)
blockTransactionId = strings.TrimSpace(blockTransactionId)
order, err := GetOrderInfoByTradeId(tradeId)
if err != nil {
return nil, err
}
if order.Status != mdb.StatusWaitPay {
return nil, constant.OrderNotWaitPay
}
if !isOnChainOrder(order.PayProvider) {
return nil, errors.New("order is not an on-chain payment order")
}
verifiedBlockTransactionID, err := ValidateManualOrderPayment(order, blockTransactionId)
if err != nil {
return nil, err
}
if err = OrderProcessing(&request.OrderProcessingRequest{
ReceiveAddress: order.ReceiveAddress,
Currency: order.Currency,
Token: order.Token,
Network: order.Network,
Amount: order.ActualAmount,
TradeId: order.TradeId,
BlockTransactionId: verifiedBlockTransactionID,
}); err != nil {
return nil, err
}
updatedOrder, err := GetOrderInfoByTradeId(order.TradeId)
if err != nil {
return nil, err
}
return &response.ManualPaymentResponse{
TradeId: updatedOrder.TradeId,
Status: updatedOrder.Status,
BlockTransactionId: updatedOrder.BlockTransactionId,
}, nil
}
func isOnChainOrder(payProvider string) bool {
payProvider = strings.TrimSpace(payProvider)
return payProvider == "" || payProvider == mdb.PaymentProviderOnChain
}
const MaxSubOrders = 2
// SwitchNetwork creates or returns an existing sub-order for a different token+network.