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/run_log" "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 runLog run_log.RunLogRepository 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, runLog run_log.RunLogRepository, columnRepo column.ColumnRepository, log logger.New) *OrderService { return &OrderService{ repo: repo, articleRepo: articleRepo, priceRepo: priceRepo, columnRepo: columnRepo, payService: payService, runLog: runLog, 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))) } 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(priceInfo.GetFinalAmount()) { fmt.Println("can use") req.Amount = priceInfo.GetFinalAmountWitCoupon(couponInfo.Value) couponInfo.Status = coupon.CouponStatusUsed } else { fmt.Println("cann't use it") } } 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, Type: req.Type, Amount: req.Amount, Duration: req.Duration, Status: order.OrderStatusPending, Description: req.Description, } s.runLog.LogOrderInfo(o.OrderNo, fmt.Sprintf("%+v", o)) // 创建聚合根 aggregate := order.NewOrderAggregate(o) err = aggregate.CreatePayment(payment.PaymentTypeWechat) if err != nil { s.runLog.LogOrderInfo(o.OrderNo, err.Error(), "创建支付订单") s.log.Error(err) return nil, err } if couponInfo.Status == coupon.CouponStatusUsed { aggregate.Coupon = couponInfo o.Coupon = req.CouponId } pInfo := &wechat_pay.PaymentInfo{ Description: descripton.String(), Attach: "", OutTradeNo: o.OrderNo, AmountTotal: req.Amount, OpenId: uInfo.Openid, } s.runLog.LogOrderInfo(o.OrderNo, fmt.Sprintf("%+v", pInfo)) resp, err := s.payService.CreatePayment(pInfo) if err != nil { s.runLog.LogOrderInfo(o.OrderNo, err.Error(), "创建WX支付订单") s.log.Error(err) return nil, err } s.runLog.LogOrderInfo(o.OrderNo, fmt.Sprintf("%+v", resp)) // 保存聚合根 if err = s.repo.Save(aggregate); err != nil { s.runLog.LogOrderInfo(o.OrderNo, err.Error(), "保存订单") 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.runLog.LogOrderInfo(oInfo.OrderNo, err.Error(), "GetByOrderNo") s.log.Error(err) return err } err = agg.HandlePaymentFailed("H5端取消支付") if err != nil { s.runLog.LogOrderInfo(oInfo.OrderNo, err.Error(), "HandlePaymentFailed") s.log.Error(err) return err } err = s.repo.PayFailed(agg) if err != nil { s.runLog.LogOrderInfo(oInfo.OrderNo, err.Error(), "PayFailed") s.log.Error(err) } return err } func (s *OrderService) OrderNotify(transaction *payments.Transaction) error { s.runLog.LogOrderInfo(*transaction.OutTradeNo, fmt.Sprintf("%+v", *transaction)) aggregate, err := s.repo.GetByOrderNo(*transaction.OutTradeNo) if err != nil { s.runLog.LogOrderInfo(*transaction.OutTradeNo, err.Error(), "GetByOrderNo") s.log.Error(err) return err } s.runLog.LogOrderInfo(aggregate.Order.OrderNo, fmt.Sprintf("%+v", transaction)) if *transaction.Amount.Total != aggregate.Order.Amount { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, "订单金额不匹配") err = aggregate.HandlePaymentFailed(fmt.Sprintf("订单金额不匹配 %+v", transaction)) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "HandlePaymentFailed") s.log.Error(err) return err } err = s.repo.PayFailed(aggregate) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "PayFailed") s.log.Error(err) return err } } if *transaction.TradeState == "SUCCESS" { err = aggregate.HandlePaymentSuccess(*transaction.TransactionId, fmt.Sprintf("%+v", transaction)) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "HandlePaymentSuccess") s.log.Error(err) return err } err = s.repo.PaySuccess(aggregate) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "PaySuccess") s.log.Error(err) return err } } else { err = aggregate.HandlePaymentFailed(fmt.Sprintf("%+v", transaction)) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "HandlePaymentFailed") s.log.Error(err) return err } err = s.repo.PayFailed(aggregate) if err != nil { s.runLog.LogOrderInfo(aggregate.Order.OrderNo, err.Error(), "PayFailed") 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) }