97 lines
2.4 KiB
Go
97 lines
2.4 KiB
Go
package logic
|
|
|
|
import (
|
|
"context"
|
|
"errors"
|
|
|
|
"lone-services/pkg/modelbase"
|
|
pkgpay "lone-services/pkg/payment"
|
|
"lone-services/pkg/utils"
|
|
payment "lone-services/rpc/payment/pb"
|
|
"lone-services/services/payment/internal/channel"
|
|
"lone-services/services/payment/internal/dao"
|
|
"lone-services/services/payment/internal/model"
|
|
"lone-services/services/payment/internal/svc"
|
|
|
|
"github.com/zeromicro/go-zero/core/logx"
|
|
)
|
|
|
|
type NotifyLogic struct {
|
|
ctx context.Context
|
|
svcCtx *svc.ServiceContext
|
|
logx.Logger
|
|
}
|
|
|
|
func NewNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *NotifyLogic {
|
|
return &NotifyLogic{
|
|
ctx: ctx,
|
|
svcCtx: svcCtx,
|
|
Logger: logx.WithContext(ctx),
|
|
}
|
|
}
|
|
|
|
func (l *NotifyLogic) Notify(in *payment.NotifyReq) (*payment.Response, error) {
|
|
if in == nil || len(in.Body) == 0 {
|
|
return failResponse(utils.ErrorParams), nil
|
|
}
|
|
|
|
channelCode := resolveChannel(in.Channel)
|
|
ch, err := channel.Get(channelCode, pkgpay.ClientMiniProgram)
|
|
if err != nil {
|
|
l.Errorf("notify channel: %v", err)
|
|
return outResponse(utils.Fail, err.Error()), nil
|
|
}
|
|
|
|
result, err := ch.ParsePayNotify(l.ctx, in.Headers, in.Body)
|
|
if err != nil {
|
|
l.Errorf("notify parse: %v", err)
|
|
return outResponse(utils.Fail, err.Error()), nil
|
|
}
|
|
if result == nil || !result.Success {
|
|
return outResponse(utils.Fail, "支付未成功"), nil
|
|
}
|
|
|
|
if err := markOrderPaid(result); err != nil {
|
|
l.Errorf("notify mark paid: %v", err)
|
|
return outResponse(utils.Fail, err.Error()), nil
|
|
}
|
|
|
|
return okResponse(result), nil
|
|
}
|
|
|
|
func markOrderPaid(result *pkgpay.NotifyResult) error {
|
|
if result.OutTradeNo == utils.StringEmpty {
|
|
return errors.New("out_trade_no empty")
|
|
}
|
|
|
|
var row dao.OrderPayRow
|
|
err := model.OrderModel{}.Init().GetOne(modelbase.Params{
|
|
Eq: map[string]string{"order_sn": result.OutTradeNo},
|
|
}, &row)
|
|
if err != nil {
|
|
return err
|
|
}
|
|
if row.Id < utils.NumberOne {
|
|
return errors.New("order not found")
|
|
}
|
|
if row.Status == dao.PayStatusOk {
|
|
return nil // idempotent
|
|
}
|
|
|
|
expected := yuanToFen(row.PayPrice)
|
|
if expected > 0 && result.AmountFen > 0 && expected != result.AmountFen {
|
|
return errors.New("amount mismatch")
|
|
}
|
|
|
|
updates := map[string]any{
|
|
"status": dao.PayStatusOk,
|
|
}
|
|
if result.OutTradeNo != utils.StringEmpty {
|
|
updates["out_trade_no"] = result.OutTradeNo
|
|
}
|
|
_, err = model.OrderModel{}.Init().Edit(modelbase.Params{
|
|
Eq: map[string]string{"order_sn": result.OutTradeNo},
|
|
}, updates)
|
|
return err
|
|
}
|