gomod引用
This commit is contained in:
@@ -12,6 +12,8 @@ import (
|
||||
"order/model/dto"
|
||||
"order/model/entity"
|
||||
|
||||
"gitee.com/red-future---jilin-g/common/http"
|
||||
"github.com/gogf/gf/v2/frame/g"
|
||||
"go.mongodb.org/mongo-driver/v2/bson"
|
||||
)
|
||||
|
||||
@@ -188,8 +190,50 @@ func (s *payment) HandlePaymentNotify(ctx context.Context, req *dto.PaymentNotif
|
||||
return fmt.Errorf("更新支付记录失败: %w", err)
|
||||
}
|
||||
|
||||
// 4. 如果支付成功,更新订单状态
|
||||
// 4. 如果支付成功,更新订单状态并处理库存
|
||||
if req.Status == "success" {
|
||||
// 获取订单信息以处理库存
|
||||
order, err := dao.Order.GetPendingOrder(ctx, req.OrderNo)
|
||||
if err != nil {
|
||||
return fmt.Errorf("获取待支付订单失败: %w", err)
|
||||
}
|
||||
|
||||
if order == nil {
|
||||
return errors.New("待支付订单不存在")
|
||||
}
|
||||
|
||||
// 处理库存扣减
|
||||
for _, item := range order.OrderItems {
|
||||
// 判断是否需要扣减库存
|
||||
shouldDeduct, saleMode, err := s.shouldDeductStock(ctx, paymentRecord.TenantId.(string), item.AssetID)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "检查库存策略失败,订单:%s,资产:%s,错误:%v", req.OrderNo, item.AssetID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 如果需要扣减库存,判断扣减时机
|
||||
if shouldDeduct {
|
||||
timing, err := s.getDeductStockTiming(ctx, paymentRecord.TenantId.(string), item.AssetID)
|
||||
if err != nil {
|
||||
g.Log().Errorf(ctx, "获取库存扣减时机失败,订单:%s,资产:%s,错误:%v", req.OrderNo, item.AssetID, err)
|
||||
continue
|
||||
}
|
||||
|
||||
// 常规售卖:支付成功时扣减库存
|
||||
if timing == "payment_success" {
|
||||
quantity := len(item.Stocks) // 每个库存项数量为1
|
||||
if err := s.deductStock(ctx, paymentRecord.TenantId.(string), req.OrderNo, item.AssetID, quantity, fmt.Sprintf("支付成功扣减库存,售卖方式:%s", saleMode)); err != nil {
|
||||
g.Log().Errorf(ctx, "支付成功扣减库存失败,订单:%s,资产:%s,错误:%v", req.OrderNo, item.AssetID, err)
|
||||
// 库存扣减失败不影响订单状态更新,但需要记录错误
|
||||
continue
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "资产 %s 支付成功扣减库存成功,订单:%s,数量:%d", item.AssetID, req.OrderNo, quantity)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// 更新订单状态
|
||||
updateData := bson.M{
|
||||
"paid_at": time.Now(),
|
||||
"transaction_id": req.TransactionID,
|
||||
@@ -344,3 +388,141 @@ func (s *payment) verifyRefundNotifySignature(req *dto.RefundNotifyReq) bool {
|
||||
// 为了演示,我们总是返回true
|
||||
return true
|
||||
}
|
||||
|
||||
// shouldDeductStock 判断是否需要扣减库存
|
||||
func (s *payment) shouldDeductStock(ctx context.Context, tenantID, assetID string) (bool, string, error) {
|
||||
// 调用assets服务获取资产信息
|
||||
assetResp, err := s.getAssetFromAssetService(ctx, tenantID, assetID)
|
||||
if err != nil {
|
||||
return false, "", fmt.Errorf("获取资产信息失败: %w", err)
|
||||
}
|
||||
|
||||
if assetResp == nil {
|
||||
return false, "", errors.New("资产不存在")
|
||||
}
|
||||
|
||||
// 无库存限制的资产不需要扣减库存
|
||||
if assetResp.UnlimitedStock {
|
||||
return false, "unlimited_stock", nil
|
||||
}
|
||||
|
||||
// 预售场景不扣减库存
|
||||
if assetResp.SaleMode == "presale" {
|
||||
return false, "presale_no_deduct", nil
|
||||
}
|
||||
|
||||
// 有库存限制的常规售卖和秒杀需要扣减库存
|
||||
return true, assetResp.SaleMode, nil
|
||||
}
|
||||
|
||||
// getDeductStockTiming 获取库存扣减时机
|
||||
func (s *payment) getDeductStockTiming(ctx context.Context, tenantID, assetID string) (string, error) {
|
||||
assetResp, err := s.getAssetFromAssetService(ctx, tenantID, assetID)
|
||||
if err != nil {
|
||||
return "", fmt.Errorf("获取资产信息失败: %w", err)
|
||||
}
|
||||
|
||||
if assetResp == nil {
|
||||
return "", errors.New("资产不存在")
|
||||
}
|
||||
|
||||
// 根据售卖方式确定扣减时机
|
||||
switch assetResp.SaleMode {
|
||||
case "flash":
|
||||
return "order_create", nil // 秒杀:下单时扣减库存
|
||||
case "regular":
|
||||
return "payment_success", nil // 常规售卖:支付成功时扣减库存
|
||||
default:
|
||||
return "", errors.New("未知售卖方式")
|
||||
}
|
||||
}
|
||||
|
||||
// deductStock 扣减库存
|
||||
func (s *payment) deductStock(ctx context.Context, tenantID, orderNo, assetID string, quantity int, reason string) error {
|
||||
// 调用assets服务扣减库存
|
||||
err := s.deductStockFromAssetService(ctx, tenantID, assetID, quantity)
|
||||
if err != nil {
|
||||
return fmt.Errorf("扣减库存失败: %w", err)
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "库存扣减成功,订单:%s,资产:%s,数量:%d,原因:%s", orderNo, assetID, quantity, reason)
|
||||
return nil
|
||||
}
|
||||
|
||||
// refundStock 回充库存
|
||||
func (s *payment) refundStock(ctx context.Context, tenantID, orderNo, assetID string, quantity int, reason string) error {
|
||||
// 调用资产服务回充库存
|
||||
err := s.refundStockFromAssetService(ctx, tenantID, assetID, quantity)
|
||||
if err != nil {
|
||||
return fmt.Errorf("回充库存失败: %w", err)
|
||||
}
|
||||
|
||||
g.Log().Infof(ctx, "库存回充成功,订单:%s,资产:%s,数量:%d,原因:%s", orderNo, assetID, quantity, reason)
|
||||
return nil
|
||||
}
|
||||
|
||||
// getAssetFromAssetService 从资产服务获取资产信息
|
||||
func (s *payment) getAssetFromAssetService(ctx context.Context, tenantID, assetID string) (*AssetServiceResponse, error) {
|
||||
// 使用common/http中的封装方法调用资产服务
|
||||
// 这里应该调用assets服务的getAsset接口
|
||||
// 暂时返回模拟数据
|
||||
var assetResp AssetServiceResponse
|
||||
err := http.Get(ctx, fmt.Sprintf("http://assets-service/internal/asset/%s", assetID), &assetResp)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
return &assetResp, nil
|
||||
}
|
||||
|
||||
// deductStockFromAssetService 从资产服务扣减库存
|
||||
func (s *payment) deductStockFromAssetService(ctx context.Context, tenantID, assetID string, quantity int) error {
|
||||
// 调用assets服务的扣减库存接口
|
||||
req := map[string]interface{}{
|
||||
"asset_id": assetID,
|
||||
"quantity": quantity,
|
||||
"reason": "订单扣减",
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
err := http.Post(ctx, "http://assets-service/internal/stock/deduct", &result, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return errors.New(result.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// refundStockFromAssetService 从资产服务回充库存
|
||||
func (s *payment) refundStockFromAssetService(ctx context.Context, tenantID, assetID string, quantity int) error {
|
||||
// 调用资产服务的回充库存接口
|
||||
req := map[string]interface{}{
|
||||
"asset_id": assetID,
|
||||
"quantity": quantity,
|
||||
"reason": "订单取消回充",
|
||||
}
|
||||
|
||||
var result struct {
|
||||
Success bool `json:"success"`
|
||||
Message string `json:"message"`
|
||||
}
|
||||
|
||||
err := http.Post(ctx, "http://assets-service/internal/stock/refund", &result, req)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if !result.Success {
|
||||
return errors.New(result.Message)
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user