init: 1.0.0
This commit is contained in:
@@ -0,0 +1,96 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/constant"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/payment"
|
||||
"github.com/perfect-panel/ppanel-server/internal/svc"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/logger"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/payment/alipay"
|
||||
"github.com/perfect-panel/ppanel-server/queue/types"
|
||||
)
|
||||
|
||||
type AlipayNotifyLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// Alipay notify
|
||||
func NewAlipayNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *AlipayNotifyLogic {
|
||||
return &AlipayNotifyLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *AlipayNotifyLogic) AlipayNotify(r *http.Request) error {
|
||||
data, ok := l.ctx.Value(constant.CtxKeyPayment).(*payment.Payment)
|
||||
if !ok {
|
||||
return fmt.Errorf("payment config not found")
|
||||
}
|
||||
var config payment.AlipayF2FConfig
|
||||
if err := json.Unmarshal([]byte(data.Config), &config); err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Unmarshal config failed", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
client := alipay.NewClient(alipay.Config{
|
||||
AppId: config.AppId,
|
||||
PrivateKey: config.PrivateKey,
|
||||
PublicKey: config.PublicKey,
|
||||
InvoiceName: config.InvoiceName,
|
||||
NotifyURL: data.Domain + "/v1/payment/alipay/notify",
|
||||
})
|
||||
notify, err := client.DecodeNotification(r.Form)
|
||||
if err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Decode notification failed", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
if notify.Status == alipay.Success {
|
||||
orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, notify.OrderNo)
|
||||
if err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Find order failed", logger.Field("error", err.Error()), logger.Field("orderNo", notify.OrderNo))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.OrderNotExist), "order not exist: %v", notify.OrderNo)
|
||||
}
|
||||
|
||||
if orderInfo.Status == 5 {
|
||||
return nil
|
||||
}
|
||||
|
||||
// Update order status
|
||||
err = l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, notify.OrderNo, 2)
|
||||
if err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Update order status failed", logger.Field("error", err.Error()), logger.Field("orderNo", notify.OrderNo))
|
||||
return err
|
||||
}
|
||||
l.Logger.Info("[AlipayNotify] Notify status success", logger.Field("orderNo", notify.OrderNo))
|
||||
payload := types.ForthwithActivateOrderPayload{
|
||||
OrderNo: notify.OrderNo,
|
||||
}
|
||||
bytes, err := json.Marshal(&payload)
|
||||
if err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Marshal payload failed", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
task := asynq.NewTask(types.ForthwithActivateOrder, bytes)
|
||||
taskInfo, err := l.svcCtx.Queue.EnqueueContext(l.ctx, task)
|
||||
if err != nil {
|
||||
l.Logger.Error("[AlipayNotify] Enqueue task failed", logger.Field("error", err.Error()))
|
||||
return err
|
||||
}
|
||||
l.Logger.Info("[AlipayNotify] Enqueue task success", logger.Field("taskInfo", taskInfo))
|
||||
} else {
|
||||
l.Logger.Error("[AlipayNotify] Notify status failed", logger.Field("status", string(notify.Status)))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
@@ -0,0 +1,106 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"net/url"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/constant"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/gin-gonic/gin"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/payment"
|
||||
"github.com/perfect-panel/ppanel-server/internal/svc"
|
||||
"github.com/perfect-panel/ppanel-server/internal/types"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/logger"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/payment/epay"
|
||||
|
||||
queueType "github.com/perfect-panel/ppanel-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)
|
||||
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
|
||||
}
|
||||
@@ -0,0 +1,97 @@
|
||||
package notify
|
||||
|
||||
import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"io"
|
||||
"net/http"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/constant"
|
||||
|
||||
"github.com/perfect-panel/ppanel-server/pkg/xerr"
|
||||
"github.com/pkg/errors"
|
||||
|
||||
"github.com/hibiken/asynq"
|
||||
"github.com/perfect-panel/ppanel-server/internal/model/payment"
|
||||
"github.com/perfect-panel/ppanel-server/internal/svc"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/logger"
|
||||
"github.com/perfect-panel/ppanel-server/pkg/payment/stripe"
|
||||
"github.com/perfect-panel/ppanel-server/queue/types"
|
||||
)
|
||||
|
||||
type StripeNotifyLogic struct {
|
||||
logger.Logger
|
||||
ctx context.Context
|
||||
svcCtx *svc.ServiceContext
|
||||
}
|
||||
|
||||
// NewStripeNotifyLogic Stripe notify
|
||||
func NewStripeNotifyLogic(ctx context.Context, svcCtx *svc.ServiceContext) *StripeNotifyLogic {
|
||||
return &StripeNotifyLogic{
|
||||
Logger: logger.WithContext(ctx),
|
||||
ctx: ctx,
|
||||
svcCtx: svcCtx,
|
||||
}
|
||||
}
|
||||
|
||||
func (l *StripeNotifyLogic) StripeNotify(r *http.Request, w http.ResponseWriter) error {
|
||||
const MaxBodyBytes = int64(65536)
|
||||
r.Body = http.MaxBytesReader(w, r.Body, MaxBodyBytes)
|
||||
payload, err := io.ReadAll(r.Body)
|
||||
if err != nil {
|
||||
l.Errorw("[StripeNotify] error", logger.Field("errors", err.Error()))
|
||||
return err
|
||||
}
|
||||
signature := r.Header.Get("Stripe-Signature")
|
||||
stripeConfig, ok := l.ctx.Value(constant.CtxKeyPayment).(*payment.Payment)
|
||||
if !ok {
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "payment config not found")
|
||||
}
|
||||
config := payment.StripeConfig{}
|
||||
if err := json.Unmarshal([]byte(stripeConfig.Config), &config); err != nil {
|
||||
return err
|
||||
}
|
||||
client := stripe.NewClient(stripe.Config{
|
||||
PublicKey: config.PublicKey,
|
||||
SecretKey: config.SecretKey,
|
||||
WebhookSecret: config.WebhookSecret,
|
||||
})
|
||||
|
||||
notify, err := client.ParseNotify(payload, signature)
|
||||
if err != nil {
|
||||
l.Errorw("[StripeNotify] error", logger.Field("errors", err.Error()))
|
||||
return err
|
||||
}
|
||||
orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, notify.OrderNo)
|
||||
if err != nil {
|
||||
l.Logger.Error("[StripeNotify] Find order failed", logger.Field("error", err.Error()), logger.Field("orderNo", notify.OrderNo))
|
||||
return errors.Wrapf(xerr.NewErrCode(xerr.OrderNotExist), "order not exist: %v", notify.OrderNo)
|
||||
}
|
||||
if notify.EventType == "payment_intent.succeeded" {
|
||||
if orderInfo.Status == 5 {
|
||||
return nil
|
||||
}
|
||||
// update order status
|
||||
err = l.svcCtx.OrderModel.UpdateOrderStatus(l.ctx, notify.OrderNo, 2)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// create ActivateOrder task
|
||||
payload := types.ForthwithActivateOrderPayload{
|
||||
OrderNo: notify.OrderNo,
|
||||
}
|
||||
bytes, err := json.Marshal(payload)
|
||||
if err != nil {
|
||||
l.Errorw("[StripeNotify] Marshal error", logger.Field("errors", err.Error()), logger.Field("payload", payload))
|
||||
return err
|
||||
}
|
||||
task := asynq.NewTask(types.ForthwithActivateOrder, bytes)
|
||||
_, err = l.svcCtx.Queue.Enqueue(task)
|
||||
if err != nil {
|
||||
l.Errorw("[StripeNotify] Enqueue error", logger.Field("errors", err.Error()))
|
||||
return err
|
||||
}
|
||||
l.Infow("[StripeNotify] success", logger.Field("orderNo", notify.OrderNo))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
Reference in New Issue
Block a user