feat: 业务逻辑补全 — 佣金待审记录、C端订单重构、支付抽象、富友支付、卡设备状态联动
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
Some checks failed
构建并部署到测试环境(无 SSH) / build-and-deploy (push) Has been cancelled
F-1: 佣金链断裂时创建 status=99 零额待审记录,新增修正接口 POST /commission-records/:id/resolve F-4: C端订单查询从 Handler 迁移至 Service 层,移除 SkipPermissionCtx J-1: 富友支付 JSAPI/MiniApp 预下单实现,回调补全签名验证 J-2: 平台钱包代购支持(buyerType 为空时使用资产所属代理钱包) J-3: 套餐激活后自动更新卡/设备 status=3,最后套餐过期后更新 status=4 支付抽象: 引入 PaymentProvider 接口 + 微信/富友适配器,CreateOrder 支持多支付渠道 修复: 设备/IoT卡响应 DTO 移除 omitempty,空值字段返回 null 而非省略
This commit is contained in:
@@ -16,6 +16,7 @@ import (
|
||||
"github.com/break/junhong_cmp_fiber/internal/store/postgres"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/constants"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/errors"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/fuiou"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/middleware"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/queue"
|
||||
"github.com/break/junhong_cmp_fiber/pkg/wechat"
|
||||
@@ -194,6 +195,14 @@ func (s *Service) CreateLegacy(ctx context.Context, req *dto.CreateOrderRequest,
|
||||
|
||||
} else if req.PaymentMethod == model.PaymentMethodWallet {
|
||||
// ==== 场景 2:代理钱包支付(wallet)====
|
||||
if buyerType == "" {
|
||||
if resourceShopID == nil {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "不支持的钱包支付场景")
|
||||
}
|
||||
buyerType = model.BuyerTypeAgent
|
||||
buyerID = *resourceShopID
|
||||
}
|
||||
|
||||
// 只有代理账号可以使用钱包支付
|
||||
if buyerType != model.BuyerTypeAgent {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "只有代理账号可以使用钱包支付")
|
||||
@@ -2379,14 +2388,126 @@ func (s *Service) GetPurchaseCheck(ctx context.Context, req *dto.PurchaseCheckRe
|
||||
return response, nil
|
||||
}
|
||||
|
||||
// FuiouPayJSAPI 富友公众号 JSAPI 支付发起(留桩)
|
||||
// TODO: 实现富友支付发起逻辑
|
||||
func (s *Service) FuiouPayJSAPI(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) error {
|
||||
return errors.New(errors.CodeFuiouPayFailed, "富友支付发起暂未实现")
|
||||
func (s *Service) FuiouPayJSAPI(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) (*dto.FuiouPayJSAPIResponse, error) {
|
||||
return s.fuiouPreCreate(ctx, orderID, openID, buyerType, buyerID, "JSAPI", false)
|
||||
}
|
||||
|
||||
// FuiouPayMiniApp 富友小程序支付发起(留桩)
|
||||
// TODO: 实现富友小程序支付发起逻辑
|
||||
func (s *Service) FuiouPayMiniApp(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) error {
|
||||
return errors.New(errors.CodeFuiouPayFailed, "富友小程序支付发起暂未实现")
|
||||
func (s *Service) FuiouPayMiniApp(ctx context.Context, orderID uint, openID string, buyerType string, buyerID uint) (*dto.FuiouPayJSAPIResponse, error) {
|
||||
return s.fuiouPreCreate(ctx, orderID, openID, buyerType, buyerID, "LETPAY", true)
|
||||
}
|
||||
|
||||
func (s *Service) fuiouPreCreate(
|
||||
ctx context.Context,
|
||||
orderID uint,
|
||||
openID string,
|
||||
buyerType string,
|
||||
buyerID uint,
|
||||
tradeType string,
|
||||
useMiniappAppID bool,
|
||||
) (*dto.FuiouPayJSAPIResponse, error) {
|
||||
if strings.TrimSpace(openID) == "" {
|
||||
return nil, errors.New(errors.CodeInvalidParam, "openID 不能为空")
|
||||
}
|
||||
|
||||
order, err := s.orderStore.GetByID(ctx, orderID)
|
||||
if err != nil {
|
||||
if err == gorm.ErrRecordNotFound {
|
||||
return nil, errors.New(errors.CodeNotFound, "订单不存在")
|
||||
}
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单失败")
|
||||
}
|
||||
|
||||
if order.BuyerType != buyerType || order.BuyerID != buyerID {
|
||||
return nil, errors.New(errors.CodeForbidden, "无权操作此订单")
|
||||
}
|
||||
|
||||
if order.PaymentStatus != model.PaymentStatusPending {
|
||||
return nil, errors.New(errors.CodeInvalidStatus, "订单状态不允许支付")
|
||||
}
|
||||
|
||||
activeConfig, err := s.wechatConfigService.GetActiveConfig(ctx)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "查询生效支付配置失败")
|
||||
}
|
||||
if activeConfig == nil || activeConfig.ProviderType != model.ProviderTypeFuiou {
|
||||
return nil, errors.New(errors.CodeFuiouPayFailed, "未找到生效的富友支付配置")
|
||||
}
|
||||
|
||||
subAppID := activeConfig.OaAppID
|
||||
if useMiniappAppID {
|
||||
subAppID = activeConfig.MiniappAppID
|
||||
}
|
||||
|
||||
if strings.TrimSpace(activeConfig.FyInsCd) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyMchntCd) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyTermID) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyPrivateKey) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyPublicKey) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyAPIURL) == "" ||
|
||||
strings.TrimSpace(activeConfig.FyNotifyURL) == "" ||
|
||||
strings.TrimSpace(subAppID) == "" {
|
||||
return nil, errors.New(errors.CodeFuiouPayFailed, "富友支付配置不完整")
|
||||
}
|
||||
|
||||
client, err := fuiou.NewClient(
|
||||
activeConfig.FyInsCd,
|
||||
activeConfig.FyMchntCd,
|
||||
activeConfig.FyTermID,
|
||||
activeConfig.FyAPIURL,
|
||||
activeConfig.FyNotifyURL,
|
||||
activeConfig.FyPrivateKey,
|
||||
activeConfig.FyPublicKey,
|
||||
s.logger,
|
||||
)
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "创建富友支付客户端失败")
|
||||
}
|
||||
|
||||
items, err := s.orderItemStore.ListByOrderIDs(ctx, []uint{orderID})
|
||||
if err != nil {
|
||||
return nil, errors.Wrap(errors.CodeInternalError, err, "查询订单明细失败")
|
||||
}
|
||||
description := "套餐购买"
|
||||
if len(items) > 0 {
|
||||
description = items[0].PackageName
|
||||
}
|
||||
|
||||
termIP := "127.0.0.1"
|
||||
if ip := middleware.GetIPFromContext(ctx); ip != nil && strings.TrimSpace(*ip) != "" {
|
||||
termIP = *ip
|
||||
}
|
||||
|
||||
resp, err := client.WxPreCreate(
|
||||
order.OrderNo,
|
||||
strconv.FormatInt(order.TotalAmount, 10),
|
||||
description,
|
||||
termIP,
|
||||
tradeType,
|
||||
subAppID,
|
||||
openID,
|
||||
)
|
||||
if err != nil {
|
||||
s.logger.Error("富友预下单失败",
|
||||
zap.Uint("order_id", orderID),
|
||||
zap.String("order_no", order.OrderNo),
|
||||
zap.String("trade_type", tradeType),
|
||||
zap.Error(err),
|
||||
)
|
||||
return nil, errors.Wrap(errors.CodeFuiouPayFailed, err, "富友预下单失败")
|
||||
}
|
||||
|
||||
s.logger.Info("富友预下单成功",
|
||||
zap.Uint("order_id", orderID),
|
||||
zap.String("order_no", order.OrderNo),
|
||||
zap.String("trade_type", tradeType),
|
||||
)
|
||||
|
||||
return &dto.FuiouPayJSAPIResponse{
|
||||
AppID: resp.SdkAppid,
|
||||
TimeStamp: resp.SdkTimestamp,
|
||||
NonceStr: resp.SdkNoncestr,
|
||||
Package: resp.SdkPackage,
|
||||
SignType: resp.SdkSigntype,
|
||||
PaySign: resp.SdkPaysign,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user