You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
320 lines
7.6 KiB
Go
320 lines
7.6 KiB
Go
package order
|
|
|
|
import (
|
|
"bytes"
|
|
dto "cls/internal/application/payment"
|
|
"cls/internal/domain/article"
|
|
"cls/internal/domain/column"
|
|
"cls/internal/domain/coupon"
|
|
"cls/internal/domain/order"
|
|
"cls/internal/domain/payment"
|
|
"cls/internal/domain/price"
|
|
"cls/internal/domain/user"
|
|
"cls/internal/infrastructure/payment/wechat_pay"
|
|
"cls/pkg/logger"
|
|
"errors"
|
|
"fmt"
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments/jsapi"
|
|
"time"
|
|
|
|
"github.com/wechatpay-apiv3/wechatpay-go/services/payments"
|
|
)
|
|
|
|
// OrderService 订单应用服务
|
|
type OrderService struct {
|
|
orderRepo order.OrderRepository
|
|
repo order.AggregateRepository
|
|
articleRepo article.ArticleRepository
|
|
columnRepo column.ColumnRepository
|
|
priceRepo price.PriceRepository
|
|
payService *wechat_pay.PayService
|
|
userRepo user.UserRepository
|
|
couponRepo coupon.CouponRepository
|
|
log logger.Logger
|
|
}
|
|
|
|
// NewOrderService 创建订单应用服务
|
|
func NewOrderService(repo order.AggregateRepository, articleRepo article.ArticleRepository,
|
|
priceRepo price.PriceRepository, userRepo user.UserRepository,
|
|
couponRepo coupon.CouponRepository, payService *wechat_pay.PayService,
|
|
orderRepo order.OrderRepository,
|
|
columnRepo column.ColumnRepository, log logger.New) *OrderService {
|
|
return &OrderService{
|
|
repo: repo,
|
|
articleRepo: articleRepo,
|
|
priceRepo: priceRepo,
|
|
columnRepo: columnRepo,
|
|
payService: payService,
|
|
orderRepo: orderRepo,
|
|
userRepo: userRepo,
|
|
couponRepo: couponRepo,
|
|
log: log("cls:service:order"),
|
|
}
|
|
}
|
|
|
|
// CreateOrder 创建订单
|
|
func (s *OrderService) CreateOrder(req *CreateOrderRequest, ePhone string) (*jsapi.PrepayWithRequestPaymentResponse, error) {
|
|
fmt.Println("=============")
|
|
fmt.Println(req)
|
|
uInfo, err := s.userRepo.FindByPhone(ePhone)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
if uInfo.Openid == "" {
|
|
s.log.Error(fmt.Sprintf("用户【%d】openid为空", req.UserID))
|
|
return nil, errors.New("")
|
|
}
|
|
|
|
oInfo, err := s.orderRepo.GetPendingOrder(req.TargetID, req.Type, uInfo.Id)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
if oInfo.ID > 0 {
|
|
s.log.Errorf("存在相同订单【%d】【%d】", req.TargetID, req.Type)
|
|
return nil, errors.New("存在相同订单")
|
|
}
|
|
|
|
priceInfo, err := s.priceRepo.FindByTargetID(req.TargetID, price.PriceType(req.Type))
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
fmt.Println("==============")
|
|
fmt.Printf("%+v\n", priceInfo)
|
|
fmt.Println("==============")
|
|
|
|
descripton := &bytes.Buffer{}
|
|
descripton.Write([]byte("上海路程-"))
|
|
if req.Type == order.OrderTypeArticle {
|
|
//购买文章,校验文章
|
|
req.Amount = priceInfo.Amount
|
|
descripton.Write([]byte("文章消费"))
|
|
} else {
|
|
//购买专栏,校验专栏
|
|
|
|
switch req.Duration {
|
|
case 1:
|
|
priceInfo.Amount = priceInfo.OneMonthPrice
|
|
case 3:
|
|
priceInfo.Amount = priceInfo.ThreeMonthsPrice
|
|
case 6:
|
|
priceInfo.Amount = priceInfo.SixMonthsPrice
|
|
case 12:
|
|
priceInfo.Amount = priceInfo.OneYearPrice
|
|
}
|
|
cInfo, err := s.columnRepo.FindByID(req.TargetID)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
descripton.Write([]byte(fmt.Sprintf("订购专栏【%s】%d个月", cInfo.Title, req.Duration)))
|
|
}
|
|
fmt.Println("==============")
|
|
fmt.Printf("%+v\n", req)
|
|
fmt.Println("==============")
|
|
|
|
couponInfo := &coupon.Coupon{ID: req.CouponId}
|
|
if req.CouponId != 0 {
|
|
fmt.Println("使用优惠券")
|
|
//使用优惠券
|
|
couponInfo, err = s.couponRepo.GetByID(req.CouponId)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
couponInfo.UserID = uInfo.Id
|
|
couponInfo.UsedAt = time.Now()
|
|
fmt.Printf("%+v\n", couponInfo)
|
|
if couponInfo.CanUse(req.Amount) {
|
|
fmt.Println("can use")
|
|
req.Amount = priceInfo.GetFinalAmountWitCoupon(couponInfo.Value)
|
|
} else {
|
|
fmt.Println("cann't use it")
|
|
}
|
|
|
|
couponInfo.Status = coupon.CouponStatusUsed
|
|
} else {
|
|
fmt.Println("不使用优惠券")
|
|
req.Amount = priceInfo.GetFinalAmount()
|
|
}
|
|
fmt.Printf("%+v\n", req)
|
|
|
|
if req.Amount <= 0 {
|
|
s.log.Error("价格小于0元")
|
|
return nil, errors.New("")
|
|
}
|
|
|
|
// 创建订单
|
|
o := &order.Order{
|
|
OrderNo: s.generateOrderNo(),
|
|
UserID: uInfo.Id,
|
|
TargetID: req.TargetID,
|
|
Coupon: req.CouponId,
|
|
Type: req.Type,
|
|
Amount: req.Amount,
|
|
Duration: req.Duration,
|
|
Status: order.OrderStatusPending,
|
|
Description: req.Description,
|
|
}
|
|
// 创建聚合根
|
|
aggregate := order.NewOrderAggregate(o)
|
|
err = aggregate.CreatePayment(payment.PaymentTypeWechat)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
aggregate.Coupon = couponInfo
|
|
|
|
resp, err := s.payService.CreatePayment(&wechat_pay.PaymentInfo{
|
|
Description: descripton.String(),
|
|
Attach: "",
|
|
OutTradeNo: o.OrderNo,
|
|
AmountTotal: req.Amount,
|
|
OpenId: uInfo.Openid,
|
|
})
|
|
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
// 保存聚合根
|
|
if err = s.repo.Save(aggregate); err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
return resp, nil
|
|
}
|
|
|
|
func (s *OrderService) CancelOrder(req *CreateOrderRequest, ePhone string) error {
|
|
uInfo, err := s.userRepo.FindByPhone(ePhone)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
|
|
oInfo, err := s.orderRepo.GetPendingOrder(req.TargetID, req.Type, uInfo.Id)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
|
|
if oInfo.ID < 1 {
|
|
s.log.Errorf("不存在的产品订购信息[%d][%d]", req.TargetID, req.Type)
|
|
return errors.New("")
|
|
}
|
|
|
|
agg, err := s.repo.GetByOrderNo(oInfo.OrderNo)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
|
|
err = agg.HandlePaymentFailed("H5端取消支付")
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
|
|
err = s.repo.PayFailed(agg)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
|
|
}
|
|
return err
|
|
}
|
|
|
|
func (s *OrderService) OrderNotify(transaction *payments.Transaction) error {
|
|
s.log.Info("订单回调======>")
|
|
s.log.Infof("%+v\n", *transaction)
|
|
aggregate, err := s.repo.GetByOrderNo(*transaction.OutTradeNo)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
|
|
if *transaction.Amount.Total != aggregate.Order.Amount {
|
|
err = aggregate.HandlePaymentFailed(fmt.Sprintf("订单金额不匹配 %+v", transaction))
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
err = s.repo.PayFailed(aggregate)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
if *transaction.TradeState == "SUCCESS" {
|
|
err = aggregate.HandlePaymentSuccess(*transaction.TransactionId, fmt.Sprintf("%+v", transaction))
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
err = s.repo.PaySuccess(aggregate)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
} else {
|
|
err = aggregate.HandlePaymentFailed(fmt.Sprintf("%+v", transaction))
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
err = s.repo.PayFailed(aggregate)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
// CreatePayment 创建支付订单
|
|
func (s *OrderService) CreatePayment(orderNo string, paymentType payment.PaymentType) (*dto.PaymentResponse, error) {
|
|
// 获取订单聚合根
|
|
aggregate, err := s.repo.GetByOrderNo(orderNo)
|
|
if err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
// 创建支付订单
|
|
if err := aggregate.CreatePayment(paymentType); err != nil {
|
|
return nil, err
|
|
}
|
|
|
|
// 保存聚合根
|
|
if err := s.repo.Save(aggregate); err != nil {
|
|
s.log.Error(err)
|
|
return nil, err
|
|
}
|
|
|
|
return dto.FromEntity(aggregate.Payment), nil
|
|
}
|
|
|
|
// DeleteOrder 删除订单
|
|
func (s *OrderService) DeleteOrder(id uint64) error {
|
|
if err := s.repo.Delete(id); err != nil {
|
|
s.log.Error(err)
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
// generateOrderNo 生成订单号
|
|
func (s *OrderService) generateOrderNo() string {
|
|
return fmt.Sprintf("LCPAY%d%d", time.Now().UnixNano()/1e6, time.Now().Unix()%1000)
|
|
}
|