199 lines
6.1 KiB
Go
199 lines
6.1 KiB
Go
package order
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"time"
|
|
|
|
"github.com/perfect-panel/server/internal/model/log"
|
|
"github.com/perfect-panel/server/internal/model/user"
|
|
"github.com/perfect-panel/server/pkg/payment/stripe"
|
|
"gorm.io/gorm"
|
|
|
|
"github.com/perfect-panel/server/internal/model/order"
|
|
"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/alipay"
|
|
)
|
|
|
|
type CloseOrderLogic struct {
|
|
logger.Logger
|
|
ctx context.Context
|
|
svcCtx *svc.ServiceContext
|
|
}
|
|
|
|
// NewCloseOrderLogic Close order
|
|
func NewCloseOrderLogic(ctx context.Context, svcCtx *svc.ServiceContext) *CloseOrderLogic {
|
|
return &CloseOrderLogic{
|
|
Logger: logger.WithContext(ctx),
|
|
ctx: ctx,
|
|
svcCtx: svcCtx,
|
|
}
|
|
}
|
|
|
|
func (l *CloseOrderLogic) CloseOrder(req *types.CloseOrderRequest) error {
|
|
// Find order information by order number
|
|
orderInfo, err := l.svcCtx.OrderModel.FindOneByOrderNo(l.ctx, req.OrderNo)
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Find order info failed",
|
|
logger.Field("error", err.Error()),
|
|
logger.Field("orderNo", req.OrderNo),
|
|
)
|
|
return nil
|
|
}
|
|
// If the order status is not 1, it means that the order has been closed or paid
|
|
if orderInfo.Status != 1 {
|
|
l.Infow("[CloseOrder] Order status is not 1",
|
|
logger.Field("orderNo", req.OrderNo),
|
|
logger.Field("status", orderInfo.Status),
|
|
)
|
|
return nil
|
|
}
|
|
err = l.svcCtx.DB.Transaction(func(tx *gorm.DB) error {
|
|
// update order status
|
|
err := tx.Model(&order.Order{}).Where("order_no = ?", req.OrderNo).Update("status", 3).Error
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Update order status failed",
|
|
logger.Field("error", err.Error()),
|
|
logger.Field("orderNo", req.OrderNo),
|
|
)
|
|
return err
|
|
}
|
|
// All orders now have associated users, no special handling needed for guest orders
|
|
// refund deduction amount to user deduction balance
|
|
if orderInfo.GiftAmount > 0 {
|
|
userInfo, err := l.svcCtx.UserModel.FindOne(l.ctx, orderInfo.UserId)
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Find user info failed",
|
|
logger.Field("error", err.Error()),
|
|
logger.Field("user_id", orderInfo.UserId),
|
|
)
|
|
return err
|
|
}
|
|
deduction := userInfo.GiftAmount + orderInfo.GiftAmount
|
|
err = tx.Model(&user.User{}).Where("id = ?", orderInfo.UserId).Update("gift_amount", deduction).Error
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Refund deduction amount failed",
|
|
logger.Field("error", err.Error()),
|
|
logger.Field("uid", orderInfo.UserId),
|
|
logger.Field("deduction", orderInfo.GiftAmount),
|
|
)
|
|
return err
|
|
}
|
|
// Record the deduction refund log
|
|
|
|
giftLog := log.Gift{
|
|
Type: log.GiftTypeIncrease,
|
|
OrderNo: orderInfo.OrderNo,
|
|
SubscribeId: 0,
|
|
Amount: orderInfo.GiftAmount,
|
|
Balance: deduction,
|
|
Remark: "Order cancellation refund",
|
|
Timestamp: time.Now().UnixMilli(),
|
|
}
|
|
content, _ := giftLog.Marshal()
|
|
|
|
err = tx.Model(&log.SystemLog{}).Create(&log.SystemLog{
|
|
Id: 0,
|
|
Type: log.TypeGift.Uint8(),
|
|
Date: time.Now().Format(time.DateOnly),
|
|
ObjectID: userInfo.Id,
|
|
Content: string(content),
|
|
}).Error
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Record cancellation refund log failed",
|
|
logger.Field("error", err.Error()),
|
|
logger.Field("uid", orderInfo.UserId),
|
|
logger.Field("deduction", orderInfo.GiftAmount),
|
|
)
|
|
return err
|
|
}
|
|
// update user cache
|
|
return l.svcCtx.UserModel.UpdateUserCache(l.ctx, userInfo)
|
|
}
|
|
return nil
|
|
})
|
|
if err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// confirmationPayment Determine whether the payment is successful
|
|
//
|
|
//nolint:unused
|
|
func (l *CloseOrderLogic) confirmationPayment(order *order.Order) bool {
|
|
paymentConfig, err := l.svcCtx.PaymentModel.FindOne(l.ctx, order.PaymentId)
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Find payment config failed", logger.Field("error", err.Error()), logger.Field("paymentMark", order.Method))
|
|
return false
|
|
}
|
|
switch order.Method {
|
|
case AlipayF2f:
|
|
if l.queryAlipay(paymentConfig, order.TradeNo) {
|
|
return true
|
|
}
|
|
case StripeAlipay:
|
|
if l.queryStripe(paymentConfig, order.TradeNo) {
|
|
return true
|
|
}
|
|
case StripeWeChatPay:
|
|
if l.queryStripe(paymentConfig, order.TradeNo) {
|
|
return true
|
|
}
|
|
default:
|
|
l.Infow("[CloseOrder] Unsupported payment method", logger.Field("paymentMethod", order.Method))
|
|
}
|
|
return false
|
|
}
|
|
|
|
// queryAlipay Query Alipay payment status
|
|
//
|
|
//nolint:unused
|
|
func (l *CloseOrderLogic) queryAlipay(paymentConfig *payment.Payment, TradeNo string) bool {
|
|
config := payment.AlipayF2FConfig{}
|
|
if err := json.Unmarshal([]byte(paymentConfig.Config), &config); err != nil {
|
|
l.Errorw("[CloseOrder] Unmarshal payment config failed", logger.Field("error", err.Error()), logger.Field("config", paymentConfig.Config))
|
|
return false
|
|
}
|
|
client := alipay.NewClient(alipay.Config{
|
|
AppId: config.AppId,
|
|
PrivateKey: config.PrivateKey,
|
|
PublicKey: config.PublicKey,
|
|
InvoiceName: config.InvoiceName,
|
|
})
|
|
status, err := client.QueryTrade(l.ctx, TradeNo)
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Query trade failed", logger.Field("error", err.Error()), logger.Field("TradeNo", TradeNo))
|
|
return false
|
|
}
|
|
if status == alipay.Success || status == alipay.Finished {
|
|
return true
|
|
}
|
|
return false
|
|
}
|
|
|
|
// queryStripe Query Stripe payment status
|
|
//
|
|
//nolint:unused
|
|
func (l *CloseOrderLogic) queryStripe(paymentConfig *payment.Payment, TradeNo string) bool {
|
|
config := payment.StripeConfig{}
|
|
if err := json.Unmarshal([]byte(paymentConfig.Config), &config); err != nil {
|
|
l.Errorw("[CloseOrder] Unmarshal payment config failed", logger.Field("error", err.Error()), logger.Field("config", paymentConfig.Config))
|
|
return false
|
|
}
|
|
client := stripe.NewClient(stripe.Config{
|
|
PublicKey: config.PublicKey,
|
|
SecretKey: config.SecretKey,
|
|
WebhookSecret: config.WebhookSecret,
|
|
})
|
|
status, err := client.QueryOrderStatus(TradeNo)
|
|
if err != nil {
|
|
l.Errorw("[CloseOrder] Query order status failed", logger.Field("error", err.Error()), logger.Field("TradeNo", TradeNo))
|
|
return false
|
|
}
|
|
return status
|
|
}
|