You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
392 lines
9.3 KiB
392 lines
9.3 KiB
package recookpay
|
|
|
|
import (
|
|
"errors"
|
|
"fmt"
|
|
"recook/internal/api/mobile/pay/public"
|
|
"recook/internal/back"
|
|
"recook/internal/dbc"
|
|
"recook/internal/model/order"
|
|
"recook/internal/model/user"
|
|
"recook/internal/v2/model/jyy"
|
|
"recook/internal/v2/model/recook/goods"
|
|
user2 "recook/internal/v2/model/recook/user"
|
|
"recook/tools"
|
|
"time"
|
|
|
|
"github.com/jinzhu/gorm"
|
|
|
|
"github.com/gin-gonic/gin"
|
|
"github.com/golangkit/formatime"
|
|
"github.com/shopspring/decimal"
|
|
)
|
|
|
|
type appCreateOrderParam struct {
|
|
UserID uint `json:"userId" validate:"required"`
|
|
OrderID uint `json:"orderId" validate:"required"`
|
|
Password string `json:"password"`
|
|
}
|
|
|
|
const passwordLockCount = 5
|
|
|
|
/*
|
|
扣除余额
|
|
生成扣除记录
|
|
|
|
*/
|
|
const (
|
|
ErrorBalance = "订单含报税仓或海外仓库,无法使用余额支付"
|
|
ErrorWallet = "余额不足,请使用其它方式支付"
|
|
)
|
|
|
|
func createOrder(virtualID uint, ip string, userID uint, password string, is bool) error {
|
|
var od []order.Information
|
|
if err := dbc.DB.Find(&od, "virtual_id = ?", virtualID).Error; err != nil {
|
|
return err
|
|
}
|
|
if len(od) != 0 {
|
|
if !od[0].CanPay && od[0].OrderType == 2 {
|
|
return errors.New("批发订单运费未确定无法支付")
|
|
}
|
|
}
|
|
|
|
var id []uint
|
|
for _, v := range od {
|
|
id = append(id, v.ID)
|
|
}
|
|
var detail []order.GoodsDetail
|
|
if err := dbc.DB.Find(&detail, "order_id in (?)", id).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if err := public.UpdateVirtualPay(virtualID); err != nil {
|
|
return err
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
|
|
amount := decimal.Zero
|
|
for _, v := range od {
|
|
if err := public.ValidateOrderInfo(&v, now); err != nil {
|
|
return err
|
|
}
|
|
amount = amount.Add(v.ActualTotalAmount)
|
|
}
|
|
var rg goods.RecookGoodsInfoModel
|
|
for _, v := range detail {
|
|
if !rg.HasBalance(v.Storehouse) {
|
|
return errors.New(ErrorBalance)
|
|
}
|
|
}
|
|
var wallet user.Wallet
|
|
if err := dbc.DB.First(&wallet, "user_id = ?", userID).Error; err != nil {
|
|
return err
|
|
}
|
|
if err := walletCheck(&wallet, now, password); err != nil {
|
|
return err
|
|
}
|
|
|
|
if !is {
|
|
// 余额支付
|
|
if wallet.Balance.LessThan(amount) {
|
|
return errors.New(ErrorWallet)
|
|
}
|
|
|
|
tx := dbc.DB.Begin()
|
|
{
|
|
for _, o := range od {
|
|
|
|
if err := payOrder(tx, o, &wallet, ip); err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
tx.Commit()
|
|
} else {
|
|
// 预存款支付
|
|
var wallet2 jyy.UserWallet
|
|
dbc.DB.First(&wallet2, "user_id = ?", userID)
|
|
if wallet2.Deposit.LessThan(amount) {
|
|
return errors.New(ErrorWallet)
|
|
}
|
|
tx := dbc.DB.Begin()
|
|
{
|
|
|
|
for _, o := range od {
|
|
|
|
if err := payDeposit(tx, o, &wallet2, ip); err != nil {
|
|
tx.Rollback()
|
|
return err
|
|
}
|
|
}
|
|
}
|
|
tx.Commit()
|
|
}
|
|
|
|
return nil
|
|
}
|
|
|
|
func walletCheck(wallet *user.Wallet, now int64, passwd string) error {
|
|
if wallet.ErrorCount == passwordLockCount && wallet.UnlockTime.Time.Unix() >= now { // 密码正在锁定中
|
|
return errors.New("密码锁定中,请稍后再试")
|
|
} else {
|
|
if tools.SHA256Str(passwd) != wallet.Password {
|
|
if wallet.ErrorCount == passwordLockCount-1 {
|
|
dbc.DB.Model(&wallet).Updates(user.Wallet{
|
|
ErrorCount: wallet.ErrorCount + 1,
|
|
UnlockTime: formatime.NewSecondFrom(time.Now().Add(time.Minute * 10)),
|
|
})
|
|
return fmt.Errorf("%d次错误,密码已被锁定,请10分钟后再试", passwordLockCount)
|
|
} else {
|
|
if wallet.UnlockTime.Time.Unix() < now && wallet.ErrorCount == passwordLockCount {
|
|
dbc.DB.Model(&wallet).Updates(map[string]interface{}{
|
|
"error_count": 1,
|
|
"unlock_time": nil,
|
|
})
|
|
return errors.New("密码错误")
|
|
}
|
|
dbc.DB.Model(&wallet).Updates(user.Wallet{
|
|
ErrorCount: wallet.ErrorCount + 1,
|
|
})
|
|
return errors.New("密码错误")
|
|
}
|
|
} else {
|
|
dbc.DB.Model(&wallet).Updates(map[string]interface{}{
|
|
"error_count": 0,
|
|
"unlock_time": nil,
|
|
})
|
|
}
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func payOrder(tx *gorm.DB, orderInfo order.Information, wallet *user.Wallet, ip string) error {
|
|
if err := tx.Model(&orderInfo).Updates(
|
|
map[string]interface{}{
|
|
"PayIP": ip,
|
|
"PayMethod": 0,
|
|
}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if orderInfo.ActualTotalAmount.GreaterThan(decimal.NewFromFloat(0.0)) {
|
|
if r := tx.Exec("UPDATE `recook_user_wallet` SET balance=balance-? WHERE id = ?",
|
|
orderInfo.ActualTotalAmount, wallet.ID).RowsAffected; r == 0 {
|
|
return errors.New("账户扣款失败")
|
|
}
|
|
|
|
recookUserWalletBalanceListModel := &user2.RecookUserWalletBalanceListModel{
|
|
UserId: wallet.UserID,
|
|
IncomeType: user2.RecookUserWalletBalanceListIncomeTypePay, // 订单支付
|
|
Amount: orderInfo.ActualTotalAmount.Mul(decimal.NewFromInt(-1)),
|
|
Title: orderInfo.Title,
|
|
Comment: "订单支付抵扣",
|
|
OrderId: orderInfo.ID,
|
|
OrderTime: orderInfo.CreatedAt,
|
|
}
|
|
recookUserWalletBalanceListModel.SetDb(tx)
|
|
recookUserWalletBalanceListModel.Create(recookUserWalletBalanceListModel)
|
|
if recookUserWalletBalanceListModel.Id == 0 {
|
|
return errors.New("系统异常")
|
|
}
|
|
}
|
|
|
|
if err := public.PaySuccessCallback(tx, orderInfo, formatime.NewSecondNow()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
|
|
func PayOrder(c *gin.Context) {
|
|
var p appCreateOrderParam
|
|
err := tools.ParseParams(&p, c)
|
|
if err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
|
|
if !public.Judge(p.OrderID) {
|
|
if err = createOrder(p.OrderID, c.ClientIP(), p.UserID, p.Password, false); err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
c.Set("status", "SyncOrder")
|
|
c.Set("id", p.OrderID)
|
|
back.Suc(c, "支付成功", nil)
|
|
return
|
|
}
|
|
|
|
if err = public.UpdateNormalPay(p.OrderID); err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
var orderInfo order.Information
|
|
|
|
err = dbc.DB.First(&orderInfo, "id = ?", p.OrderID).Error
|
|
if err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
|
|
if !orderInfo.CanPay && orderInfo.OrderType == 2 {
|
|
err = errors.New("批发订单运费未确定无法支付")
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
err = public.ValidateOrderInfo(&orderInfo, now)
|
|
if err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
|
|
var details []order.GoodsDetail
|
|
dbc.DB.Find(&details, "order_id = ?", p.OrderID)
|
|
recookGoodsInfoModel := &goods.RecookGoodsInfoModel{}
|
|
for _, detail := range details {
|
|
if !recookGoodsInfoModel.HasBalance(detail.Storehouse) {
|
|
back.Fail(c, ErrorBalance)
|
|
return
|
|
}
|
|
}
|
|
|
|
var wallet user.Wallet
|
|
dbc.DB.First(&wallet, "user_id = ?", orderInfo.UserID)
|
|
if wallet.Balance.LessThan(orderInfo.ActualTotalAmount) {
|
|
back.Fail(c, "余额不足,请使用其它方式支付")
|
|
return
|
|
}
|
|
|
|
if len(wallet.Password) == 0 {
|
|
back.Fail(c, "没有设置支付密码")
|
|
return
|
|
}
|
|
|
|
if err = walletCheck(&wallet, now, p.Password); err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
|
|
tx := dbc.DB.Begin()
|
|
{
|
|
if err = payOrder(tx, orderInfo, &wallet, c.ClientIP()); err != nil {
|
|
tx.Rollback()
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
}
|
|
tx.Commit()
|
|
c.Set("status", "SyncOrder")
|
|
c.Set("id", p.OrderID)
|
|
back.Suc(c, "支付成功", nil)
|
|
}
|
|
|
|
func PayDeposit(c *gin.Context) {
|
|
var p appCreateOrderParam
|
|
err := tools.ParseParams(&p, c)
|
|
if err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
|
|
if !public.Judge(p.OrderID) {
|
|
if err = createOrder(p.OrderID, c.ClientIP(), p.UserID, p.Password, true); err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
back.Suc(c, "支付成功", nil)
|
|
return
|
|
}
|
|
|
|
if err = public.UpdateNormalPay(p.OrderID); err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
|
|
now := time.Now().Unix()
|
|
var orderInfo order.Information
|
|
|
|
err = dbc.DB.First(&orderInfo, "id = ?", p.OrderID).Error
|
|
if err != nil {
|
|
back.Err(c, err.Error())
|
|
return
|
|
}
|
|
|
|
if !orderInfo.CanPay && orderInfo.OrderType == 2 {
|
|
err = errors.New("批发订单运费未确定无法支付")
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
err = public.ValidateOrderInfo(&orderInfo, now)
|
|
if err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
var wallet user.Wallet
|
|
dbc.DB.First(&wallet, "user_id = ?", orderInfo.UserID)
|
|
|
|
var wallet2 jyy.UserWallet
|
|
dbc.DB.First(&wallet2, "user_id = ?", orderInfo.UserID)
|
|
if wallet2.Deposit.LessThan(orderInfo.ActualTotalAmount) {
|
|
back.Fail(c, "余额不足,请使用其它方式支付")
|
|
return
|
|
}
|
|
|
|
if len(wallet.Password) == 0 {
|
|
back.Fail(c, "没有设置支付密码")
|
|
return
|
|
}
|
|
|
|
if err = walletCheck(&wallet, now, p.Password); err != nil {
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
|
|
tx := dbc.DB.Begin()
|
|
{
|
|
if err = payDeposit(tx, orderInfo, &wallet2, c.ClientIP()); err != nil {
|
|
tx.Rollback()
|
|
back.Fail(c, err.Error())
|
|
return
|
|
}
|
|
}
|
|
tx.Commit()
|
|
back.Suc(c, "支付成功", nil)
|
|
}
|
|
|
|
func payDeposit(tx *gorm.DB, orderInfo order.Information, wallet *jyy.UserWallet, ip string) error {
|
|
if err := tx.Model(&orderInfo).Updates(
|
|
map[string]interface{}{
|
|
"PayIP": ip,
|
|
"PayMethod": 10,
|
|
}).Error; err != nil {
|
|
return err
|
|
}
|
|
|
|
if orderInfo.ActualTotalAmount.GreaterThan(decimal.NewFromFloat(0.0)) {
|
|
if r := tx.Model(wallet).Where("version = ?", wallet.Version).Updates(map[string]interface{}{
|
|
"deposit": gorm.Expr("deposit - ?", orderInfo.ActualTotalAmount),
|
|
"version": gorm.Expr("version + 1"),
|
|
}).RowsAffected; r == 0 {
|
|
return errors.New("账户扣款失败")
|
|
}
|
|
if e := tx.Create(&jyy.UserWalletRecord{
|
|
WalletID: wallet.ID,
|
|
UserID: int(orderInfo.UserID),
|
|
Amount: orderInfo.ActualTotalAmount.Neg(),
|
|
Current: wallet.Deposit,
|
|
Kind: 1,
|
|
}).Error; e != nil {
|
|
return e
|
|
}
|
|
|
|
if err := public.PaySuccessCallback(tx, orderInfo, formatime.NewSecondNow()); err != nil {
|
|
return err
|
|
}
|
|
return nil
|
|
}
|
|
return nil
|
|
}
|