package repositories import ( "context" "encoding/json" "errors" "fmt" "fusenapi/constants" "fusenapi/model/gmodel" "fusenapi/utils/basic" "fusenapi/utils/handlers" "fusenapi/utils/order" "fusenapi/utils/pay" "fusenapi/utils/queue" "math" "time" "github.com/aws/aws-sdk-go/aws/session" "github.com/stripe/stripe-go/v75" "github.com/zeromicro/go-zero/core/logc" "gorm.io/gorm" ) func NewOrder(gormDB *gorm.DB, awsSession *session.Session, delayQueue *queue.DelayMessage) Order { return &defaultOrder{ MysqlConn: gormDB, DelayQueue: delayQueue, } } type ( defaultOrder struct { MysqlConn *gorm.DB DelayQueue *queue.DelayMessage } 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) // 支付成功 PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error) // 关闭 Close(ctx context.Context, in *CloseReq) (res *CloseRes, err error) // 删除 Delete(ctx context.Context, in *DeleteReq) (res *DeleteRes, err error) // 支付超时订单自动关闭 CloseList(ctx context.Context, in *CloseListReq) (res *CloseListRes, err error) } PayInfo struct { PayMethod string `json:"pay_method"` // 支付方式 PaymentMethod string `json:"payment_method"` // 交易方式 PayTime time.Time `json:"pay_time"` // 支付时间 Status gmodel.PayStatus `json:"status"` // 当前状态 StatusLink []gmodel.PayStatus `json:"status_link"` // 状态链路 TradeNo string `json:"trade_no"` // 支付交易号 } 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"` // 标签 } /* 删除订单 */ DeleteReq struct { UserId int64 `json:"user_id"` OrderSn string `json:"order_sn"` } DeleteRes struct { ErrorCode basic.StatusResponse OrderSn string } /* 删除订单 */ /* 支付超时订单自动关闭 */ CloseListReq struct { Type int64 // type:1=关闭 } CloseListRes struct{} /* 支付超时订单自动关闭 */ /* 关闭 */ CloseReq struct { Type int64 // type:1=添加购物车 OrderSn string UserId int64 `json:"user_id"` } CloseRes struct { ErrorCode basic.StatusResponse } /* 关闭 */ /* 支付成功 */ PaymentSuccessfulReq struct { EventId string PaymentMethod string Charge *stripe.Charge } PaymentSuccessfulRes struct{} /* 支付成功 */ /* 预支付--定金 */ 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 OrderDetailOriginal } OrderDetailOriginal struct { Status *gmodel.OrderStatus OrderAmount *gmodel.OrderAmount OrderAddress *gmodel.OrderAddress OrderProduct []gmodel.OrderProductInter ShoppingCartSnapshot []gmodel.FsShoppingCart ShoppingProductSnapshot []gmodel.RelaFsProduct StatusLink []gmodel.OrderStatus PayStatusLink []gmodel.PayStatus } /* 详情 */ /* 列表 */ 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) Delete(ctx context.Context, in *DeleteReq) (res *DeleteRes, err error) { var errorCode basic.StatusResponse err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error { var orderInfo gmodel.FsOrder model := tx if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model = model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&orderInfo) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logc.Errorf(ctx, "order delete failed, err: %v", err) return result.Error } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 0) if err != nil { logc.Errorf(ctx, "order delete failed DetailOrderDetailHandler,OrderSn:%s, err: %v", in.OrderSn, err) return err } if !(*orderInfo.Status == int64(constants.ORDER_STATUS_CLOSE) || (*orderInfo.DeliveryMethod == int64(constants.DELIVERYMETHODDIRECTMAIL) && *orderInfo.Status == int64(constants.ORDER_STATUS_DIRECTMAIL_ARRIVED))) { errorCode = *basic.CodeErrOrderDeleteStatusIllegality err = errors.New("order delete failed, status is illegality") logc.Errorf(ctx, "order delete failed, err: %v", err) return err } // 状态链路 var ntime = time.Now().UTC() var statusCode = constants.ORDER_STATUS_DELETE var statusLink = append(ress.OrderDetailOriginal.StatusLink, gmodel.OrderStatus{ Ctime: &ntime, Utime: &ntime, StatusCode: statusCode, StatusTitle: constants.OrderStatusMessage[statusCode], }) statusLinkByte, err := json.Marshal(statusLink) if err != nil { logc.Errorf(ctx, "order delete failed Marshal statusLinkByte,OrderSn:%s, err: %v", in.OrderSn, err) return err } var table = gmodel.NewAllModels(tx).FsOrder.TableName() var resUpdate *gorm.DB var resUpdateSql string = fmt.Sprintf("UPDATE %s SET `utime` = '%s',`is_del` = 1", table, ntime) resUpdate = tx.Exec(fmt.Sprintf("%s ,`status_link`= JSON_MERGE_PATCH(`status_link`,?) WHERE `id` = %d", resUpdateSql, orderInfo.Id), statusLinkByte) err = resUpdate.Error if err != nil { logc.Errorf(ctx, "order delete failed Update FsOrder,OrderSn:%s, err: %v", in.OrderSn, err) return err } return nil }) if err != nil { logc.Errorf(ctx, "order delete failed, err: %v", err) if errorCode.Code == 0 { errorCode.Code = basic.CodeApiErr.Code errorCode.Message = basic.CodeApiErr.Message } return &DeleteRes{ ErrorCode: errorCode, }, err } return &DeleteRes{ ErrorCode: errorCode, OrderSn: in.OrderSn, }, err } // 订单关闭-支付超时 func (d *defaultOrder) CloseList(ctx context.Context, in *CloseListReq) (res *CloseListRes, err error) { var orderList []gmodel.FsOrder result := d.MysqlConn.Model(&gmodel.FsOrder{}). Where("is_del = ?", 0). Where("status = ?", int64(constants.ORDER_STATUS_UNPAIDDEPOSIT)). Where("pay_status = ?", int64(constants.ORDER_PAY_STATUS_UNPAIDDEPOSIT)). Find(&orderList) if result.Error != nil { logc.Errorf(ctx, "order CloseList failed, err: %v", err) return nil, result.Error } for _, orderInfo := range orderList { var ntime = time.Now().UTC() var cptime = orderInfo.Ctime.Add(time.Minute * 30) var dd = ntime.Unix() - cptime.Unix() if in.Type == 1 { fmt.Println("未支付超时时间: dd--", dd) if dd >= 0 { orderSn := *orderInfo.OrderSn fmt.Println("即时任务: OrderSn--", orderSn) ctx := context.Background() logc.Infof(ctx, "order CloseList, orderSn: %s", orderSn) d.Close(ctx, &CloseReq{ OrderSn: orderSn, Type: 1, }) } else { ddd := math.Abs(float64(dd)) // 延时任务 time.AfterFunc(time.Second*time.Duration(ddd), func() { orderSn := *orderInfo.OrderSn fmt.Println("延时任务: OrderSn--", orderSn) ctx := context.Background() logc.Infof(ctx, "order CloseList, orderSn: %s", orderSn) d.Close(ctx, &CloseReq{ OrderSn: orderSn, Type: 1, }) }) } } } return nil, nil } // 关闭 func (d *defaultOrder) Close(ctx context.Context, in *CloseReq) (res *CloseRes, err error) { var errorCode basic.StatusResponse err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error { var orderInfo gmodel.FsOrder model := tx.Where("status = ?", int64(constants.ORDER_STATUS_UNPAIDDEPOSIT)).Where("pay_status = ?", int(constants.ORDER_PAY_STATUS_UNPAIDDEPOSIT)) if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model = model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&orderInfo) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logc.Errorf(ctx, "order close failed, err: %v", err) return result.Error } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 0) if err != nil { logc.Errorf(ctx, "order close failed DetailOrderDetailHandler,OrderSn:%s, err: %v", in.OrderSn, err) return err } // 更新状态、状态链路 var ntime = time.Now().UTC() var statusCode = constants.ORDER_STATUS_CLOSE var statusLink = order.UpdateOrderStatusLink(ress.OrderDetailOriginal.StatusLink, gmodel.OrderStatus{ Ctime: &ntime, Utime: &ntime, StatusCode: statusCode, StatusTitle: constants.OrderStatusMessage[statusCode], }) statusLinkByte, err := json.Marshal(statusLink) if err != nil { logc.Errorf(ctx, "order close failed Marshal statusLinkByte,OrderSn:%s, err: %v", in.OrderSn, err) return err } var table = gmodel.NewAllModels(tx).FsOrder.TableName() var resUpdate *gorm.DB var resUpdateSql string = fmt.Sprintf("UPDATE %s SET `status` = %d , `utime` = '%s'", table, statusCode, ntime) resUpdate = tx.Exec(fmt.Sprintf("%s ,`status_link`= JSON_MERGE_PATCH(`status_link`,?) WHERE `id` = %d", resUpdateSql, orderInfo.Id), statusLinkByte) err = resUpdate.Error if err != nil { logc.Errorf(ctx, "order close failed Update FsOrder,OrderSn:%s, err: %v", in.OrderSn, err) return err } // 新增购物车 if in.Type == 1 { var users []gmodel.FsShoppingCart for _, shoppingCart := range ress.OrderDetailOriginal.ShoppingCartSnapshot { users = append(users, gmodel.FsShoppingCart{ UserId: shoppingCart.UserId, ProductId: shoppingCart.ProductId, TemplateId: shoppingCart.TemplateId, ModelId: shoppingCart.ModelId, SizeId: shoppingCart.SizeId, LightId: shoppingCart.FittingId, FittingId: shoppingCart.FittingId, PurchaseQuantity: shoppingCart.PurchaseQuantity, Snapshot: shoppingCart.Snapshot, IsSelected: shoppingCart.IsSelected, IsHighlyCustomized: shoppingCart.IsHighlyCustomized, Ctime: &ntime, Utime: &ntime, }) } resCreate := tx.Create(&users) err = resCreate.Error if err != nil { logc.Errorf(ctx, "order close failed Create FsShoppingCart,OrderSn:%s, err: %v", in.OrderSn, err) return err } } return nil }) if err != nil { logc.Errorf(ctx, "order close failed, err: %v", err) if errorCode.Code == 0 { errorCode.Code = basic.CodeApiErr.Code errorCode.Message = basic.CodeApiErr.Message } return &CloseRes{ ErrorCode: errorCode, }, err } return &CloseRes{ ErrorCode: errorCode, }, err } // 支付成功 func (d *defaultOrder) PaymentSuccessful(ctx context.Context, in *PaymentSuccessfulReq) (res *PaymentSuccessfulRes, err error) { var orderSn string var payStage string var ok bool var card string var brand string var country string var currency string var tradeSn string var payAmount int64 var payTitle string var payTime time.Time var paymentMethod string var payMethod int64 = 1 if in.PaymentMethod == "stripe" { payMethod = 1 } if in.PaymentMethod == "paypal" { payMethod = 2 } if in.Charge != nil { charge := in.Charge orderSn, ok = charge.Metadata["order_sn"] if !ok || orderSn == "" { err = errors.New("order_sn is empty") logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err) return &PaymentSuccessfulRes{}, err } payStage, ok = charge.Metadata["pay_stage"] if !ok || payStage == "" { err = errors.New("pay_stage is empty") logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err) return &PaymentSuccessfulRes{}, err } country, ok = charge.Metadata["country"] if !ok || country == "" { err = errors.New("country is empty") logc.Errorf(ctx, "PaymentSuccessful failed param, eventId:%s,err:%v", in.EventId, err) return &PaymentSuccessfulRes{}, err } if charge.PaymentMethodDetails != nil { if charge.PaymentMethodDetails.Card != nil { if charge.PaymentMethodDetails.Card.Last4 != "" { card = charge.PaymentMethodDetails.Card.Last4 } if charge.PaymentMethodDetails.Card.Brand != "" { brand = string(charge.PaymentMethodDetails.Card.Brand) } } if charge.PaymentMethodDetails.Type != "" { paymentMethod = string(charge.PaymentMethodDetails.Type) } } if charge.Currency != "" { currency = string(charge.Currency) } tradeSn = charge.ID payAmount = charge.Amount payTitle = charge.Description payTime = time.Unix(charge.Created, 0).UTC() } err = d.MysqlConn.WithContext(ctx).Transaction(func(tx *gorm.DB) error { var orderInfo gmodel.FsOrder result := tx.Where("is_del = ?", 0).Where("order_sn = ?", orderSn).Take(&orderInfo) err = result.Error if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed order Take, eventId:%s,err: %v", in.EventId, err) return err } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 0) if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed DetailOrderDetailHandler,eventId:%s, err: %v", in.EventId, err) return err } var ntime = time.Now().UTC() if (payStage == "deposit" && *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_UNPAIDDEPOSIT)) || (payStage == "remaining_balance" && *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT)) { var payStatus = int64(constants.PAY_STATUS_PAID) var payStageInt int64 var orderPayStatusCode constants.OrderPayStatusCode // 订单状态--当前 var status gmodel.OrderStatus var statusLink []gmodel.OrderStatus var payStatusLink []gmodel.PayStatus var orderAmount = make(map[string]interface{}) var payInfo PayInfo payInfo.PayMethod = paymentMethod payInfo.PaymentMethod = in.PaymentMethod payInfo.PayTime = payTime payInfo.TradeNo = tradeSn // 当前状态 var statusCode constants.OrderStatusCode var statusCodePre constants.OrderStatusCode if payStage == "deposit" { if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { // 直邮 statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDERED } if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE { // 云仓 statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDERED } payStageInt = 1 orderPayStatusCode = constants.ORDER_PAY_STATUS_PAIDDEPOSIT status = gmodel.OrderStatus{ Ctime: &ntime, Utime: &ntime, StatusCode: statusCode, StatusTitle: constants.OrderStatusMessage[statusCode], } statusLink = order.UpdateOrderStatusLink(ress.OrderDetailOriginal.StatusLink, gmodel.OrderStatus{ Ctime: &ntime, Utime: &ntime, StatusCode: statusCode, StatusTitle: constants.OrderStatusMessage[statusCode], }) payInfo.Status = gmodel.PayStatus{ StatusCode: int64(constants.PAY_STATUS_PAID), StatusTitle: constants.PayStatusMessage[constants.PAY_STATUS_PAID], } payInfo.StatusLink = append(ress.OrderDetailOriginal.OrderAmount.Deposit.StatusLink, payInfo.Status) orderAmount["deposit"] = payInfo } if payStage == "remaining_balance" { if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { // 直邮 statusCodePre = constants.ORDER_STATUS_DIRECTMAIL_ORDERED statusCode = constants.ORDER_STATUS_DIRECTMAIL_ORDEREDMAINING } if *orderInfo.DeliveryMethod == constants.DELIVERYMETHODDSCLOUDSTORE { // 云仓 statusCodePre = constants.ORDER_STATUS_CLOUDSTORE_ORDERED statusCode = constants.ORDER_STATUS_CLOUDSTORE_ORDEREDMAINING } payStageInt = 2 orderPayStatusCode = constants.ORDER_PAY_STATUS_PAIDDREMAINING var statusChildren []*gmodel.OrderStatus // 更新订单状态链路--子状态 for oStatusLinkKey, oStatusLink := range ress.OrderDetailOriginal.StatusLink { if oStatusLink.StatusCode == statusCodePre { statusChildren = append(oStatusLink.Children, &gmodel.OrderStatus{ Ctime: &ntime, Utime: &ntime, StatusCode: statusCode, StatusTitle: constants.OrderStatusMessage[statusCode], }) ress.OrderDetailOriginal.StatusLink[oStatusLinkKey].Children = statusChildren } } statusLink = ress.OrderDetailOriginal.StatusLink if ress.OrderDetailOriginal.Status.StatusCode == constants.ORDER_STATUS_DIRECTMAIL_ORDERED || ress.OrderDetailOriginal.Status.StatusCode == constants.ORDER_STATUS_CLOUDSTORE_ORDERED { status = *ress.OrderDetailOriginal.Status status.Children = statusChildren } payInfo.Status = gmodel.PayStatus{ StatusCode: int64(constants.PAY_STATUS_PAID), StatusTitle: constants.PayStatusMessage[constants.PAY_STATUS_PAID], } payInfo.StatusLink = append(ress.OrderDetailOriginal.OrderAmount.RemainingBalance.StatusLink, payInfo.Status) orderAmount["remaining_balance"] = payInfo } payStatusLink = append(ress.OrderDetailOriginal.PayStatusLink, gmodel.PayStatus{ StatusCode: int64(orderPayStatusCode), StatusTitle: constants.OrderPayStatusMessage[orderPayStatusCode], }) orderAmountByte, err := json.Marshal(orderAmount) if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed Marshal orderAmount,eventId:%s, err: %v", in.EventId, err) return err } statusLinkByte, err := json.Marshal(statusLink) if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed Marshal statusLink,eventId:%s, err: %v", in.EventId, err) return err } payStatusLinkByte, err := json.Marshal(payStatusLink) if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed Marshal payStatusLink,eventId:%s, err: %v", in.EventId, err) return err } // 新增交易信息 tx.Create(&gmodel.FsOrderTrade{ UserId: orderInfo.UserId, OrderSn: &orderSn, OrderSource: orderInfo.OrderSource, TradeSn: &tradeSn, PayAmount: &payAmount, PayStatus: &payStatus, PaymentMethod: &payMethod, PayStage: &payStageInt, CardSn: &card, CardBrand: &brand, Country: &country, Currency: ¤cy, Ctime: &ntime, Utime: &ntime, PayTitle: &payTitle, }) // 更新数据库 var table = gmodel.NewAllModels(tx).FsOrder.TableName() var resUpdate *gorm.DB var resUpdateSql string if *orderInfo.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) { resUpdateSql = fmt.Sprintf("UPDATE %s SET `status` = %d,`pay_status` = %d , `utime` = '%s'", table, statusCode, orderPayStatusCode, ntime) } else { resUpdateSql = fmt.Sprintf("UPDATE %s SET `pay_status` = %d , `utime` = '%s'", table, orderPayStatusCode, ntime) } resUpdate = tx.Exec(fmt.Sprintf("%s ,`status_link`= JSON_MERGE_PATCH(`status_link`,?),`pay_status_link`= JSON_MERGE_PATCH(`pay_status_link`,?),`order_amount`= JSON_MERGE_PATCH(`order_amount`,?) WHERE `id` = %d", resUpdateSql, orderInfo.Id), statusLinkByte, payStatusLinkByte, orderAmountByte) err = resUpdate.Error if err != nil { logc.Errorf(ctx, "PaymentSuccessful failed resUpdate,eventId:%s, err: %v", in.EventId, err) return err } } return nil }) return &PaymentSuccessfulRes{}, nil } // 预支付--尾款 func (d *defaultOrder) CreatePrePaymentByBalance(ctx context.Context, in *CreatePrePaymentByBalanceReq) (res *CreatePrePaymentByBalanceRes, err error) { var errorCode basic.StatusResponse var orderInfo gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model = model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&orderInfo) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logc.Errorf(ctx, "create prePayment balance failed, err: %v", err) return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, result.Error } // 非未支付 if *orderInfo.PayStatus != int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT) { errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid err = errors.New("order balance pay status is not unPaid") logc.Errorf(ctx, "create prePayment balance failed, err: %v", err) return &CreatePrePaymentByBalanceRes{ ErrorCode: errorCode, }, err } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 1) if err != nil { logc.Errorf(ctx, "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 metadata = make(map[string]string, 2) metadata["model"] = "product_order" metadata["order_sn"] = in.OrderSn metadata["pay_stage"] = "remaining_balance" metadata["country"] = in.Country var generatePrepaymentReq = &pay.GeneratePrepaymentReq{ Metadata: metadata, ProductName: "支付尾款后期统一调整", Amount: amount, Currency: "usd", Quantity: 1, ProductDescription: "支付尾款后期统一调整", } payDriver := pay.NewPayDriver(1, payConfig) prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq) if err != nil { logc.Errorf(ctx, "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: 2, Total: OrderPayTotal{ Amount: amount, Label: "支付尾款后期统一调整", }, }, }, nil } // 预支付--定金 func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) { var errorCode basic.StatusResponse var orderInfo gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model = model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&orderInfo) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logc.Errorf(ctx, "create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, result.Error } // 非未支付 if *orderInfo.PayStatus != int64(constants.ORDER_PAY_STATUS_UNPAIDDEPOSIT) { errorCode = *basic.CodeErrOrderCreatePrePaymentNoUnPaid err = errors.New("order pay status is not unPaidDeposit") logc.Errorf(ctx, "create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } // 是否超时支付 ntime := time.Now().UTC() ctime := *orderInfo.Ctime ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix() ntimeTimeOut := ntime.Unix() // 测试超时支付不限制 if ctimeTimeOut < ntimeTimeOut { // if ctimeTimeOut == ntimeTimeOut { errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout err = errors.New("order pay timeout") logc.Errorf(ctx, "create prePayment deposit failed, err: %v", err) return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 1) if err != nil { logc.Errorf(ctx, "create prePayment deposit failed DetailOrderDetailHandler, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } var orderAddress *gmodel.OrderAddress var orderAddressByte []byte var statusLinkByte []byte if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { orderAddress = &gmodel.OrderAddress{ Name: in.DeliveryAddress.Name, Mobile: in.DeliveryAddress.Mobile, Address: in.DeliveryAddress.Address, } orderAddressByte, err = json.Marshal(orderAddress) if err != nil { logc.Errorf(ctx, "create prePayment deposit failed orderAddressByte, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } } // 订单状态--链路 tPlus60Days := ntime.AddDate(0, 0, 60).UTC() var statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, ntime, tPlus60Days) statusLinkByte, err = json.Marshal(statusLink) if err != nil { logc.Errorf(ctx, "create prePayment deposit failed statusLinkByte, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } // 更新数据库 var table = gmodel.NewAllModels(d.MysqlConn).FsOrder.TableName() var resUpdate *gorm.DB if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { resUpdate = d.MysqlConn.Exec(fmt.Sprintf("UPDATE %s SET `delivery_method` = ? , `utime` = ?, `order_address` = JSON_MERGE_PATCH(`order_address`,?), `status_link` = JSON_MERGE_PATCH(`status_link`,?) WHERE `id` = ?", table), in.DeliveryMethod, ntime, orderAddressByte, statusLinkByte, orderInfo.Id) } else { resUpdate = d.MysqlConn.Exec(fmt.Sprintf("UPDATE %s SET `delivery_method` = ? , `utime` = ? WHERE `id` = ?", table), in.DeliveryMethod, ntime, orderInfo.Id) } err = resUpdate.Error if err != nil { logc.Errorf(ctx, "create prePayment deposit failed update Exec, err: %v", err) errorCode = *basic.CodeServiceErr return &CreatePrePaymentByDepositRes{ ErrorCode: errorCode, }, err } ress.OrderDetail.OrderInfo.Utime = &ntime ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod ress.OrderDetail.OrderInfo.StatusLink = statusLink 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 metadata = make(map[string]string, 2) metadata["model"] = "product_order" metadata["order_sn"] = in.OrderSn metadata["pay_stage"] = "deposit" metadata["country"] = in.Country var generatePrepaymentReq = &pay.GeneratePrepaymentReq{ Metadata: metadata, ProductName: "支付首款", Amount: amount, Currency: "usd", Quantity: 1, ProductDescription: "支付首款", } payDriver := pay.NewPayDriver(1, payConfig) prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq) if err != nil { logc.Errorf(ctx, "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) model = model.Where("pay_status > ?", 0) if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.DeliveryMethod != 0 { model = model.Where("delivery_method = ?", in.DeliveryMethod) } if in.OrderCycle != "" { // 下单时间 switch in.OrderCycle { case "within_one_month": model = model.Where("ctime >?", time.Now().UTC().AddDate(0, -1, 0)) case "within_three_month": model = model.Where("ctime >?", time.Now().UTC().AddDate(0, -3, 0)) case "within_six_month": model = model.Where("ctime >?", time.Now().UTC().AddDate(0, -6, 0)) case "within_one_year": model = model.Where("ctime >?", time.Now().UTC().AddDate(-1, 0, 0)) } } var count int64 resultCount := model.Count(&count) if resultCount.Error != nil { logc.Errorf(ctx, "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)).Order("id desc") result := m.Find(&orderList) if result.Error != nil { logc.Errorf(ctx, "order list failed, err: %v", err) return nil, result.Error } for _, order := range orderList { ress, err := d.OrderDetailHandler(ctx, &order, 1) if err != nil { return nil, err } orderDetailList = append(orderDetailList, ress.OrderDetail) } } if len(orderList) == 0 { 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 orderInfo gmodel.FsOrder model := d.MysqlConn.Where("is_del = ?", 0) if in.UserId != 0 { model = model.Where("user_id = ?", in.UserId) } if in.OrderSn != "" { model = model.Where("order_sn = ?", in.OrderSn) } result := model.Take(&orderInfo) if result.Error != nil { if errors.Is(result.Error, gorm.ErrRecordNotFound) { errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound } else { errorCode = *basic.CodeServiceErr } logc.Errorf(ctx, "order detail failed, err: %v", err) return &DetailRes{ ErrorCode: errorCode, }, result.Error } // 是否超时支付 // if *order.Status == int64(constants.ORDER_STATUS_UNPAIDDEPOSIT) { // 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") // logc.Errorf(ctx, "order detail failed, err: %v", err) // return &DetailRes{ // ErrorCode: errorCode, // }, err // } // } ress, err := d.OrderDetailHandler(ctx, &orderInfo, 1) if err != nil { logc.Errorf(ctx, "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("ShoppingCartProductModel3d"). 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.OrderProductInter var shoppingProductSnapshotList []*gmodel.RelaFsProduct var shoppingCartSnapshotList []*gmodel.FsShoppingCart 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.ORDER_PAY_STATUS_UNPAIDDEPOSIT // 订单状态 var status = constants.ORDER_STATUS_UNPAIDDEPOSIT // 直邮 if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL { orderAddress = &gmodel.OrderAddress{ Mobile: in.DeliveryAddress.Mobile, Name: in.DeliveryAddress.Name, } } // 预计交付时间 var expectedDeliveryTime = &gmodel.ExpectedDelivery{ Current: in.ExpectedDeliveryTime, Initiate: in.ExpectedDeliveryTime, } for _, shoppingCart := range shoppingCartList { // 购物车快照 var shoppingCartSnapshot gmodel.CartSnapshot 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) } var stepPriceJson gmodel.StepPriceJsonStruct if shoppingCart.ShoppingCartProductModel3d.StepPrice != nil { err = json.Unmarshal(*shoppingCart.ShoppingCartProductModel3d.StepPrice, &stepPriceJson) if err != nil { return err } } else { errorCode = *basic.CodeErrOrderCreatProductPriceAbsent errorCode.Message = "create order failed, step price of product '" + shoppingCartSnapshot.ProductInfo.ProductName + "'is failed" return errors.New("shoppingCartProductModel3d.StepPrice nil") } var fittingPrice int64 if shoppingCart.ShoppingCartProductModel3dFitting != nil { fittingPrice = *shoppingCart.ShoppingCartProductModel3dFitting.Price } /* 计算价格 */ productTotalPrice, productPrice, err := NewShoppingCart(tx, nil, nil).CaculateStepPrice(*shoppingCart.PurchaseQuantity, stepPriceJson, fittingPrice) 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) } productInter := gmodel.OrderProductInter{ TotalPrice: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: productTotalPrice, Current: productTotalPrice, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), ItemPrice: order.GetAmountInfo(order.GetAmountInfoReq{ ExchangeRate: in.ExchangeRate, Initiate: productPrice, Current: productPrice, CurrentCurrency: in.CurrentCurrency, OriginalCurrency: in.OriginalCurrency, }), PurchaseQuantity: &gmodel.PurchaseQuantity{ Current: *shoppingCart.PurchaseQuantity, Initiate: *shoppingCart.PurchaseQuantity, }, ProductId: *shoppingCart.ProductId, ProductCover: *shoppingCart.ShoppingCartProduct.Cover, ProductCoverMetadata: productCoverMetadata, ProductName: *shoppingCart.ShoppingCartProduct.Title, 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, }, }, IsHighlyCustomized: *shoppingCart.IsHighlyCustomized, RenderImage: shoppingCartSnapshot.RenderImage, CartId: shoppingCart.Id, ExpectedDeliveryTime: expectedDeliveryTime, } orderProductList = append(orderProductList, &productInter) shoppingProductSnapshotList = append(shoppingProductSnapshotList, shoppingCart.ShoppingCartProduct) shoppingCartSnapshotList = append(shoppingCartSnapshotList, &shoppingCart.FsShoppingCart) } 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.PAY_STATUS_UNPAID), StatusTitle: constants.PayStatusMessage[constants.PAY_STATUS_UNPAID], }, StatusLink: make([]gmodel.PayStatus, 0), 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.PAY_STATUS_UNPAID), StatusTitle: constants.PayStatusMessage[constants.PAY_STATUS_UNPAID], }, StatusLink: make([]gmodel.PayStatus, 0), 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 statusLink = order.GenerateOrderStatusLink(in.DeliveryMethod, nowTime, in.ExpectedDeliveryTime) byteOrderProduct, _ := json.Marshal(orderProductList) var byteOrderAddress []byte if orderAddress != nil { byteOrderAddress, _ = json.Marshal(orderAddress) } byteOrderAmount, _ := json.Marshal(orderAmount) byteShoppingCartSnapshot, _ := json.Marshal(shoppingCartSnapshotList) byteShoppingProductSnapshot, _ := json.Marshal(shoppingProductSnapshotList) byteStatusLink, _ := json.Marshal(statusLink) byteOrderMetadata, _ := json.Marshal(gmodel.OrderMetadata{ ExpectedDeliveryTime: expectedDeliveryTime, }) // 创建订单 resultCreate := tx.Create(&gmodel.FsOrder{ OrderProduct: &byteOrderProduct, OrderAddress: &byteOrderAddress, OrderAmount: &byteOrderAmount, ShoppingCartSnapshot: &byteShoppingCartSnapshot, ShoppingProductSnapshot: &byteShoppingProductSnapshot, StatusLink: &byteStatusLink, UserId: &in.UserId, DeliveryMethod: &in.DeliveryMethod, OrderSn: &orderSn, Status: (*int64)(&status), PayStatus: (*int64)(&payStatus), Ctime: &nowTime, Metadata: &byteOrderMetadata, }) if resultCreate.Error != nil { return resultCreate.Error } // 删除购物车 resultDelete := tx.Delete(&gmodel.FsShoppingCart{}, in.CartIds) if resultDelete.Error != nil { return resultDelete.Error } return nil }) if err != nil { logc.Errorf(ctx, "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) OrderShoppingCartSnapshotHandler(ctx context.Context, req *string) (res map[string]interface{}, err error) { var snapshot map[string]interface{} json.Unmarshal([]byte(*req), &snapshot) // snapshotFittingInfoData, snapshotFittingInfoEx := snapshot["fitting_info"] // var fittingInfoMap map[string]interface{} // if snapshotFittingInfoEx { // var snapshotFittingInfoJson map[string]interface{} // var fittingName string // snapshotFittingInfo := snapshotFittingInfoData.(map[string]interface{}) // snapshotFittingInfoJsonData, snapshotFittingInfoJsonEx := snapshotFittingInfo["fitting_json"] // if snapshotFittingInfoJsonEx { // json.Unmarshal([]byte(snapshotFittingInfoJsonData.(string)), &snapshotFittingInfoJson) // } // fittingNameData, fittingNameEx := snapshotFittingInfo["fitting_name"] // if fittingNameEx { // fittingName = fittingNameData.(string) // } // fittingInfoMap = make(map[string]interface{}, 2) // fittingInfoMap["fitting_json"] = snapshotFittingInfoJson // fittingInfoMap["fitting_name"] = fittingName // } // snapshot["fitting_info"] = fittingInfoMap // snapshotModelInfoData, snapshotModelInfoEx := snapshot["model_info"] // var modelInfoMap map[string]interface{} // if snapshotModelInfoEx { // var snapshotModelInfoJson map[string]interface{} // snapshotModelInfo := snapshotModelInfoData.(map[string]interface{}) // snapshotModelInfoJsonData, snapshotModelInfoJsonEx := snapshotModelInfo["model_json"] // if snapshotModelInfoJsonEx { // json.Unmarshal([]byte(snapshotModelInfoJsonData.(string)), &snapshotModelInfoJson) // } // modelInfoMap = make(map[string]interface{}, 1) // modelInfoMap["model_json"] = snapshotModelInfoJson // } // snapshot["model_info"] = modelInfoMap // snapshotTemplateInfoData, snapshotTemplateInfoEx := snapshot["template_info"] // var templateInfoMap map[string]interface{} // if snapshotTemplateInfoEx { // var snapshotTemplateInfoJson map[string]interface{} // var templateTag string // snapshotTemplateInfo := snapshotTemplateInfoData.(map[string]interface{}) // snapshotTemplateInfoJsonData, snapshotTemplateInfoJsonEx := snapshotTemplateInfo["template_json"] // if snapshotTemplateInfoJsonEx { // json.Unmarshal([]byte(snapshotTemplateInfoJsonData.(string)), &snapshotTemplateInfoJson) // } // templateTagData, templateTagEx := snapshotTemplateInfo["template_tag"] // if templateTagEx { // templateTag = templateTagData.(string) // } // templateInfoMap = make(map[string]interface{}, 2) // templateInfoMap["template_json"] = snapshotTemplateInfoJson // templateInfoMap["template_tag"] = templateTag // } // snapshot["template_info"] = templateInfoMap // snapshotLightInfoData, snapshotLightInfoEx := snapshot["light_info"] // var lightInfoMap map[string]interface{} // if snapshotLightInfoEx { // var snapshotLightInfoJson map[string]interface{} // var lightTag string // snapshotLightInfo := snapshotLightInfoData.(map[string]interface{}) // snapshotLightInfoJsonData, snapshotLightInfoJsonEx := snapshotLightInfo["light_json"] // if snapshotLightInfoJsonEx { // json.Unmarshal([]byte(snapshotLightInfoJsonData.(string)), &snapshotLightInfoJson) // } // lightTagData, lightTagEx := snapshotLightInfo["light_tag"] // if lightTagEx { // lightTag = lightTagData.(string) // } // lightInfoMap = make(map[string]interface{}, 2) // lightInfoMap["light_json"] = snapshotLightInfoJson // lightInfoMap["light_tag"] = lightTag // } // snapshot["light_info"] = lightInfoMap return snapshot, nil } // 详情处理 func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder, original int64) (res *DetailRes, err error) { var orderAmount gmodel.OrderAmount err = json.Unmarshal(*orderInfo.OrderAmount, &orderAmount) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal OrderAmount failed, err: %v", err) return nil, err } var orderAddress *gmodel.OrderAddress if orderInfo.OrderAddress != nil { err = json.Unmarshal(*orderInfo.OrderAddress, &orderAddress) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal OrderAddress failed, err: %v", err) return nil, err } } var orderProduct []gmodel.OrderProductInter err = json.Unmarshal(*orderInfo.OrderProduct, &orderProduct) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal OrderProduct failed, err: %v", err) return nil, err } var shoppingCartSnapshot []gmodel.FsShoppingCart err = json.Unmarshal(*orderInfo.ShoppingCartSnapshot, &shoppingCartSnapshot) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal ShoppingCartSnapshot failed, err: %v", err) return nil, err } var shoppingProductSnapshot []gmodel.RelaFsProduct err = json.Unmarshal(*orderInfo.ShoppingProductSnapshot, &shoppingProductSnapshot) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal ShoppingCartSnapshot failed, err: %v", err) return nil, err } var statusLink []gmodel.OrderStatus err = json.Unmarshal(*orderInfo.StatusLink, &statusLink) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal StatusLink failed, err: %v", err) return nil, err } var payStatusLink []gmodel.PayStatus if orderInfo.PayStatusLink != nil { err = json.Unmarshal(*orderInfo.PayStatusLink, &payStatusLink) if err != nil { logc.Errorf(ctx, "order detail handler unmarshal PayStatusLink failed, err: %v", err) return nil, err } } var orderMetadata gmodel.OrderMetadata if orderInfo.Metadata != nil { json.Unmarshal(*orderInfo.Metadata, &orderMetadata) } // 预计到货时间 var expectedTime = orderMetadata.ExpectedDeliveryTime.Current var status = order.GetOrderStatusCurrent(statusLink, constants.OrderStatusCode(*orderInfo.Status)) status.ExpectedTime = &expectedTime var orderDetail gmodel.OrderDetail if original == 1 { orderDetail.DeliveryAddress = orderAddress orderDetail.OrderAmount = orderAmount orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderAmount.Deposit.PayAmount) orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderAmount.RemainingBalance.PayAmount) orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderAmount.Subtotal) orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderAmount.Total) orderDetail.PayStatus = constants.OrderPayStatusCode(*orderInfo.PayStatus) orderDetail.PayTimeout = time.Duration(orderInfo.Ctime.Add(30*time.Minute).UTC().Unix() - time.Now().UTC().Unix()) orderDetail.OrderInfo = gmodel.OrderInfo{ UserId: *orderInfo.UserId, DeliveryMethod: *orderInfo.DeliveryMethod, OrderSn: *orderInfo.OrderSn, Ctime: orderInfo.Ctime, Utime: orderInfo.Utime, Status: status, StatusLink: order.GetOrderStatusLinkUser(*orderInfo.DeliveryMethod, statusLink), Metadata: orderMetadata, } var orderProductList []gmodel.OrderProduct for _, productValue := range orderProduct { var selectColorIndex int64 var shoppingCartSnapshotData gmodel.FsShoppingCartData for _, shoppingCartSnapshotValue := range shoppingCartSnapshot { if productValue.CartId == shoppingCartSnapshotValue.Id { snapshot, err := d.OrderShoppingCartSnapshotHandler(ctx, shoppingCartSnapshotValue.Snapshot) if err != nil { logc.Errorf(ctx, "OrderDetailHandler OrderShoppingCartSnapshotHandler failed, err: %v", err) return nil, err } shoppingCartSnapshotData.Id = shoppingCartSnapshotValue.Id shoppingCartSnapshotData.UserId = shoppingCartSnapshotValue.UserId shoppingCartSnapshotData.ProductId = shoppingCartSnapshotValue.ProductId shoppingCartSnapshotData.TemplateId = shoppingCartSnapshotValue.TemplateId shoppingCartSnapshotData.ModelId = shoppingCartSnapshotValue.ModelId shoppingCartSnapshotData.SizeId = shoppingCartSnapshotValue.SizeId shoppingCartSnapshotData.LightId = shoppingCartSnapshotValue.LightId shoppingCartSnapshotData.FittingId = shoppingCartSnapshotValue.FittingId shoppingCartSnapshotData.PurchaseQuantity = shoppingCartSnapshotValue.PurchaseQuantity shoppingCartSnapshotData.IsSelected = shoppingCartSnapshotValue.IsSelected shoppingCartSnapshotData.IsSelected = shoppingCartSnapshotValue.IsSelected shoppingCartSnapshotData.IsHighlyCustomized = shoppingCartSnapshotValue.IsHighlyCustomized shoppingCartSnapshotData.Ctime = shoppingCartSnapshotValue.Ctime shoppingCartSnapshotData.Utime = shoppingCartSnapshotValue.Utime shoppingCartSnapshotData.Snapshot = &snapshot selectColorIndexV, selectColorIndexE := snapshot["select_color_index"] if selectColorIndexE { selectColorIndex = selectColorIndexV.(int64) } } } var expectedDeliveryTime time.Time if productValue.ExpectedDeliveryTime == nil { expectedDeliveryTime = expectedTime } else { expectedDeliveryTime = productValue.ExpectedDeliveryTime.Current } orderProductItem := gmodel.OrderProduct{ TotalPrice: order.GetAmountInfoFormat(&productValue.TotalPrice), ItemPrice: order.GetAmountInfoFormat(&productValue.ItemPrice), ProductId: productValue.ProductId, ProductSn: productValue.ProductSn, ProductName: productValue.ProductName, ProductCover: productValue.ProductCover, ProductCoverMetadata: productValue.ProductCoverMetadata, ShoppingCartSnapshot: &shoppingCartSnapshotData, ExpectedDeliveryTime: &expectedDeliveryTime, PurchaseQuantity: *productValue.PurchaseQuantity, DiyInformation: productValue.DiyInformation, SizeInfo: productValue.SizeInfo, FittingInfo: productValue.FittingInfo, IsHighlyCustomized: productValue.IsHighlyCustomized, RenderImage: productValue.RenderImage, SelectColorIndex: selectColorIndex, } orderProductList = append(orderProductList, orderProductItem) } orderDetail.OrderProduct = orderProductList } return &DetailRes{ OrderDetail: orderDetail, OrderDetailOriginal: OrderDetailOriginal{ Status: &status, OrderAmount: &orderAmount, OrderAddress: orderAddress, OrderProduct: orderProduct, ShoppingCartSnapshot: shoppingCartSnapshot, ShoppingProductSnapshot: shoppingProductSnapshot, StatusLink: statusLink, PayStatusLink: payStatusLink, }, }, nil }