206 lines
6.7 KiB
Go
206 lines
6.7 KiB
Go
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)
|
|
}
|