server/internal/logic/notify/ePayNotifyLogic.go

107 lines
3.3 KiB
Go

package notify
import (
"encoding/json"
"net/url"
"github.com/perfect-panel/server/pkg/constant"
"github.com/perfect-panel/server/pkg/xerr"
"github.com/pkg/errors"
"github.com/gin-gonic/gin"
"github.com/hibiken/asynq"
"github.com/perfect-panel/server/internal/model/payment"
"github.com/perfect-panel/server/internal/svc"
"github.com/perfect-panel/server/internal/types"
"github.com/perfect-panel/server/pkg/logger"
"github.com/perfect-panel/server/pkg/payment/epay"
queueType "github.com/perfect-panel/server/queue/types"
)
type EPayNotifyLogic struct {
logger.Logger
ctx *gin.Context
svcCtx *svc.ServiceContext
}
// EPay notify
func NewEPayNotifyLogic(ctx *gin.Context, svcCtx *svc.ServiceContext) *EPayNotifyLogic {
return &EPayNotifyLogic{
Logger: logger.WithContext(ctx),
ctx: ctx,
svcCtx: svcCtx,
}
}
func (l *EPayNotifyLogic) EPayNotify(req *types.EPayNotifyRequest) error {
// Find payment config
data, ok := l.ctx.Request.Context().Value(constant.CtxKeyPayment).(*payment.Payment)
if !ok {
l.Logger.Error("[EPayNotify] Payment not found in context")
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "payment config not found")
}
l.Infof("[EPayNotify] Payment config: %+v", data)
orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OutTradeNo)
if err != nil {
l.Logger.Error("[EPayNotify] Find order failed", logger.Field("error", err.Error()), logger.Field("orderNo", req.OutTradeNo))
return errors.Wrapf(xerr.NewErrCode(xerr.OrderNotExist), "order not exist: %v", req.OutTradeNo)
}
var config payment.EPayConfig
if err := json.Unmarshal([]byte(data.Config), &config); err != nil {
l.Logger.Errorw("[EPayNotify] Unmarshal config failed", logger.Field("error", err.Error()))
return err
}
// Verify sign
client := epay.NewClient(config.Pid, config.Url, config.Key, config.Type)
if !client.VerifySign(urlParamsToMap(l.ctx.Request.URL.RawQuery)) && !l.svcCtx.Config.Debug {
l.Logger.Error("[EPayNotify] Verify sign failed")
return nil
}
if req.TradeStatus != "TRADE_SUCCESS" {
l.Logger.Error("[EPayNotify] Trade status is not success", logger.Field("orderNo", req.OutTradeNo), logger.Field("tradeStatus", req.TradeStatus))
return nil
}
if orderInfo.Status == 5 {
return nil
}
// Update order status
err = l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, req.OutTradeNo, 2)
if err != nil {
l.Logger.Error("[EPayNotify] Update order status failed", logger.Field("error", err.Error()), logger.Field("orderNo", req.OutTradeNo))
return err
}
// Create activate order task
payload := queueType.ForthwithActivateOrderPayload{
OrderNo: req.OutTradeNo,
}
bytes, err := json.Marshal(&payload)
if err != nil {
l.Logger.Error("[EPayNotify] Marshal payload failed", logger.Field("error", err.Error()))
return err
}
task := asynq.NewTask(queueType.ForthwithActivateOrder, bytes)
taskInfo, err := l.svcCtx.Queue.EnqueueContext(l.ctx, task)
if err != nil {
l.Logger.Error("[EPayNotify] Enqueue task failed", logger.Field("error", err.Error()))
return err
}
l.Logger.Info("[EPayNotify] Enqueue task success", logger.Field("taskInfo", taskInfo))
return nil
}
func urlParamsToMap(query string) map[string]string {
params := make(map[string]string)
values, _ := url.ParseQuery(query)
for k, v := range values {
if len(v) > 0 {
params[k] = v[0]
}
}
return params
}