107 lines
3.3 KiB
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
|
|
}
|