package repositories import ( "context" "encoding/json" "errors" "fmt" "fusenapi/constants" "fusenapi/model/gmodel" "fusenapi/utils/basic" "fusenapi/utils/format" "fusenapi/utils/order" "fusenapi/utils/step_price" "math" "strings" "time" "github.com/aws/aws-sdk-go/aws/session" "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) // 预支付 // 列表 // 详情 } OrderAddress struct { Address string `json:"address"` // 详细地址 Mobile string `json:"mobile"` // 手机 Name string `json:"name"` // 姓名 } /* 下单 */ 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 } /* 下单 */ ) // 下单 func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error) { var errorCode basic.StatusResponse // 订单编号 var orderSn string = order.GenerateOrderNumber(int(in.DeliveryMethod), int(in.UserId)) err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error { // 查询购物车 var shoppingCartList []*gmodel.RelaFsShoppingCart resShoppingCartFind := tx.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) } /* 计算价格 */ //阶梯数量切片 stepNum, err := format.StrSlicToIntSlice(strings.Split(*shoppingCartProductPrice.StepNum, ",")) if err != nil { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = fmt.Sprintf("failed to parse step number:%d_%d", *shoppingCart.ProductId, *shoppingCart.SizeId) return errors.New(errorCode.Message) } lenStepNum := len(stepNum) //阶梯价格切片 stepPrice, err = format.StrSlicToIntSlice(strings.Split(*shoppingCartProductPrice.StepPrice, ",")) if err != nil { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = fmt.Sprintf("failed to parse step price:%d_%d", *shoppingCart.ProductId, *shoppingCart.SizeId) return errors.New(errorCode.Message) } lenStepPrice := len(stepPrice) if lenStepPrice == 0 || lenStepNum == 0 { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = fmt.Sprintf("step price or step number is not set:%d_%d", *shoppingCart.ProductId, *shoppingCart.SizeId) return errors.New(errorCode.Message) } // 购买数量 reqPurchaseQuantity := *shoppingCart.PurchaseQuantity // 购买箱数 boxQuantity := int(math.Ceil(float64(reqPurchaseQuantity) / float64(*shoppingCartProductPrice.EachBoxNum))) // 根据数量获取阶梯价格中对应的价格 productPrice := step_price.GetCentStepPrice(boxQuantity, stepNum, stepPrice) // 如果有配件,单价也要加入配件价格 if *shoppingCart.FittingId > 0 { if shoppingCart.ShoppingCartProductModel3dFitting != nil { productPrice = productPrice + *shoppingCart.ShoppingCartProductModel3dFitting.Price } } // 单个购物车总价(厘) productTotalPrice := productPrice * reqPurchaseQuantity /* 计算价格 */ // 订单商品总价(厘) orderProductTotal = orderProductTotal + productTotalPrice // 订单商品 var productSnapshot = make(map[string]interface{}, 1) productSnapshot["product_snapshot"] = shoppingCart.ShoppingCartProduct 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: productSnapshot, ShoppingCartSnapshot: &shoppingCart.FsShoppingCart, ProductSn: *shoppingCart.ShoppingCartProduct.Sn, DiyInformation: &shoppingCartSnapshot.UserDiyInformation, FittingInfo: &shoppingCartSnapshot.FittingInfo, SizeInfo: &shoppingCartSnapshot.SizeInfo, StepNum: stepNum, }) } 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, } // 数据库操作 var order = gmodel.NewFsOrder{ UserId: &in.UserId, DeliveryMethod: &in.DeliveryMethod, OrderSn: &orderSn, Status: (*int64)(&status.StatusCode), PayStatus: (*int64)(&payStatus), Ctime: &nowTime, Metadata: &orderDetail, } result := tx.Create(&order) if result.Error != nil { return result.Error } return nil }) if err != nil { return &CreateRes{ OrderSn: orderSn, ErrorCode: errorCode, }, err } return &CreateRes{ OrderSn: orderSn, ErrorCode: errorCode, }, nil }