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

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
}