package repositories import ( "context" "encoding/json" "errors" "fmt" "fusenapi/constants" "fusenapi/model/gmodel" "fusenapi/utils/basic" "fusenapi/utils/fssql" "fusenapi/utils/handlers" "fusenapi/utils/order" "fusenapi/utils/pay" "time" "github.com/aws/aws-sdk-go/aws/session" "github.com/zeromicro/go-zero/core/logx" "gorm.io/gorm" ) func NewOrder(gormDB *gorm.DB, bLMServiceUrl *string, awsSession *session.Session) Order { return &defaultOrder{ MysqlConn: gormDB, } } type ( defaultOrder struct { MysqlConn *gorm.DB } Order interface { // 下单 Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error) // 预支付--定金 CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) // 预支付--定金 CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error) // 列表 List(ctx context.Context, in *ListReq) (res *ListRes, err error) // 详情 Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) } OrderAddress struct { Address string `json:"address"` // 详细地址 Mobile string `json:"mobile"` // 手机 Name string `json:"name"` // 姓名 } OrderPay struct { ClientSecret string `json:"client_secret"` // 支付方--秘钥 Country string `json:"country"` // 国家 Currency string `json:"currency"` // 货币 Metadata map[string]interface{} `json:"metadata"` // 额外参数 Method string `json:"method"` // 支付方--途径 OrderSn string `json:"order_sn"` // 订单编码 PayStage int64 `json:"pay_stage"` // 支付阶段 RedirectURL *string `json:"redirect_url"` // 支付方--重定向地址 Total OrderPayTotal `json:"total"` // 支付参数 } // 支付参数 OrderPayTotal struct { Amount int64 `json:"amount"` // 金额 Label string `json:"label"` // 标签 } /* 预支付--定金 */ CreatePrePaymentByDepositReq struct { StripeKey string `json:"stripe_key"` Currency string `json:"currency"` Country string `json:"country"` UserId int64 `json:"user_id"` OrderSn string `json:"order_sn"` DeliveryMethod int64 `json:"delivery_method"` DeliveryAddress *OrderAddress `json:"delivery_address"` } CreatePrePaymentByDepositRes struct { ErrorCode basic.StatusResponse OrderDetail gmodel.OrderDetail OrderPay OrderPay } /* 预支付--定金 */ /* 预支付--尾款 */ CreatePrePaymentByBalanceReq struct { StripeKey string `json:"stripe_key"` Currency string `json:"currency"` Country string `json:"country"` UserId int64 `json:"user_id"` OrderSn string `json:"order_sn"` } CreatePrePaymentByBalanceRes struct { ErrorCode basic.StatusResponse OrderDetail gmodel.OrderDetail OrderPay OrderPay } /* 预支付--尾款 */ /* 下单 */ CreateReq struct { ExpectedDeliveryTime time.Time `json:"expected_delivery_time"` // 预计到货时间 ExchangeRate int64 `json:"exchange_rate"` // 换算汇率(厘) CurrentCurrency string `json:"current_currency"` // 当前货币 OriginalCurrency string `json:"original_currency"` // 原始货币 UserId int64 `json:"user_id"` CartIds []int64 `json:"cart_ids"` DeliveryMethod int64 `json:"delivery_method"` DeliveryAddress *OrderAddress `json:"delivery_address"` // 收货地址 } CreateRes struct { ErrorCode basic.StatusResponse OrderSn string } /* 下单 */ /* 详情 */ DetailReq struct { UserId int64 `json:"user_id"` OrderSn string `json:"order_sn"` } DetailRes struct { ErrorCode basic.StatusResponse OrderDetail gmodel.OrderDetail OrderDetailOriginal gmodel.OrderDetail } /* 详情 */ /* 列表 */ ListReq struct { UserId int64 `json:"user_id"` DeliveryMethod int64 `json:"delivery_method"` OrderCycle string `json:"order_cycle"` CurrentPage int64 `json:"current_page"` PerPage int64 `json:"per_page"` } ListRes struct { OrderDetailList []gmodel.OrderDetail Meta interface{} } /* 列表 */ ) // 预支付--尾款 func (d *defaultOrder) CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error) { var errorCode basic.StatusResponse var order gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&order) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logx.Errorf("create prePayment balance failed, err: %v", err) return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, result.Error } // 非未支付 if *order.PayStatus != int64(constants.ORDERPAYSTATUSPAIDDEPOSIT) { errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid err = errors.New("order balance pay status is not unPaid") logx.Errorf("create prePayment balance failed, err: %v", err) return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, err } ress, err := d.OrderDetailHandler(ctx, &order) if err != nil { logx.Errorf("create prePayment balance failed DetailOrderDetailHandler, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, err } // 支付初始化 amount := int64(ress.OrderDetailOriginal.OrderAmount.RemainingBalance.PayAmount.Current.CurrentAmount.(float64) / float64(10)) payConfig := &pay.Config{} payConfig.Stripe.PayType = "intent" payConfig.Stripe.Key = in.StripeKey var generatePrepaymentReq = &pay.GeneratePrepaymentReq{ OrderSn: in.OrderSn, ProductName: "支付尾款后期统一调整", Amount: amount, Currency: "usd", Quantity: 1, ProductDescription: "支付尾款后期统一调整", } payDriver := pay.NewPayDriver(1, payConfig) prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq) if err != nil { logx.Errorf("create prePayment balance failed GeneratePrepayment, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, nil } return &CreatePrePaymentByBalanceRes{ OrderDetail: ress.OrderDetail, OrderPay: OrderPay{ ClientSecret: prepaymentRes.ClientSecret, Country: in.Country, Currency: in.Currency, Method: payConfig.Stripe.PayType, OrderSn: in.OrderSn, PayStage: 1, Total: OrderPayTotal{ Amount: amount, Label: "支付尾款后期统一调整", }, }, }, nil } // 预支付--定金 func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) { var errorCode basic.StatusResponse var order gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&order) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logx.Errorf("create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, result.Error } // 非未支付 if *order.PayStatus != int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT) { errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid err = errors.New("order pay status is not unPaidDeposit") logx.Errorf("create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } // 是否超时支付 ntime := time.Now().UTC() ctime := *order.Ctime ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix() ntimeTimeOut := ntime.Unix() // 测试超时支付不限制 if ctimeTimeOut == ntimeTimeOut { errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout err = errors.New("order pay timeout") logx.Errorf("create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } ress, err := d.OrderDetailHandler(ctx, &order) if err != nil { logx.Errorf("create prePayment deposit failed DetailOrderDetailHandler, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } var uOrderDetail = make(map[string]interface{}) var orderAddress *gmodel.OrderAddress if in.DeliveryAddress != nil { if in.DeliveryAddress.Name != ress.OrderDetailOriginal.DeliveryAddress.Name || in.DeliveryAddress.Address != ress.OrderDetail.DeliveryAddress.Address || in.DeliveryAddress.Mobile != ress.OrderDetail.DeliveryAddress.Mobile { orderAddress = &gmodel.OrderAddress{ Name: in.DeliveryAddress.Name, Mobile: in.DeliveryAddress.Mobile, Address: in.DeliveryAddress.Address, } } } var sql string = fmt.Sprintf(", `utime` = '%s'", ntime) // 是否更新 if in.DeliveryMethod != *order.DeliveryMethod { sql = sql + fmt.Sprintf(",`delivery_method` = %d", in.DeliveryMethod) if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { uOrderDetail["delivery_address"] = orderAddress } else { uOrderDetail["delivery_address"] = nil } uOrderDetail["order_info"] = struct { DeliveryMethod int64 `json:"delivery_method"` Utime *time.Time `json:"utime"` }{ DeliveryMethod: in.DeliveryMethod, Utime: &ntime, } } else { if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { // 更新收货地址 if orderAddress != nil { uOrderDetail["delivery_address"] = orderAddress uOrderDetail["order_info"] = struct { DeliveryMethod int64 `json:"delivery_method"` Utime *time.Time `json:"utime"` }{ DeliveryMethod: in.DeliveryMethod, Utime: &ntime, } } } } if len(uOrderDetail) > 0 { err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, in.OrderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", order.Id) if err != nil { errorCode = *basic.CodeServiceErr logx.Errorf("create prePayment deposit failed MetadataOrderPATCH, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, result.Error } } ress.OrderDetail.OrderInfo.Utime = &ntime ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod ress.OrderDetail.DeliveryAddress = orderAddress // 支付初始化 amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10)) payConfig := &pay.Config{} payConfig.Stripe.PayType = "intent" payConfig.Stripe.Key = in.StripeKey var generatePrepaymentReq = &pay.GeneratePrepaymentReq{ OrderSn: in.OrderSn, ProductName: "支付首款", Amount: amount, Currency: "usd", Quantity: 1, ProductDescription: "支付首款", } payDriver := pay.NewPayDriver(1, payConfig) prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq) if err != nil { logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, nil } return &CreatePrePaymentByDepositRes{ OrderDetail: ress.OrderDetail, OrderPay: OrderPay{ ClientSecret: prepaymentRes.ClientSecret, Country: in.Country, Currency: in.Currency, Method: payConfig.Stripe.PayType, OrderSn: in.OrderSn, PayStage: 1, Total: OrderPayTotal{ Amount: amount, Label: "", }, }, }, nil } // 列表 func (d *defaultOrder) List(ctx context.Context, in *ListReq) (res *ListRes, err error) { var orderList []gmodel.FsOrder model := d.MysqlConn.Model(&gmodel.FsOrder{}).Where("is_del = ?", 0) if in.UserId != 0 { model.Where("user_id = ?", in.UserId) } // Where("pay_status > ?", 0) if in.DeliveryMethod != 0 { model.Where("delivery_method = ?", in.DeliveryMethod) } if in.OrderCycle != "" { // 下单时间 switch in.OrderCycle { case "within_one_month": model.Where("ctime >?", time.Now().UTC().AddDate(0, -1, 0).Unix()) case "within_three_month": model.Where("ctime >?", time.Now().UTC().AddDate(0, -3, 0).Unix()) case "within_six_month": model.Where("ctime >?", time.Now().UTC().AddDate(0, -6, 0).Unix()) case "within_one_year": model.Where("ctime >?", time.Now().UTC().AddDate(-1, 0, 0).Unix()) } } var count int64 resultCount := model.Count(&count) if resultCount.Error != nil { logx.Errorf("order count failed, err: %v", err) return nil, resultCount.Error } var orderDetailList []gmodel.OrderDetail if count > 0 { m := model.Scopes(handlers.Paginate(&in.CurrentPage, &in.PerPage)) result := m.Find(&orderList) if result.Error != nil { logx.Errorf("order list failed, err: %v", err) return nil, result.Error } for _, order := range orderList { ress, err := d.OrderDetailHandler(ctx, &order) if err != nil { return nil, err } orderDetailList = append(orderDetailList, ress.OrderDetail) } } else { orderDetailList = make([]gmodel.OrderDetail, 0) } return &ListRes{ OrderDetailList: orderDetailList, Meta: map[string]int64{ "total_count": count, "page_count": count / in.PerPage, "current_page": in.CurrentPage, "per_page": in.PerPage, }, }, nil } // 详情 func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) { var errorCode basic.StatusResponse var order gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&order) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logx.Errorf("order detail failed, err: %v", err) return &DetailRes{ ErrorCode: errorCode, }, result.Error } // 是否超时支付 ctime := *order.Ctime ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix() ntimeTimeOut := time.Now().UTC().Unix() if ctimeTimeOut < ntimeTimeOut { errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout err = errors.New("order pay timeout") logx.Errorf("order detail failed, err: %v", err) return &DetailRes{ ErrorCode: errorCode, }, err } ress, err := d.OrderDetailHandler(ctx, &order) if err != nil { logx.Errorf("order detail failed, err: %v", err) errorCode = *basic.CodeServiceErr return &DetailRes{ ErrorCode: errorCode, }, err } return &DetailRes{ ErrorCode: errorCode, OrderDetail: ress.OrderDetail, }, nil } // 下单 func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error) { var errorCode basic.StatusResponse // 订单编号 var orderSn string = order.GenerateOrderNumber() err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error { // 查询购物车 var shoppingCartList []*gmodel.RelaFsShoppingCart resShoppingCartFind := tx.Table(gmodel.NewFsShoppingCartModel(tx).TableName()). Preload("ShoppingCartProduct", func(dbPreload *gorm.DB) *gorm.DB { return dbPreload.Table(gmodel.NewFsProductModel(tx).TableName()).Preload("CoverResource") }).Preload("ShoppingCartProductPriceList"). Preload("ShoppingCartProductModel3dList"). Preload("ShoppingCartProductModel3dFitting"). Where("id IN ?", in.CartIds). Where("user_id = ?", in.UserId). Find(&shoppingCartList) err = resShoppingCartFind.Error if err != nil { return err } shoppingCartListLen := len(shoppingCartList) if shoppingCartListLen == 0 { errorCode = *basic.CodeErrOrderCreatShoppingCartEmpty return errors.New(errorCode.Message) } if shoppingCartListLen != len(in.CartIds) { errorCode = *basic.CodeErrOrderCreatShoppingCartNotMatched return errors.New(errorCode.Message) } // 订单商品列表 var orderProductList []gmodel.OrderProduct var shippingFee gmodel.AmountInfo // 订单税费总价(厘) var shippingFeeTotal int64 var tax = gmodel.AmountInfo{} // 订单邮费总价(厘) var taxTotal int64 var discount gmodel.AmountInfo // 订单折扣总价(厘) var discountTotal int64 var subtotal gmodel.AmountInfo // 订单商品总价(厘) var orderProductTotal int64 var total gmodel.AmountInfo // 订单总价(厘) var orderTotal int64 var nowTime = time.Now().UTC() // 收货地址 var orderAddress *gmodel.OrderAddress // 支付状态 var payStatus = constants.ORDERPAYSTATUSUNPAIDDEPOSIT // 直邮 if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { orderAddress = &gmodel.OrderAddress{ Mobile: in.DeliveryAddress.Mobile, Name: in.DeliveryAddress.Name, } } for _, shoppingCart := range shoppingCartList { // 购物车快照 var shoppingCartSnapshot gmodel.CartSnapshot // 购物车商品价格 var shoppingCartProductPrice *gmodel.FsProductPrice // 购物车商品模型 var shoppingCartProductModel3d *gmodel.FsProductModel3d if shoppingCart.Snapshot != nil { json.Unmarshal([]byte(*shoppingCart.Snapshot), &shoppingCartSnapshot) } // 商品异常 if shoppingCart.ShoppingCartProduct == nil || (shoppingCart.ShoppingCartProduct != nil && *shoppingCart.ShoppingCartProduct.IsShelf == 0) { errorCode = *basic.CodeErrOrderCreatProductAbsent errorCode.Message = "create order failed, product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" return errors.New(errorCode.Message) } // 商品价格异常 if len(shoppingCart.ShoppingCartProductPriceList) == 0 { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" return errors.New(errorCode.Message) } else { var isProductPrice bool for _, shoppingCartProductPriceInfo := range shoppingCart.ShoppingCartProductPriceList { if *shoppingCart.SizeId == *shoppingCartProductPriceInfo.SizeId { shoppingCartProductPrice = shoppingCartProductPriceInfo isProductPrice = true break } } if !isProductPrice { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" return errors.New(errorCode.Message) } shoppingCart.ShoppingCartProductPriceList = []*gmodel.FsProductPrice{shoppingCartProductPrice} } // 商品模型异常 if len(shoppingCart.ShoppingCartProductModel3dList) == 0 { errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent errorCode.Message = "create order failed, accessoryof product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" return errors.New(errorCode.Message) } else { var isProductModel bool for _, shoppingCartProductModel3dInfo := range shoppingCart.ShoppingCartProductModel3dList { if *shoppingCart.SizeId == *shoppingCartProductModel3dInfo.SizeId { shoppingCartProductModel3d = shoppingCartProductModel3dInfo isProductModel = true break } } if !isProductModel { errorCode = *basic.CodeErrOrderCreatProductAccessoryAbsent errorCode.Message = "create order failed, accessory of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is absent" return errors.New(errorCode.Message) } shoppingCart.ShoppingCartProductModel3dList = []*gmodel.FsProductModel3d{shoppingCartProductModel3d} } var stepNum []int var stepPrice []int if *shoppingCartProductPrice.StepNum == "" { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, step num of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" return errors.New(errorCode.Message) } else { json.Unmarshal([]byte(*shoppingCartProductPrice.StepNum), &stepNum) } if *shoppingCartProductPrice.StepPrice == "" { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" return errors.New(errorCode.Message) } else { json.Unmarshal([]byte(*shoppingCartProductPrice.StepPrice), &stepPrice) } /* 计算价格 */ productPrice, productTotalPrice, stepNum, stepPrice, err := NewShoppingCart(tx, nil, nil).CaculateCartPrice(*shoppingCart.PurchaseQuantity, shoppingCartProductPrice, *shoppingCart.ShoppingCartProductModel3dFitting.Price) if err != nil { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" return err } /* 计算价格 */ // 订单商品总价(厘) orderProductTotal = orderProductTotal + productTotalPrice // 订单商品 var productCoverMetadata map[string]interface{} if shoppingCart.ShoppingCartProduct.CoverResource != nil && shoppingCart.ShoppingCartProduct.CoverResource.Metadata != nil { json.Unmarshal(*shoppingCart.ShoppingCartProduct.CoverResource.Metadata, &productCoverMetadata) } orderProductList = append(orderProductList, gmodel.OrderProduct{ TotalPrice: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: productTotalPrice, Current: productTotalPrice, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), ExpectedDeliveryTime: &in.ExpectedDeliveryTime, PurchaseQuantity: *shoppingCart.PurchaseQuantity, ProductID: *shoppingCart.ProductId, ProductCover: *shoppingCart.ShoppingCartProduct.Cover, ProductCoverMetadata: productCoverMetadata, ProductName: *shoppingCart.ShoppingCartProduct.Title, ItemPrice: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: productPrice, Current: productPrice, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), ProductSnapshot: shoppingCart.ShoppingCartProduct, ShoppingCartSnapshot: &shoppingCart.FsShoppingCart, ProductSn: *shoppingCart.ShoppingCartProduct.Sn, DiyInformation: &shoppingCartSnapshot.UserDiyInformation, FittingInfo: &gmodel.OrderProductFittingInfo{ FittingID: *shoppingCart.FittingId, FittingName: shoppingCartSnapshot.FittingInfo.FittingName, }, SizeInfo: &gmodel.OrderProductSizeInfo{ SizeID: *shoppingCart.SizeId, Capacity: shoppingCartSnapshot.SizeInfo.Capacity, Title: gmodel.OrderProductSizeInfoTitle{ Inch: shoppingCartSnapshot.SizeInfo.Inch, Cm: shoppingCartSnapshot.SizeInfo.Cm, }, }, StepNum: stepNum, IsHighlyCustomized: *shoppingCart.IsHighlyCustomized, }) } subtotal = order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: orderProductTotal, Current: orderProductTotal, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }) orderTotal = orderProductTotal + shippingFeeTotal + taxTotal - discountTotal total = order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: orderTotal, Current: orderTotal, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }) // 定金 var depositInt int64 = orderTotal / 2 var deposit = gmodel.PayInfo{ Status: gmodel.PayStatus{ StatusCode: int64(constants.PAYSTATUSUNPAID), StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID], }, PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: depositInt, Current: depositInt, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), } // 尾款 var remainingBalanceInt int64 = orderTotal - depositInt var remainingBalance = gmodel.PayInfo{ Status: gmodel.PayStatus{ StatusCode: int64(constants.PAYSTATUSUNPAID), StatusTitle: constants.PayStatusMessage[constants.PAYSTATUSUNPAID], }, PayAmount: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: remainingBalanceInt, Current: remainingBalanceInt, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), } var orderAmount = gmodel.OrderAmount{ Deposit: deposit, RemainingBalance: remainingBalance, Discount: discount, ShippingFee: shippingFee, Tax: tax, Subtotal: subtotal, Total: total, } // 订单状态--当前 var status = gmodel.OrderStatus{ Ctime: &nowTime, Utime: &nowTime, StatusCode: constants.ORDERSTATUSUNPAIDDEPOSIT, StatusTitle: constants.OrderStatusMessage[constants.ORDERSTATUSUNPAIDDEPOSIT], } // 订单状态--链路 var statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, nowTime, in.ExpectedDeliveryTime) var orderInfo = gmodel.OrderInfo{ Ctime: &nowTime, DeliveryMethod: in.DeliveryMethod, OrderSn: orderSn, Status: status, StatusLink: statusLink, } var orderDetail = gmodel.OrderDetail{ DeliveryAddress: orderAddress, OrderAmount: orderAmount, OrderInfo: orderInfo, OrderProduct: orderProductList, PayStatus: payStatus, PayTimeout: 30 * time.Minute, } // 数据库操作 orderDetailByte, err := json.Marshal(orderDetail) if err != nil { return err } var order = gmodel.FsOrder{ UserId: &in.UserId, DeliveryMethod: &in.DeliveryMethod, OrderSn: &orderSn, Status: (*int64)(&status.StatusCode), PayStatus: (*int64)(&payStatus), Ctime: &nowTime, Metadata: &orderDetailByte, } result := tx.Create(&order) if result.Error != nil { return result.Error } return nil }) if err != nil { logx.Errorf("order create order failed, err: %v", err) if errorCode.Code == 0 { errorCode.Code = basic.CodeApiErr.Code errorCode.Message = basic.CodeApiErr.Message } return &CreateRes{ OrderSn: orderSn, ErrorCode: errorCode, }, err } return &CreateRes{ OrderSn: orderSn, ErrorCode: errorCode, }, nil } // 详情处理 func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder) (res *DetailRes, err error) { var orderDetail gmodel.OrderDetail err = json.Unmarshal(*orderInfo.Metadata, &orderDetail) if err != nil { logx.Errorf("order detail handler unmarshal metadata failed, err: %v", err) return nil, err } orderDetailOriginal := orderDetail for orderProductKey, orderProduct := range orderDetail.OrderProduct { orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice) orderDetail.OrderProduct[orderProductKey].ItemPrice = order.GetAmountInfoFormat(&orderProduct.ItemPrice) orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot = nil orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil } orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink) orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount) orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.RemainingBalance.PayAmount) orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal) orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total) orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix()) return &DetailRes{ OrderDetail: orderDetail, OrderDetailOriginal: orderDetailOriginal, }, nil }