package financeorder import ( "errors" "strconv" "strings" "hyapp-admin-server/internal/integration/userclient" "hyapp-admin-server/internal/integration/walletclient" "hyapp-admin-server/internal/middleware" "hyapp-admin-server/internal/modules/shared" "hyapp-admin-server/internal/repository" "hyapp-admin-server/internal/response" "github.com/gin-gonic/gin" "google.golang.org/grpc/codes" "google.golang.org/grpc/status" "gorm.io/gorm" ) type Handler struct { service *Service audit shared.OperationLogger } func New(store *repository.Store, wallet walletclient.Client, user userclient.Client, audit shared.OperationLogger, options ...Option) *Handler { return &Handler{service: NewService(store, wallet, user, options...), audit: audit} } func (h *Handler) ListCoinSellerRechargeOrders(c *gin.Context) { options := shared.ListOptions(c) items, total, err := h.service.ListOrders(repository.CoinSellerRechargeOrderListOptions{ Page: options.Page, PageSize: options.PageSize, AppCode: firstQuery(c, "app_code", "appCode"), Status: options.Status, VerifyStatus: firstQuery(c, "verify_status", "verifyStatus"), GrantStatus: firstQuery(c, "grant_status", "grantStatus"), ProviderCode: firstQuery(c, "provider_code", "providerCode"), Keyword: options.Keyword, TargetUserID: parseInt64Query(c, "target_user_id", "targetUserId"), OperatorID: uint(parseInt64Query(c, "operator_id", "operatorId")), CreatedFromMS: parseInt64Query(c, "created_from_ms", "createdFromMs", "start_ms", "startMs"), CreatedToMS: parseInt64Query(c, "created_to_ms", "createdToMs", "end_ms", "endMs"), }) if err != nil { writeServiceError(c, err, "获取币商充值订单失败") return } response.OK(c, response.Page{Items: items, Page: options.Page, PageSize: options.PageSize, Total: total}) } func (h *Handler) GetCoinSellerRechargeOrder(c *gin.Context) { id, ok := shared.ParseID(c, "order_id") if !ok { return } item, err := h.service.GetOrder(id) if err != nil { writeServiceError(c, err, "获取币商充值订单失败") return } response.OK(c, item) } func (h *Handler) CreateCoinSellerRechargeOrder(c *gin.Context) { var req createCoinSellerRechargeOrderRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "币商充值订单参数不正确") return } item, err := h.service.CreateOrder(c.Request.Context(), shared.ActorFromContext(c), req, middleware.CurrentRequestID(c)) if err != nil { writeServiceError(c, err, "创建币商充值订单失败") return } shared.OperationLogWithResourceID(c, h.audit, "create-coin-seller-recharge-order", "admin_coin_seller_recharge_orders", idString(item.ID), "success", item.ProviderCode+":"+item.ExternalOrderNo) response.Created(c, item) } func (h *Handler) VerifyCoinSellerRechargeReceipt(c *gin.Context) { var req verifyCoinSellerRechargeReceiptRequest if err := c.ShouldBindJSON(&req); err != nil { response.BadRequest(c, "币商充值凭证参数不正确") return } item, err := h.service.VerifyReceipt(c.Request.Context(), shared.ActorFromContext(c), req, middleware.CurrentRequestID(c)) if err != nil { writeServiceError(c, err, "校验币商充值凭证失败") return } shared.OperationLogWithResourceID(c, h.audit, "verify-coin-seller-recharge-receipt", "admin_coin_seller_recharge_orders", item.ExternalOrderNo, "success", item.ProviderCode+":"+item.Status) response.OK(c, item) } func (h *Handler) VerifyCoinSellerRechargeOrder(c *gin.Context) { id, ok := shared.ParseID(c, "order_id") if !ok { return } item, err := h.service.VerifyOrder(c.Request.Context(), shared.ActorFromContext(c), id, middleware.CurrentRequestID(c)) if err != nil { writeServiceError(c, err, "校验币商充值订单失败") return } shared.OperationLogWithResourceID(c, h.audit, "verify-coin-seller-recharge-order", "admin_coin_seller_recharge_orders", idString(item.ID), "success", item.VerifyStatus) response.OK(c, item) } func (h *Handler) GrantCoinSellerRechargeOrder(c *gin.Context) { id, ok := shared.ParseID(c, "order_id") if !ok { return } item, err := h.service.GrantOrder(c.Request.Context(), shared.ActorFromContext(c), id, middleware.CurrentRequestID(c)) if err != nil { writeServiceError(c, err, "发放币商充值金币失败") return } shared.OperationLogWithResourceID(c, h.audit, "grant-coin-seller-recharge-order", "admin_coin_seller_recharge_orders", idString(item.ID), "success", item.WalletTransactionID) response.OK(c, item) } func writeServiceError(c *gin.Context, err error, fallback string) { if errors.Is(err, gorm.ErrRecordNotFound) { response.NotFound(c, "币商充值订单不存在") return } if errors.Is(err, errCoinSellerRechargeForbidden) { response.Forbidden(c, err.Error()) return } if errors.Is(err, repository.ErrCoinSellerRechargeOrderNotVerified) { response.BadRequest(c, "订单尚未校验通过") return } if errors.Is(err, repository.ErrCoinSellerRechargeOrderGranting) { response.BadRequest(c, "订单正在发放中") return } if errors.Is(err, repository.ErrCoinSellerRechargeOrderGranted) { response.BadRequest(c, "订单已发放") return } if errors.Is(err, errInvalidCoinSellerRechargeOrderInput) { response.BadRequest(c, err.Error()) return } if errors.Is(err, errLegacyCoinSellerNotFound) { response.BadRequest(c, "目标用户不是启用中的币商/货运代理") return } if errors.Is(err, errLegacyCoinSellerOrderDuplicate) { response.BadRequest(c, "legacy 账套中订单号已入账") return } if isDuplicateKeyError(err) { response.BadRequest(c, "订单号已绑定,不能重复使用") return } if status.Code(err) == codes.NotFound { response.NotFound(c, err.Error()) return } if st, ok := status.FromError(err); ok && strings.TrimSpace(st.Message()) != "" { switch st.Code() { case codes.PermissionDenied: response.Forbidden(c, st.Message()) return case codes.InvalidArgument, codes.FailedPrecondition, codes.AlreadyExists, codes.Aborted, codes.ResourceExhausted: response.BadRequest(c, st.Message()) return case codes.Unavailable: response.ServerError(c, fallback) return } } if strings.Contains(err.Error(), "not configured") { response.ServerError(c, fallback) return } response.BadRequest(c, err.Error()) } func firstQuery(c *gin.Context, keys ...string) string { for _, key := range keys { if value := strings.TrimSpace(c.Query(key)); value != "" { return value } } return "" } func parseInt64Query(c *gin.Context, keys ...string) int64 { value := firstQuery(c, keys...) if value == "" { return 0 } parsed, _ := strconv.ParseInt(value, 10, 64) return parsed } func idString(id uint) string { return strconv.FormatUint(uint64(id), 10) }