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
+5 -49
View File
@@ -17,11 +17,6 @@ import (
"github.com/labstack/echo/v4"
)
// MarkPaidRequest is the payload for manually marking an order as paid.
type MarkPaidRequest struct {
BlockTransactionId string `json:"block_transaction_id" validate:"required" example:"0xabc123def456..."`
}
// OrderListResponse wraps the paginated order list.
type OrderListResponse struct {
List []mdb.Orders `json:"list"`
@@ -142,14 +137,14 @@ func (c *BaseAdminController) CloseOrder(ctx echo.Context) error {
// @Accept json
// @Produce json
// @Param trade_id path string true "Trade ID"
// @Param request body admin.MarkPaidRequest true "Block transaction ID"
// @Param request body request.ManualPaymentRequest true "Block transaction ID"
// @Success 200 {object} response.ApiResponse
// @Failure 400 {object} response.ApiResponse
// @Router /admin/api/v1/orders/{trade_id}/mark-paid [post]
func (c *BaseAdminController) MarkOrderPaid(ctx echo.Context) error {
tradeID := ctx.Param("trade_id")
adminUserID := currentAdminUserID(ctx)
req := new(MarkPaidRequest)
req := new(request.ManualPaymentRequest)
if err := ctx.Bind(req); err != nil {
log.Sugar.Warnf("[admin-order] mark-paid bind failed admin_user_id=%d trade_id=%s err=%v", adminUserID, tradeID, err)
return c.FailJson(ctx, err)
@@ -159,46 +154,12 @@ func (c *BaseAdminController) MarkOrderPaid(ctx echo.Context) error {
log.Sugar.Warnf("[admin-order] mark-paid validation failed admin_user_id=%d trade_id=%s block_transaction_id=%s err=%v", adminUserID, tradeID, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
order, err := data.GetOrderInfoByTradeId(tradeID)
resp, err := service.SubmitManualPayment(tradeID, req.BlockTransactionId)
if err != nil {
log.Sugar.Warnf("[admin-order] mark-paid load failed admin_user_id=%d trade_id=%s block_transaction_id=%s err=%v", adminUserID, tradeID, req.BlockTransactionId, err)
log.Sugar.Warnf("[admin-order] mark-paid failed admin_user_id=%d trade_id=%s block_transaction_id=%s err=%v", adminUserID, tradeID, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
if order.ID == 0 {
err = errors.New("order not found")
log.Sugar.Warnf("[admin-order] mark-paid rejected admin_user_id=%d trade_id=%s block_transaction_id=%s err=%v", adminUserID, tradeID, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
if order.Status != mdb.StatusWaitPay {
err = errors.New("order is not waiting payment")
log.Sugar.Warnf("[admin-order] mark-paid rejected admin_user_id=%d trade_id=%s status=%d block_transaction_id=%s err=%v", adminUserID, tradeID, order.Status, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
if !isOnChainOrder(order.PayProvider) {
err = errors.New("order is not an on-chain payment order")
log.Sugar.Warnf("[admin-order] mark-paid rejected admin_user_id=%d trade_id=%s pay_provider=%s block_transaction_id=%s err=%v", adminUserID, tradeID, order.PayProvider, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
verifiedBlockTransactionID, err := service.ValidateManualOrderPayment(order, req.BlockTransactionId)
if err != nil {
log.Sugar.Warnf("[admin-order] mark-paid chain verification failed admin_user_id=%d trade_id=%s network=%s token=%s amount=%.8f block_transaction_id=%s err=%v", adminUserID, tradeID, order.Network, order.Token, order.ActualAmount, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
req.BlockTransactionId = verifiedBlockTransactionID
err = service.OrderProcessing(&request.OrderProcessingRequest{
ReceiveAddress: order.ReceiveAddress,
Currency: order.Currency,
Token: order.Token,
Network: order.Network,
Amount: order.ActualAmount,
TradeId: order.TradeId,
BlockTransactionId: req.BlockTransactionId,
})
if err != nil {
log.Sugar.Warnf("[admin-order] mark-paid processing failed admin_user_id=%d trade_id=%s block_transaction_id=%s err=%v", adminUserID, tradeID, req.BlockTransactionId, err)
return c.FailJson(ctx, err)
}
log.Sugar.Infof("[admin-order] mark-paid success admin_user_id=%d trade_id=%s block_transaction_id=%s", adminUserID, tradeID, req.BlockTransactionId)
log.Sugar.Infof("[admin-order] mark-paid success admin_user_id=%d trade_id=%s block_transaction_id=%s", adminUserID, tradeID, resp.BlockTransactionId)
return c.SucJson(ctx, nil)
}
@@ -251,11 +212,6 @@ func (c *BaseAdminController) ResendCallback(ctx echo.Context) error {
return c.SucJson(ctx, nil)
}
func isOnChainOrder(payProvider string) bool {
payProvider = strings.TrimSpace(payProvider)
return payProvider == "" || payProvider == mdb.PaymentProviderOnChain
}
// ExportOrders streams matching orders as CSV. No pagination — the
// caller drives what rows to include via filter params. Capped at
// 10k rows to keep the response bounded.