fix:支付
This commit is contained in:
@@ -4,10 +4,14 @@ import (
|
||||
"context"
|
||||
"encoding/json"
|
||||
"errors"
|
||||
"fmt"
|
||||
"fusenapi/constants"
|
||||
"fusenapi/model/gmodel"
|
||||
"fusenapi/utils/basic"
|
||||
"fusenapi/utils/fssql"
|
||||
"fusenapi/utils/handlers"
|
||||
"fusenapi/utils/order"
|
||||
"fusenapi/utils/pay"
|
||||
"time"
|
||||
|
||||
"github.com/aws/aws-sdk-go/aws/session"
|
||||
@@ -28,8 +32,10 @@ type (
|
||||
Order interface {
|
||||
// 下单
|
||||
Create(ctx context.Context, in *CreateReq) (res *CreateRes, err error)
|
||||
// 预支付
|
||||
// 预支付--定金
|
||||
CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error)
|
||||
// 列表
|
||||
List(ctx context.Context, in *ListReq) (res *ListRes, err error)
|
||||
// 详情
|
||||
Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error)
|
||||
}
|
||||
@@ -39,6 +45,38 @@ type (
|
||||
Mobile string `json:"mobile"` // 手机
|
||||
Name string `json:"name"` // 姓名
|
||||
}
|
||||
OrderPay struct {
|
||||
ClientSecret string `json:"client_secret"` // 支付方--秘钥
|
||||
Country string `json:"country"` // 国家
|
||||
Currency string `json:"currency"` // 货币
|
||||
Metadata map[string]interface{} `json:"metadata"` // 额外参数
|
||||
Method string `json:"method"` // 支付方--途径
|
||||
OrderSn string `json:"order_sn"` // 订单编码
|
||||
PayStage int64 `json:"pay_stage"` // 支付阶段
|
||||
RedirectURL *string `json:"redirect_url"` // 支付方--重定向地址
|
||||
Total OrderPayTotal `json:"total"` // 支付参数
|
||||
}
|
||||
// 支付参数
|
||||
OrderPayTotal struct {
|
||||
Amount int64 `json:"amount"` // 金额
|
||||
Label string `json:"label"` // 标签
|
||||
}
|
||||
/* 预支付--定金 */
|
||||
CreatePrePaymentByDepositReq struct {
|
||||
StripeKey string `json:"stripe_key"`
|
||||
Currency string `json:"currency"`
|
||||
Country string `json:"country"`
|
||||
UserId int64 `json:"user_id"`
|
||||
OrderSn string `json:"order_sn"`
|
||||
DeliveryMethod int64 `json:"delivery_method"`
|
||||
DeliveryAddress *OrderAddress `json:"delivery_address"` // 收货地址
|
||||
}
|
||||
CreatePrePaymentByDepositRes struct {
|
||||
ErrorCode basic.StatusResponse
|
||||
OrderDetail gmodel.OrderDetail
|
||||
OrderPay OrderPay
|
||||
}
|
||||
/* 预支付--定金 */
|
||||
|
||||
/* 下单 */
|
||||
CreateReq struct {
|
||||
@@ -63,49 +101,291 @@ type (
|
||||
OrderSn string `json:"order_sn"`
|
||||
}
|
||||
DetailRes struct {
|
||||
OrderDetail gmodel.OrderDetail
|
||||
ErrorCode basic.StatusResponse
|
||||
OrderDetail gmodel.OrderDetail
|
||||
OrderDetailOriginal gmodel.OrderDetail
|
||||
}
|
||||
/* 详情 */
|
||||
|
||||
/* 列表 */
|
||||
ListReq struct {
|
||||
UserId int64 `json:"user_id"`
|
||||
DeliveryMethod int64 `json:"delivery_method"`
|
||||
OrderCycle string `json:"order_cycle"`
|
||||
CurrentPage int64 `json:"current_page"`
|
||||
PerPage int64 `json:"per_page"`
|
||||
}
|
||||
ListRes struct {
|
||||
OrderDetailList []gmodel.OrderDetail
|
||||
Meta interface{}
|
||||
}
|
||||
/* 列表 */
|
||||
)
|
||||
|
||||
// 详情
|
||||
func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) {
|
||||
// 预支付--定金
|
||||
func (d *defaultOrder) CreatePrePaymentByDeposit(ctx context.Context, in *CreatePrePaymentByDepositReq) (res *CreatePrePaymentByDepositRes, err error) {
|
||||
var errorCode basic.StatusResponse
|
||||
var order gmodel.FsOrder
|
||||
result := d.MysqlConn.Where("order_sn = ?", in.OrderSn).Where("user_id = ?", in.UserId).Take(&order)
|
||||
if result.Error != nil {
|
||||
logx.Errorf("detail failed, err: %v", err)
|
||||
return nil, result.Error
|
||||
model := d.MysqlConn.Where("is_del = ?", 0)
|
||||
if in.UserId != 0 {
|
||||
model.Where("user_id = ?", in.UserId)
|
||||
}
|
||||
if in.OrderSn != "" {
|
||||
model.Where("order_sn = ?", in.OrderSn)
|
||||
}
|
||||
result := model.Take(&order)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
||||
} else {
|
||||
errorCode = *basic.CodeServiceErr
|
||||
}
|
||||
logx.Errorf("create prePayment deposit failed, err: %v", err)
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, result.Error
|
||||
}
|
||||
|
||||
// 非未支付
|
||||
if *order.PayStatus != int64(constants.ORDERPAYSTATUSUNPAIDDEPOSIT) {
|
||||
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
||||
err = errors.New("order pay status is not unPaidDeposit")
|
||||
logx.Errorf("create prePayment deposit failed, err: %v", err)
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, err
|
||||
}
|
||||
|
||||
// 是否超时支付
|
||||
ntime := time.Now().UTC()
|
||||
ctime := *order.Ctime
|
||||
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
|
||||
ntimeTimeOut := ntime.Unix()
|
||||
if ctimeTimeOut == ntimeTimeOut {
|
||||
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
|
||||
err = errors.New("order pay timeout")
|
||||
logx.Errorf("create prePayment deposit failed, err: %v", err)
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, err
|
||||
}
|
||||
|
||||
ress, err := d.OrderDetailHandler(ctx, &order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
logx.Errorf("create prePayment deposit failed DetailOrderDetailHandler, err: %v", err)
|
||||
errorCode = *basic.CodeServiceErr
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, err
|
||||
}
|
||||
return &DetailRes{
|
||||
ress.OrderDetail,
|
||||
|
||||
var uOrderDetail = make(map[string]interface{})
|
||||
|
||||
var orderAddress *gmodel.OrderAddress
|
||||
if in.DeliveryAddress != nil {
|
||||
if in.DeliveryAddress.Name != ress.OrderDetailOriginal.DeliveryAddress.Name || in.DeliveryAddress.Address != ress.OrderDetail.DeliveryAddress.Address || in.DeliveryAddress.Mobile != ress.OrderDetail.DeliveryAddress.Mobile {
|
||||
orderAddress = &gmodel.OrderAddress{
|
||||
Name: in.DeliveryAddress.Name,
|
||||
Mobile: in.DeliveryAddress.Mobile,
|
||||
Address: in.DeliveryAddress.Address,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
var sql string = fmt.Sprintf(", `utime` = '%s'", ntime)
|
||||
// 是否更新
|
||||
if in.DeliveryMethod != *order.DeliveryMethod {
|
||||
sql = sql + fmt.Sprintf(",`delivery_method` = %d", in.DeliveryMethod)
|
||||
if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
|
||||
uOrderDetail["delivery_address"] = orderAddress
|
||||
} else {
|
||||
uOrderDetail["delivery_address"] = nil
|
||||
}
|
||||
uOrderDetail["order_info"] = struct {
|
||||
DeliveryMethod int64 `json:"delivery_method"`
|
||||
Utime *time.Time `json:"utime"`
|
||||
}{
|
||||
DeliveryMethod: in.DeliveryMethod,
|
||||
Utime: &ntime,
|
||||
}
|
||||
} else {
|
||||
if in.DeliveryMethod == constants.DELIVERYMETHODDIRECTMAIL {
|
||||
// 更新收货地址
|
||||
if orderAddress != nil {
|
||||
uOrderDetail["delivery_address"] = orderAddress
|
||||
uOrderDetail["order_info"] = struct {
|
||||
DeliveryMethod int64 `json:"delivery_method"`
|
||||
Utime *time.Time `json:"utime"`
|
||||
}{
|
||||
DeliveryMethod: in.DeliveryMethod,
|
||||
Utime: &ntime,
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if len(uOrderDetail) > 0 {
|
||||
err = fssql.MetadataOrderPATCH(d.MysqlConn, sql, in.OrderSn, gmodel.FsOrder{}, uOrderDetail, "id = ?", order.Id)
|
||||
if err != nil {
|
||||
errorCode = *basic.CodeServiceErr
|
||||
logx.Errorf("create prePayment deposit failed MetadataOrderPATCH, err: %v", err)
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, result.Error
|
||||
}
|
||||
}
|
||||
|
||||
ress.OrderDetail.OrderInfo.Utime = &ntime
|
||||
ress.OrderDetail.OrderInfo.DeliveryMethod = in.DeliveryMethod
|
||||
ress.OrderDetail.DeliveryAddress = orderAddress
|
||||
|
||||
// 支付初始化
|
||||
amount := int64(ress.OrderDetailOriginal.OrderAmount.Deposit.PayAmount.Current.CurrentAmount.(float64) / float64(10))
|
||||
payConfig := &pay.Config{}
|
||||
payConfig.Stripe.PayType = "intent"
|
||||
payConfig.Stripe.Key = in.StripeKey
|
||||
var generatePrepaymentReq = &pay.GeneratePrepaymentReq{
|
||||
OrderSn: in.OrderSn,
|
||||
ProductName: "支付标题",
|
||||
Amount: amount,
|
||||
Currency: "usd",
|
||||
Quantity: 1,
|
||||
ProductDescription: "支付描述",
|
||||
}
|
||||
payDriver := pay.NewPayDriver(1, payConfig)
|
||||
|
||||
prepaymentRes, err := payDriver.GeneratePrepayment(generatePrepaymentReq)
|
||||
if err != nil {
|
||||
logx.Errorf("create prePayment deposit failed GeneratePrepayment, err: %v", err)
|
||||
errorCode = *basic.CodeServiceErr
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
ErrorCode: errorCode,
|
||||
}, nil
|
||||
}
|
||||
return &CreatePrePaymentByDepositRes{
|
||||
OrderDetail: ress.OrderDetail,
|
||||
OrderPay: OrderPay{
|
||||
ClientSecret: prepaymentRes.ClientSecret,
|
||||
Country: in.Country,
|
||||
Currency: in.Currency,
|
||||
Method: payConfig.Stripe.PayType,
|
||||
OrderSn: in.OrderSn,
|
||||
PayStage: 1,
|
||||
Total: OrderPayTotal{
|
||||
Amount: amount,
|
||||
Label: "",
|
||||
},
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder) (res *DetailRes, err error) {
|
||||
var orderDetail gmodel.OrderDetail
|
||||
// 列表
|
||||
func (d *defaultOrder) List(ctx context.Context, in *ListReq) (res *ListRes, err error) {
|
||||
var orderList []gmodel.FsOrder
|
||||
model := d.MysqlConn.Model(&gmodel.FsOrder{}).Where("is_del = ?", 0)
|
||||
if in.UserId != 0 {
|
||||
model.Where("user_id = ?", in.UserId)
|
||||
}
|
||||
|
||||
err = json.Unmarshal(*orderInfo.Metadata, &orderDetail)
|
||||
// Where("pay_status > ?", 0)
|
||||
if in.DeliveryMethod != 0 {
|
||||
model.Where("delivery_method = ?", in.DeliveryMethod)
|
||||
}
|
||||
if in.OrderCycle != "" {
|
||||
// 下单时间
|
||||
switch in.OrderCycle {
|
||||
case "within_one_month":
|
||||
model.Where("ctime >?", time.Now().UTC().AddDate(0, -1, 0).Unix())
|
||||
case "within_three_month":
|
||||
model.Where("ctime >?", time.Now().UTC().AddDate(0, -3, 0).Unix())
|
||||
case "within_six_month":
|
||||
model.Where("ctime >?", time.Now().UTC().AddDate(0, -6, 0).Unix())
|
||||
case "within_one_year":
|
||||
model.Where("ctime >?", time.Now().UTC().AddDate(-1, 0, 0).Unix())
|
||||
}
|
||||
}
|
||||
var count int64
|
||||
resultCount := model.Count(&count)
|
||||
if resultCount.Error != nil {
|
||||
logx.Errorf("order count failed, err: %v", err)
|
||||
return nil, resultCount.Error
|
||||
}
|
||||
var orderDetailList []gmodel.OrderDetail
|
||||
if count > 0 {
|
||||
m := model.Scopes(handlers.Paginate(&in.CurrentPage, &in.PerPage))
|
||||
result := m.Find(&orderList)
|
||||
if result.Error != nil {
|
||||
logx.Errorf("order list failed, err: %v", err)
|
||||
return nil, result.Error
|
||||
}
|
||||
for _, order := range orderList {
|
||||
ress, err := d.OrderDetailHandler(ctx, &order)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
orderDetailList = append(orderDetailList, ress.OrderDetail)
|
||||
}
|
||||
} else {
|
||||
orderDetailList = make([]gmodel.OrderDetail, 0)
|
||||
}
|
||||
return &ListRes{
|
||||
OrderDetailList: orderDetailList,
|
||||
Meta: map[string]int64{
|
||||
"total_count": count,
|
||||
"page_count": count / in.PerPage,
|
||||
"current_page": in.CurrentPage,
|
||||
"per_page": in.PerPage,
|
||||
},
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 详情
|
||||
func (d *defaultOrder) Detail(ctx context.Context, in *DetailReq) (res *DetailRes, err error) {
|
||||
var errorCode basic.StatusResponse
|
||||
var order gmodel.FsOrder
|
||||
model := d.MysqlConn.Where("is_del = ?", 0)
|
||||
if in.UserId != 0 {
|
||||
model.Where("user_id = ?", in.UserId)
|
||||
}
|
||||
if in.OrderSn != "" {
|
||||
model.Where("order_sn = ?", in.OrderSn)
|
||||
}
|
||||
result := model.Take(&order)
|
||||
if result.Error != nil {
|
||||
if errors.Is(result.Error, gorm.ErrRecordNotFound) {
|
||||
errorCode = *basic.CodeErrOrderCreatePrePaymentInfoNoFound
|
||||
} else {
|
||||
errorCode = *basic.CodeServiceErr
|
||||
}
|
||||
logx.Errorf("order detail failed, err: %v", err)
|
||||
return &DetailRes{
|
||||
ErrorCode: errorCode,
|
||||
}, result.Error
|
||||
}
|
||||
|
||||
// 是否超时支付
|
||||
ctime := *order.Ctime
|
||||
ctimeTimeOut := ctime.Add(30 * time.Minute).UTC().Unix()
|
||||
ntimeTimeOut := time.Now().UTC().Unix()
|
||||
if ctimeTimeOut < ntimeTimeOut {
|
||||
errorCode = *basic.CodeErrOrderCreatePrePaymentTimeout
|
||||
err = errors.New("order pay timeout")
|
||||
logx.Errorf("order detail failed, err: %v", err)
|
||||
return &DetailRes{
|
||||
ErrorCode: errorCode,
|
||||
}, err
|
||||
}
|
||||
|
||||
ress, err := d.OrderDetailHandler(ctx, &order)
|
||||
if err != nil {
|
||||
logx.Errorf("detail handler unmarshal metadata failed, err: %v", err)
|
||||
return nil, err
|
||||
logx.Errorf("order detail failed, err: %v", err)
|
||||
errorCode = *basic.CodeServiceErr
|
||||
return &DetailRes{
|
||||
ErrorCode: errorCode,
|
||||
}, err
|
||||
}
|
||||
for orderProductKey, orderProduct := range orderDetail.OrderProduct {
|
||||
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
|
||||
orderDetail.OrderProduct[orderProductKey].ItemPrice = order.GetAmountInfoFormat(&orderProduct.ItemPrice)
|
||||
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot = nil
|
||||
orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil
|
||||
}
|
||||
orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink)
|
||||
orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount)
|
||||
orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.RemainingBalance.PayAmount)
|
||||
orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal)
|
||||
orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total)
|
||||
return &DetailRes{
|
||||
OrderDetail: orderDetail,
|
||||
ErrorCode: errorCode,
|
||||
OrderDetail: ress.OrderDetail,
|
||||
}, nil
|
||||
}
|
||||
|
||||
@@ -396,6 +676,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
|
||||
OrderInfo: orderInfo,
|
||||
OrderProduct: orderProductList,
|
||||
PayStatus: payStatus,
|
||||
PayTimeout: 30 * time.Minute,
|
||||
}
|
||||
// 数据库操作
|
||||
|
||||
@@ -419,7 +700,7 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
|
||||
return nil
|
||||
})
|
||||
if err != nil {
|
||||
logx.Errorf("create order failed, err: %v", err)
|
||||
logx.Errorf("order create order failed, err: %v", err)
|
||||
|
||||
if errorCode.Code == 0 {
|
||||
errorCode.Code = basic.CodeApiErr.Code
|
||||
@@ -435,3 +716,32 @@ func (d *defaultOrder) Create(ctx context.Context, in *CreateReq) (res *CreateRe
|
||||
ErrorCode: errorCode,
|
||||
}, nil
|
||||
}
|
||||
|
||||
// 详情处理
|
||||
func (d *defaultOrder) OrderDetailHandler(ctx context.Context, orderInfo *gmodel.FsOrder) (res *DetailRes, err error) {
|
||||
var orderDetail gmodel.OrderDetail
|
||||
|
||||
err = json.Unmarshal(*orderInfo.Metadata, &orderDetail)
|
||||
if err != nil {
|
||||
logx.Errorf("order detail handler unmarshal metadata failed, err: %v", err)
|
||||
return nil, err
|
||||
}
|
||||
orderDetailOriginal := orderDetail
|
||||
for orderProductKey, orderProduct := range orderDetail.OrderProduct {
|
||||
orderDetail.OrderProduct[orderProductKey].TotalPrice = order.GetAmountInfoFormat(&orderProduct.TotalPrice)
|
||||
orderDetail.OrderProduct[orderProductKey].ItemPrice = order.GetAmountInfoFormat(&orderProduct.ItemPrice)
|
||||
orderDetail.OrderProduct[orderProductKey].ShoppingCartSnapshot = nil
|
||||
orderDetail.OrderProduct[orderProductKey].ProductSnapshot = nil
|
||||
}
|
||||
orderDetail.OrderInfo.StatusLink = order.GetOrderStatusLinkUser(orderDetail.OrderInfo.DeliveryMethod, orderDetail.OrderInfo.StatusLink)
|
||||
orderDetail.OrderAmount.Deposit.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Deposit.PayAmount)
|
||||
orderDetail.OrderAmount.RemainingBalance.PayAmount = order.GetAmountInfoFormat(&orderDetail.OrderAmount.RemainingBalance.PayAmount)
|
||||
orderDetail.OrderAmount.Subtotal = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Subtotal)
|
||||
orderDetail.OrderAmount.Total = order.GetAmountInfoFormat(&orderDetail.OrderAmount.Total)
|
||||
orderDetail.PayTimeout = time.Duration(orderDetail.OrderInfo.Ctime.Add(orderDetail.PayTimeout).UTC().Unix() - time.Now().UTC().Unix())
|
||||
|
||||
return &DetailRes{
|
||||
OrderDetail: orderDetail,
|
||||
OrderDetailOriginal: orderDetailOriginal,
|
||||
}, nil
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user