1926 lines
67 KiB
Go
1926 lines
67 KiB
Go
package repositories
|
|
|
|
import (
|
|
"context"
|
|
"encoding/json"
|
|
"errors"
|
|
"fmt"
|
|
"fusenapi/constants"
|
|
"fusenapi/model/gmodel"
|
|
"fusenapi/utils/basic"
|
|
"fusenapi/utils/file"
|
|
"fusenapi/utils/format"
|
|
"fusenapi/utils/handlers"
|
|
"fusenapi/utils/hash"
|
|
"fusenapi/utils/order"
|
|
"fusenapi/utils/pay"
|
|
"fusenapi/utils/pdf"
|
|
"fusenapi/utils/queue"
|
|
"math"
|
|
"strconv"
|
|
"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,
|
|
AwsSession: awsSession,
|
|
}
|
|
}
|
|
|
|
type (
|
|
defaultOrder struct {
|
|
MysqlConn *gorm.DB
|
|
DelayQueue *queue.DelayMessage
|
|
AwsSession *session.Session
|
|
}
|
|
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)
|
|
// 发票
|
|
Invoice(ctx context.Context, in *InvoiceReq) (res *InvoiceRes, 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 {
|
|
Street string `json:"street"` // 详细地址
|
|
City string `json:"city"` // 城市
|
|
FirstName string `json:"first_name"` // 姓
|
|
LastName string `json:"last_name"` // 名
|
|
Mobile string `json:"mobile"` // 手机
|
|
State string `json:"state"` // 州
|
|
Suite string `json:"suite"` // 房号
|
|
ZipCode string `json:"zip_code"` // 邮编号码
|
|
}
|
|
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"` // 标签
|
|
}
|
|
/* 发票 */
|
|
InvoiceReq struct {
|
|
UserId int64 `json:"user_id"`
|
|
OrderSn string `json:"order_sn"`
|
|
}
|
|
InvoiceRes struct {
|
|
ErrorCode basic.StatusResponse
|
|
InvoiceUrls []string `json:"invoice_urls"`
|
|
}
|
|
/* 发票 */
|
|
|
|
/* 删除订单 */
|
|
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) Invoice(ctx context.Context, in *InvoiceReq) (res *InvoiceRes, err error) {
|
|
var errorCode basic.StatusResponse
|
|
var orderInfo gmodel.FsOrder
|
|
var receiptSnsResources []string
|
|
var receiptSnsDeposit string
|
|
var receiptSnsFinal string
|
|
var invoiceUrls []string
|
|
|
|
var orderTradeDeposit gmodel.FsOrderTrade
|
|
var orderTradeFinal gmodel.FsOrderTrade
|
|
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 invoice detail failed, err: %v", err)
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, result.Error
|
|
}
|
|
|
|
if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT) || *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDREMAINING) {
|
|
// 查询支付账单
|
|
var orderTradeList []gmodel.FsOrderTrade
|
|
|
|
model1 := d.MysqlConn
|
|
if in.OrderSn != "" {
|
|
model1 = model1.Where("order_sn = ?", in.OrderSn)
|
|
}
|
|
result1 := model1.Find(&orderTradeList)
|
|
if result1.Error != nil {
|
|
if errors.Is(result1.Error, gorm.ErrRecordNotFound) {
|
|
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
|
} else {
|
|
errorCode = *basic.CodeServiceErr
|
|
}
|
|
logc.Errorf(ctx, "order invoice trade failed, err: %v", err)
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, result1.Error
|
|
}
|
|
if len(orderTradeList) > 0 {
|
|
for _, orderTrade := range orderTradeList {
|
|
receiptSnsResources = append(receiptSnsResources, hash.JsonHashKey(*orderTrade.ReceiptSn))
|
|
if *orderTrade.PayStage == 1 {
|
|
receiptSnsDeposit = *orderTrade.ReceiptSn
|
|
orderTradeDeposit = orderTrade
|
|
}
|
|
if *orderTrade.PayStage == 2 {
|
|
receiptSnsFinal = *orderTrade.ReceiptSn
|
|
orderTradeFinal = orderTrade
|
|
}
|
|
}
|
|
// 查询支付账单
|
|
var resourceList []gmodel.FsResource
|
|
result2 := d.MysqlConn.Where("resource_id in ?", receiptSnsResources).Find(&resourceList)
|
|
if result2.Error != nil {
|
|
errorCode = *basic.CodeServiceErr
|
|
logc.Errorf(ctx, "order invoice esource failed, err: %v", err)
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, result1.Error
|
|
}
|
|
resourceListLen := len(resourceList)
|
|
for _, resource := range resourceList {
|
|
invoiceUrls = append(invoiceUrls, *resource.ResourceUrl)
|
|
}
|
|
if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDEPOSIT) {
|
|
if resourceListLen == 1 {
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
InvoiceUrls: invoiceUrls,
|
|
}, nil
|
|
}
|
|
if resourceListLen == 0 {
|
|
receiptSnsFinal = ""
|
|
}
|
|
}
|
|
if *orderInfo.PayStatus == int64(constants.ORDER_PAY_STATUS_PAIDDREMAINING) {
|
|
if resourceListLen == 2 {
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
InvoiceUrls: invoiceUrls,
|
|
}, nil
|
|
}
|
|
if resourceListLen == 1 {
|
|
receiptSnsDeposit = ""
|
|
}
|
|
}
|
|
} else {
|
|
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, errors.New("get order invoice failed, not found")
|
|
}
|
|
} else {
|
|
err = errors.New("get order invoice failed, pay status is illegality")
|
|
errorCode = *basic.CodeErrOrderInvoiceStatusIllegality
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
}
|
|
|
|
ress, err := d.OrderDetailHandler(ctx, &orderInfo, 1)
|
|
if err != nil {
|
|
logc.Errorf(ctx, "order invoice detail handler failed, err: %v", err)
|
|
errorCode = *basic.CodeServiceErr
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
} else {
|
|
var model001 = constants.INVOICE_TEMPLATE_01
|
|
var model002 string
|
|
var model003 string
|
|
var model004 string
|
|
var model005 string
|
|
var model006 = constants.INVOICE_TEMPLATE_06
|
|
|
|
ctimeDate := orderInfo.Ctime.Format("2006/01/02")
|
|
var name string
|
|
var city string
|
|
var street string
|
|
var state string
|
|
var suite string
|
|
var zipCode string
|
|
if ress.OrderDetail.DeliveryAddress != nil {
|
|
name = fmt.Sprintf("%s %s", ress.OrderDetail.DeliveryAddress.FirstName, ress.OrderDetail.DeliveryAddress.LastName)
|
|
street = ress.OrderDetail.DeliveryAddress.Street
|
|
city = ress.OrderDetail.DeliveryAddress.City
|
|
state = ress.OrderDetail.DeliveryAddress.State
|
|
suite = ress.OrderDetail.DeliveryAddress.Suite
|
|
zipCode = ress.OrderDetail.DeliveryAddress.ZipCode
|
|
} else {
|
|
// 邮箱
|
|
modelUser := d.MysqlConn.Model(&gmodel.FsUser{})
|
|
if in.UserId != 0 {
|
|
modelUser = modelUser.Where("id = ?", in.UserId)
|
|
}
|
|
var userInfo = &gmodel.FsUser{}
|
|
result1 := modelUser.Debug().Take(&userInfo)
|
|
if result1.Error != nil {
|
|
if errors.Is(result1.Error, gorm.ErrRecordNotFound) {
|
|
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
|
} else {
|
|
errorCode = *basic.CodeServiceErr
|
|
}
|
|
logc.Errorf(ctx, "order invoice trade failed, err: %v", err)
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, result1.Error
|
|
}
|
|
if userInfo.Email != nil {
|
|
name = *userInfo.Email
|
|
}
|
|
}
|
|
|
|
var products string
|
|
for _, orderProduct := range ress.OrderDetail.OrderProduct {
|
|
var model00301 = constants.INVOICE_TEMPLATE_0301
|
|
|
|
var priceStr = format.NumToStringWithThousandthPercentile(orderProduct.ItemPrice.Current.CurrentAmount.(string))
|
|
var price = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(orderProduct.ItemPrice.Current.CurrentCurrency)], priceStr)
|
|
|
|
var priceTotalStr = format.NumToStringWithThousandthPercentile(orderProduct.TotalPrice.Current.CurrentAmount.(string))
|
|
var priceTotal = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(orderProduct.TotalPrice.Current.CurrentCurrency)], priceTotalStr)
|
|
|
|
productNum := strconv.FormatFloat(orderProduct.PurchaseQuantity.Current.(float64), 'f', -1, 64)
|
|
var productNumStr = format.NumToStringWithThousandthPercentile(productNum)
|
|
|
|
var productsInfo = fmt.Sprintf(model00301, orderProduct.ProductName, price, productNumStr, priceTotal)
|
|
products = products + productsInfo
|
|
}
|
|
model003 = fmt.Sprintf(constants.INVOICE_TEMPLATE_03, products)
|
|
var subtotalStr = format.NumToStringWithThousandthPercentile(ress.OrderDetail.OrderAmount.Subtotal.Current.CurrentAmount.(string))
|
|
var subtotal = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Subtotal.Current.CurrentCurrency)], subtotalStr)
|
|
var taxStr = "0.00"
|
|
if ress.OrderDetail.OrderAmount.Tax.Current.CurrentAmount != nil {
|
|
taxStr = ress.OrderDetail.OrderAmount.Tax.Current.CurrentAmount.(string)
|
|
}
|
|
var taxCurrency string = constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Tax.Current.CurrentCurrency)]
|
|
if taxCurrency == "" {
|
|
taxCurrency = constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Total.Current.CurrentCurrency)]
|
|
}
|
|
var tax = fmt.Sprintf("%s%s", taxCurrency, taxStr)
|
|
var totalStr = format.NumToStringWithThousandthPercentile(ress.OrderDetail.OrderAmount.Total.Current.CurrentAmount.(string))
|
|
var total = fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Total.Current.CurrentCurrency)], totalStr)
|
|
|
|
// 生成收据发票--首款
|
|
if receiptSnsDeposit != "" {
|
|
model002 = fmt.Sprintf(constants.INVOICE_TEMPLATE_02, receiptSnsDeposit, name, ctimeDate, street+" "+suite, city, state+zipCode)
|
|
|
|
var payAmountStr01 = format.NumToStringWithThousandthPercentile(ress.OrderDetail.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(string))
|
|
v7 := "Deposit Requested"
|
|
v8 := fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.Deposit.PayAmount.Current.CurrentCurrency)], payAmountStr01)
|
|
v9 := "Deposit Due"
|
|
v10 := v8
|
|
model004 = fmt.Sprintf(constants.INVOICE_TEMPLATE_04, subtotal, tax, total, v7, v8, v9, v10)
|
|
|
|
cardSn := "****" + *orderTradeDeposit.CardSn
|
|
model005 = fmt.Sprintf(constants.INVOICE_TEMPLATE_05, *orderTradeDeposit.CardBrand, cardSn)
|
|
|
|
var content = model001 + model002 + model003 + model004 + model005 + model006
|
|
|
|
base64, err := pdf.HtmlToPdfBase64(content, "html", "Letter")
|
|
if err != nil {
|
|
logc.Errorf(ctx, "order invoice HtmlToPdfBase64 failed, err: %v", err)
|
|
errorCode = *basic.CodeServiceErr
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
}
|
|
// 根据hash 查询数据资源
|
|
var resourceId string = hash.JsonHashKey(receiptSnsDeposit)
|
|
|
|
// 上传文件
|
|
var upload = file.Upload{
|
|
Ctx: ctx,
|
|
MysqlConn: d.MysqlConn,
|
|
AwsSession: d.AwsSession,
|
|
}
|
|
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
|
|
FileHash: resourceId,
|
|
FileData: "data:application/pdf;base64," + base64,
|
|
UploadBucket: 1,
|
|
ApiType: 2,
|
|
UserId: *orderInfo.UserId,
|
|
GuestId: 0,
|
|
Source: "order_invoice",
|
|
Refresh: 1,
|
|
})
|
|
if err != nil {
|
|
if err != nil {
|
|
logc.Errorf(ctx, "order invoice UploadFileByBase64 failed, err: %v", err)
|
|
errorCode = *basic.CodeServiceErr
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
}
|
|
}
|
|
invoiceUrls = append(invoiceUrls, uploadRes.ResourceUrl)
|
|
}
|
|
|
|
// 生成收据发票--尾款
|
|
if receiptSnsFinal != "" {
|
|
model002 = fmt.Sprintf(constants.INVOICE_TEMPLATE_02, receiptSnsDeposit, name, ctimeDate, street+" "+suite, city, state+zipCode)
|
|
var payAmountStr02 = format.NumToStringWithThousandthPercentile(ress.OrderDetail.OrderAmount.RemainingBalance.PayAmount.Current.CurrentAmount.(string))
|
|
v7 := "Balance Requested"
|
|
v8 := fmt.Sprintf("%s%s", constants.OrderCurrencyMessage[constants.Currency(ress.OrderDetail.OrderAmount.RemainingBalance.PayAmount.Current.CurrentCurrency)], payAmountStr02)
|
|
v9 := "Balance Due"
|
|
v10 := v8
|
|
model004 = fmt.Sprintf(constants.INVOICE_TEMPLATE_04, subtotal, tax, total, v7, v8, v9, v10)
|
|
|
|
cardSn := "****" + *orderTradeFinal.CardSn
|
|
model005 = fmt.Sprintf(constants.INVOICE_TEMPLATE_05, *orderTradeDeposit.CardBrand, cardSn)
|
|
var content = model001 + model002 + model003 + model004 + model005 + model006
|
|
base64, err := pdf.HtmlToPdfBase64(content, "html", "Letter")
|
|
if err != nil {
|
|
logc.Errorf(ctx, "order invoice HtmlToPdfBase64 failed, err: %v", err)
|
|
errorCode = *basic.CodeServiceErr
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
}
|
|
// 根据hash 查询数据资源
|
|
var resourceId string = hash.JsonHashKey(receiptSnsDeposit)
|
|
|
|
// 上传文件
|
|
var upload = file.Upload{
|
|
Ctx: ctx,
|
|
MysqlConn: d.MysqlConn,
|
|
AwsSession: d.AwsSession,
|
|
}
|
|
uploadRes, err := upload.UploadFileByBase64(&file.UploadBaseReq{
|
|
FileHash: resourceId,
|
|
FileData: "data:application/pdf;base64," + base64,
|
|
UploadBucket: 1,
|
|
ApiType: 2,
|
|
UserId: *orderInfo.UserId,
|
|
GuestId: 0,
|
|
Source: "order_invoice",
|
|
Refresh: 1,
|
|
})
|
|
if err != nil {
|
|
if err != nil {
|
|
logc.Errorf(ctx, "order invoice UploadFileByBase64 failed, err: %v", err)
|
|
errorCode = *basic.CodeServiceErr
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
}, err
|
|
}
|
|
}
|
|
invoiceUrls = append(invoiceUrls, uploadRes.ResourceUrl)
|
|
}
|
|
|
|
return &InvoiceRes{
|
|
ErrorCode: errorCode,
|
|
InvoiceUrls: invoiceUrls,
|
|
}, nil
|
|
}
|
|
}
|
|
|
|
// 订单删除
|
|
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
|
|
}
|
|
|
|
// 新增交易信息
|
|
receiptSn := order.GenerateReceiptNumber()
|
|
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,
|
|
ReceiptSn: &receiptSn,
|
|
})
|
|
|
|
// 更新数据库
|
|
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 && in.DeliveryAddress != nil {
|
|
orderAddress = &gmodel.OrderAddress{
|
|
Street: in.DeliveryAddress.Street,
|
|
City: in.DeliveryAddress.City,
|
|
FirstName: in.DeliveryAddress.FirstName,
|
|
LastName: in.DeliveryAddress.LastName,
|
|
Mobile: in.DeliveryAddress.Mobile,
|
|
State: in.DeliveryAddress.State,
|
|
Suite: in.DeliveryAddress.Suite,
|
|
ZipCode: in.DeliveryAddress.ZipCode,
|
|
}
|
|
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
|
|
}
|
|
} else {
|
|
var orderAddress *gmodel.OrderAddress
|
|
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 = d.MysqlConn.Exec(fmt.Sprintf("UPDATE %s SET `delivery_method` = ? , `utime` = ?, `status_link` = JSON_MERGE_PATCH(`status_link`,?), `order_address` = JSON_MERGE_PATCH(`order_address`,?) WHERE `id` = ?", table), in.DeliveryMethod, ntime, statusLinkByte, orderAddressByte, 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{
|
|
Street: in.DeliveryAddress.Street,
|
|
City: in.DeliveryAddress.City,
|
|
FirstName: in.DeliveryAddress.FirstName,
|
|
LastName: in.DeliveryAddress.LastName,
|
|
Mobile: in.DeliveryAddress.Mobile,
|
|
State: in.DeliveryAddress.State,
|
|
Suite: in.DeliveryAddress.Suite,
|
|
ZipCode: in.DeliveryAddress.ZipCode,
|
|
}
|
|
}
|
|
// 预计交付时间
|
|
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)
|
|
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
|
|
}
|