package service import ( "bkb-seller/dto" "bkb-seller/global" "bkb-seller/initialize/api" "bkb-seller/model" "bkb-seller/model/request" "bkb-seller/model/response" "bkb-seller/utils" "context" "encoding/json" "errors" "fmt" "google.golang.org/protobuf/types/known/emptypb" "time" "github.com/plutov/paypal" "gorm.io/gorm" ) func GetUserWalletDetail(storeNo string) (error, *model.Wallet) { var ( err error wallet model.Wallet ) err = global.MG_DB.Model(&model.Wallet{}).Where("user_id = ?", storeNo).First(&wallet).Error if err != nil { return errors.New("获取钱包失败"), nil } if wallet.AccountName != "" { wallet.AccountName = utils.HideStar(wallet.AccountName) } return nil, &wallet } func GetUserAccountList(storeNo string) (error, *model.Account) { var ( err error account model.Account ) err = global.MG_DB.Model(&model.Account{}).Where("user_id = ?", storeNo).Find(&account).Error if err != nil { return errors.New("获取用户账户失败"), nil } if account.ID != 0 { account.AccountName = utils.HideStar(account.AccountName) } return nil, &account } func AddUserAccount(storeNo string, info *request.AddAccount) error { var ( err error accountZ model.Account ) err = global.MG_DB.Model(&model.Account{}).Where("user_id = ?", storeNo).Find(&accountZ).Error if err != nil || accountZ.ID != 0 { return errors.New("已存在绑定账户,不可再次绑定") } tx := global.MG_DB.Begin() var account model.Account if info.CardNumber != "" { account.Type = 2 } account.UserID = storeNo account.Platform = "saller" account.AccountName = info.AccountName account.BankCode = info.BankCode account.SwiftCode = info.SwiftCode account.CardNumber = info.CardNumber account.Address = info.Address account.Country = info.Country account.Currency = info.Currency account.IsDefault = info.IsDefault err = tx.Model(&model.Account{}).Create(&account).Error if err != nil { tx.Rollback() return errors.New("绑定用户账户失败") } //uMap := make(map[string]interface{}) //uMap["account_name"] = data.AccountName //uMap["id_card"] = data.IDCard //err = tx.Model(&model.Wallet{}).Where("user_id = ?", storeNo).Updates(uMap).Error //if err != nil { // tx.Rollback() // return errors.New("绑定用户账户失败") //} tx.Commit() return nil } func DeleteUserAccount(storeNo string, data *request.IdReq) error { var err error // TODO 校验是否有提现中 err = global.MG_DB.Model(&model.Account{}).Where("user_id=? and id=?", storeNo, data.ID).Delete(&model.Account{}).Error if err != nil { return errors.New("删除账户失败") } return nil } func GetUserCommissionList(storeNo string, info *request.SearchCommission) (error, interface{}, interface{}, int64) { var ( err error data []model.BillList limit int offset int total int64 totalB model.BillTotal ) limit = info.PageSize offset = info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.Bill{}) db2 := global.MG_DB.Model(&model.Bill{}) if info.Receipt != 0 { db = db.Where("receipt=?", info.Receipt) db2 = db2.Where("receipt=?", info.Receipt) } if info.StartTime != "" { db = db.Where("created_at>=?", info.StartTime) db2 = db2.Where("created_at>=?", info.StartTime) } if info.EndTime != "" { db = db.Where("created_at3", storeNo) db2 = db2.Where("user_id=? and type<>3", storeNo) err = db.Count(&total).Error if err != nil { return errors.New("获取总数失败"), data, totalB, total } //统计总数 err = db2.Select("sum(case when `status`=2 then price else 0 end) income,sum(case when `status`=2 then 1 else 0 end) income_num,sum(case when `status`=1 then price else 0 end) payout,sum(case when `status`=1 then 1 else 0 end) payout_num").Group("user_id").Scan(&totalB).Error if err != nil { return errors.New("获取总数失败"), data, totalB, total } err = db.Offset(offset).Limit(limit).Find(&data).Error if err != nil { return errors.New("获取用户失败"), data, totalB, total } return nil, data, totalB, total } func GetUserWithdrawalList(storeNo string, info *request.SearchWithdrawal) (error, interface{}, int64) { var ( err error data []model.BillList limit int offset int total int64 ) limit = info.PageSize offset = info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.Bill{}) if info.Status != 0 { db = db.Where("receipt=?", info.Status) } db = db.Where("user_id=? and type=3", storeNo) err = db.Count(&total).Error if err != nil { return errors.New("获取总数失败"), data, total } err = db.Offset(offset).Limit(limit).Find(&data).Error if err != nil { return errors.New("获取用户失败"), data, total } for v := range data { data[v].Account = utils.HideStar(data[v].Account) } return nil, data, total } //func UserWithdrawal(storeNo string, info *request.Withdrawal) error { // var ( // err error // wallet model.Wallet // account model.Account // result bool // ) // if info.Code == "" { // return errors.New("验证码不可为空") // } // code := RedisGet("time_msg_bkb:86" + info.Phone) // if global.MG_CONFIG.System.Env == "develop" && info.Code == "888888" { // // } else if code != info.Code { // return errors.New("验证码验证失败") // } // if info.Amount == 0 { // return errors.New("提现金额不可为0") // } // if info.Amount < 100 { // return errors.New("提现金额不可小于100") // } // if info.Amount > 1000000 { // return errors.New("提现金额最大为1000000") // } // for { // err, result = utils.RedisSetNX("withdrawal-"+storeNo, "used", 10*time.Second) // if result && err == nil { // //获取成功 // break // } // } // defer func() { // //释放锁 // _, _ = utils.RedisDel("withdrawal-" + storeNo) // }() // err = global.MG_DB.Model(&model.Wallet{}).Where("user_id = ?", storeNo).Find(&wallet).Error // if err != nil { // return errors.New("获取账户信息失败") // } // if wallet.Balance < info.Amount { // return errors.New("金额不足,无法提现") // } // err = global.MG_DB.Model(&model.Account{}).Where("user_id = ?", storeNo).Find(&account).Error // if err != nil { // return errors.New("获取账户信息失败") // } // if account.ID == 0 { // return errors.New("未绑定账户,不可提现") // } // withdID := Generate() // //进行paypal提现操作 // tx := global.MG_DB.Begin() // //卖家扣除佣金 // var sBill model.Bill // sBill.UserID = storeNo // sBill.Type = "3" // sBill.Price = info.Amount // sBill.WithdID = withdID // sBill.Status = 1 // sBill.Receipt = 2 // sBill.WithdrawalStatus = 0 // sBill.Platform = "saller" // sBill.Account = account.PayPalName // sBill.CheckStatus = "0" // err = tx.Create(&sBill).Error // if err != nil { // tx.Rollback() // return errors.New("卖家账单扣除佣金失败") // } // //操作完成 // err = tx.Model(&model.Wallet{}).Where("id = ?", wallet.ID).Update("balance", gorm.Expr("balance - ?", info.Amount)).Error // if err != nil { // tx.Rollback() // return errors.New("金额扣除失败,取消提现") // } // //进行paypal提现操作 // //err, _ = CreatePayOutPayer(account.PayPalName, strconv.FormatFloat(info.Amount, 'f', 2, 64), withdID) // //if err != nil { // // fmt.Println(err) // // tx.Rollback() // // return errors.New("paypal创建提现订单失败") // //} // tx.Commit() // return nil //} //func UserWithdrawalFund(storeNo string, info *request.Withdrawal) error { // var ( // err error // wallet model.Wallet // account model.Account // result bool // ) // if info.Code == "" { // return errors.New("验证码不可为空") // } // code := RedisGet("time_msg_bkb:86" + info.Phone) // if global.MG_CONFIG.System.Env == "develop" && info.Code == "888888" { // // } else if code != info.Code { // return errors.New("验证码验证失败") // } // if info.Amount == 0 { // return errors.New("提现金额不可为0") // } // if info.Amount < 100 { // return errors.New("提现金额不可小于100") // } // if info.Amount > 1000000 { // return errors.New("提现金额最大为1000000") // } // for { // err, result = utils.RedisSetNX("withdrawal-fund-"+storeNo, "used", 10*time.Second) // if result && err == nil { // //获取成功 // break // } // } // defer func() { // //释放锁 // _, _ = utils.RedisDel("withdrawal-fund-" + storeNo) // }() // err = global.MG_DB.Model(&model.Wallet{}).Where("user_id = ?", storeNo).Find(&wallet).Error // if err != nil { // return errors.New("获取账户信息失败") // } // if (wallet.Fund - wallet.FundLock) < info.Amount { // return errors.New("金额不足,无法提现") // } // err = global.MG_DB.Model(&model.Account{}).Where("user_id = ?", storeNo).Find(&account).Error // if err != nil { // return errors.New("获取账户信息失败") // } // if account.ID == 0 { // return errors.New("未绑定账户,不可提现") // } // withdID := Generate() // //进行paypal提现操作 // tx := global.MG_DB.Begin() // //卖家扣除佣金 // var sBill model.Bill // sBill.UserID = storeNo // sBill.Type = "3" // sBill.Price = info.Amount // sBill.WithdID = withdID // sBill.Status = 1 // sBill.Receipt = 2 // sBill.WithdrawalStatus = 0 // sBill.Platform = "saller" // sBill.Account = account.PayPalName // err = tx.Create(&sBill).Error // if err != nil { // tx.Rollback() // return errors.New("卖家账单扣除佣金失败") // } // //操作完成 // err = tx.Model(&model.Wallet{}).Where("user_id = ?", storeNo).Update("fund", gorm.Expr("fund - ?", info.Amount)).Error // if err != nil { // tx.Rollback() // return errors.New("金额扣除失败,取消提现") // } // //进行paypal提现操作 // //err, _ = CreatePayOutPayer(account.PayPalName, strconv.FormatFloat(info.Amount, 'f', 2, 64), withdID) // //if err != nil { // // fmt.Println(err) // // tx.Rollback() // // return errors.New("paypal创建提现订单失败") // //} // tx.Commit() // return nil //} // 用户提现 func CreatePayOutPayer(paypalName, amount, withdID string) (error, *paypal.PayoutResponse) { var ( err error c *paypal.Client ) if global.MG_CONFIG.Paypal.Env == "SandBox" { c, err = paypal.NewClient(global.MG_CONFIG.Paypal.ClientID, global.MG_CONFIG.Paypal.Secret, paypal.APIBaseSandBox) if err != nil { return err, nil } } else { c, err = paypal.NewClient(global.MG_CONFIG.Paypal.ClientID, global.MG_CONFIG.Paypal.Secret, paypal.APIBaseLive) if err != nil { return err, nil } } _, err = c.GetAccessToken() if err != nil { return err, nil } payout := paypal.Payout{} send := &paypal.SenderBatchHeader{ SenderBatchID: withdID, } item := make([]paypal.PayoutItem, 1) fmt.Println(amount) item[0] = paypal.PayoutItem{ RecipientType: "EMAIL", Receiver: paypalName, Amount: &paypal.AmountPayout{ Currency: "USD", //收款类型 Value: amount, //收款数量 }, Note: "打款", } payout.SenderBatchHeader = send payout.Items = item fmt.Println(payout.Items[0].Amount) resp, err := c.CreateSinglePayout(payout) if err != nil { fmt.Println(err.Error()) fmt.Println(resp) return err, nil } return err, resp } func BalanceWithdrawal(storeNo string, info *request.WithdrawalParams) (error, model.WithdrawalView) { var ( err error result model.WithdrawalView ) // 开始交易 for { ok, err := global.MG_REDIS.SetNX("withdrawal-"+storeNo, "used", 10*time.Second).Result() if ok && err == nil { // 获取成功 break } } defer func() { // 释放锁 _, _ = utils.RedisDel("withdrawal-" + storeNo) }() var wallet model.Wallet err = global.MG_DB.Model(&model.Wallet{}).Where("platform = 'seller' AND user_id = ?", storeNo).First(&wallet).Error if err != nil { return err, result } //if wallet.State != 0 { // return errors.New("account no withdrawal allowed"), result //} if wallet.Balance < info.Amount { return errors.New("金额不足,无法提现"), result } var account model.Account if info.AccountID == 0 { var accountList []model.Account err = global.MG_DB.Model(&model.Account{}).Where("user_id = ?", storeNo).Find(&accountList).Error if err != nil { return errors.New("获取账户信息失败"), result } if len(accountList) == 0 { return errors.New("未绑定提现账户"), result } else if len(accountList) > 1 { return errors.New("提现账户包含多个"), result } account = accountList[0] } else { err = global.MG_DB.Model(&model.Account{}).Where("user_id = ? AND id = ?", storeNo, info.AccountID).First(&account).Error if err != nil { return errors.New("获取账户信息失败"), result } } tx := global.MG_DB.Begin() err = tx.Model(&model.Wallet{}).Where("id = ?", wallet.ID).Updates(map[string]interface{}{"balance": gorm.Expr("balance - ?", info.Amount)}).Error if err != nil { tx.Rollback() return errors.New("金额扣除失败,取消提现"), result } var withdrawal model.Withdrawal withdrawal.Platform = "2" withdrawal.WalletType = 1 withdrawal.FlowNo = Generate() withdrawal.BillNo = Generate() withdrawal.AccountType = account.Type withdrawal.BankCard = account.BankCard withdrawal.CreateBy = storeNo withdrawal.Amount = info.Amount withdrawal.CheckStatus = "0" withdrawal.Status = "0" withdrawal.Title = "提现" err = tx.Create(&withdrawal).Error if err != nil { tx.Rollback() return errors.New("提交申请失败"), result } var bill model.Bill bill.UserID = storeNo bill.Type = "3" bill.WithdID = withdrawal.BillNo bill.TransactionId = "B" + bill.WithdID bill.Price = info.Amount bill.Status = 1 bill.Receipt = 2 bill.WithdrawalStatus = 0 bill.Platform = "seller" bill.CheckStatus = "0" bill.Title = "钱包提现" err = tx.Create(&bill).Error if err != nil { tx.Rollback() return errors.New("提现失败,请稍后再试"), result } tx.Commit() result = model.WithdrawalView{ FlowNo: withdrawal.FlowNo, } return nil, result } func FundRecharge(storeNo string, info *request.FundRecharge) (error, response.PayResult) { var ( err error wallet model.Wallet billFund model.BillFund result response.PayResult ) err = global.MG_DB.Model(&model.Wallet{}).Where("platform = 'seller' AND user_id = ?", storeNo).First(&wallet).Error if err != nil { return err, result } billFund.UserID = storeNo billFund.TransactionType = 2 billFund.TransactionId = "RC" + Generate() billFund.Title = "recharge" billFund.Price = info.Amount billFund.Balance = wallet.Fund + info.Amount billFund.Platform = "seller" billFund.Status = 1 tx := global.MG_DB.Begin() err = tx.Model(&model.BillFund{}).Create(&billFund).Error if err != nil { tx.Rollback() return err, result } var payChannel string if info.PayMode == 1 { payChannel = "paypal" } attach, _ := json.Marshal(map[string]string{"transactionId": billFund.TransactionId}) params := api.PayTransRequest{ Appid: "bkb5918273465092837", Mchid: "11000001", OutTradeNo: billFund.TransactionId, Attach: string(attach), NotifyUrl: global.MG_CONFIG.Paypal.NotifyUrl + "/base/payment/payback", Amount: info.Amount, Currency: "USD", PayChannel: payChannel, ReturnUrl: global.MG_CONFIG.Paypal.ReturnUrl + "/funds_manage/list", CancelUrl: global.MG_CONFIG.Paypal.CancelUrl + "/funds_manage/list", } payOrder, err := api.NewGreeterClient(global.PAY_CONN).PayTransactionWebUrl(context.Background(), ¶ms) if err != nil { fmt.Println(err.Error()) tx.Rollback() return errors.New("open " + payChannel + " failed"), result } err = tx.Model(&model.BillFund{}).Where("id = ?", billFund.ID).UpdateColumn("pay_id", payOrder.PayId).Error if err != nil { tx.Rollback() return err, result } tx.Commit() result.PayChannel = payOrder.PayChannel result.PayId = payOrder.PayId result.PayReturn = payOrder.PayReturn result.PayStatus = payOrder.PayStatus return err, result } func FundWithdrawal(storeNo string, info *request.WithdrawalParams) (error, model.WithdrawalView) { var ( err error result model.WithdrawalView ) // 开始交易 for { ok, err := global.MG_REDIS.SetNX("withdrawal-"+storeNo, "used", 10*time.Second).Result() if ok && err == nil { // 获取成功 break } } defer func() { // 释放锁 _, _ = utils.RedisDel("withdrawal-" + storeNo) }() var wallet model.Wallet err = global.MG_DB.Model(&model.Wallet{}).Where("platform = 'seller' AND user_id = ?", storeNo).First(&wallet).Error if err != nil { return err, result } if wallet.State != 0 { return errors.New("account no withdrawal allowed"), result } if wallet.Fund < info.Amount { return errors.New("金额不足,无法提现"), result } var account model.Account err = global.MG_DB.Model(&model.Account{}).Where("user_id = ? AND id = ?", storeNo, info.AccountID).First(&account).Error if err != nil { return errors.New("获取账户信息失败"), result } tx := global.MG_DB.Begin() err = tx.Model(&model.Wallet{}).Where("id = ?", wallet.ID).Updates(map[string]interface{}{"fund": gorm.Expr("fund - ?", info.Amount), "state": "1"}).Error if err != nil { tx.Rollback() return errors.New("金额扣除失败,取消提现"), result } var withdrawal model.Withdrawal withdrawal.Platform = "2" withdrawal.WalletType = 2 withdrawal.FlowNo = Generate() withdrawal.BillNo = Generate() withdrawal.AccountType = account.Type withdrawal.BankCard = account.BankCard withdrawal.CreateBy = storeNo withdrawal.Amount = info.Amount withdrawal.CheckStatus = "0" withdrawal.Status = "0" withdrawal.Title = "提现至PayPal账号" + account.AccountName err = tx.Create(&withdrawal).Error if err != nil { tx.Rollback() return errors.New("提交申请失败"), result } //var bill model.Bill //bill.UserID = storeNo //bill.Type = "3" //bill.WithdID = withdrawal.BillNo //bill.TransactionId = "B" + bill.WithdID //bill.Price = info.Amount //bill.Status = 1 //bill.Receipt = 2 //bill.WithdrawalStatus = 0 //bill.Platform = "seller" //bill.Account = account.PayPalName //bill.CheckStatus = "0" //bill.Title = "营销账户提现" //err = tx.Create(&bill).Error //if err != nil { // tx.Rollback() // return errors.New("提现失败,请稍后再试"), result //} var billFund model.BillFund billFund.UserID = storeNo billFund.TransactionType = 1 billFund.TransactionId = "WD" + Generate() billFund.Title = "提现" billFund.Price = info.Amount billFund.Balance = wallet.Fund - info.Amount billFund.Platform = "seller" billFund.RelatedId = withdrawal.FlowNo billFund.Status = 1 err = tx.Create(&billFund).Error if err != nil { tx.Rollback() return errors.New("创建fund bill失败,请稍后再试"), result } tx.Commit() result = model.WithdrawalView{ FlowNo: withdrawal.FlowNo, } return nil, result } func GetWithdrawalList(storeNo string, info *request.WithdrawalSearch) (error, []model.Withdrawal, int64) { var ( err error total int64 result []model.Withdrawal ) limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.Withdrawal{}).Where("platform = '2' AND create_by = ?", storeNo) if info.WalletType != 0 { db = db.Where("wallet_type = ?", info.WalletType) } _ = db.Count(&total) err = db.Order("id DESC").Offset(offset).Limit(limit).Find(&result).Error return err, result, total } func GetBillFundList(storeNo string, info *request.BillFundSearch) (error, []model.BillFund, int64) { var ( err error total int64 result []model.BillFund ) limit := info.PageSize offset := info.PageSize * (info.Page - 1) db := global.MG_DB.Model(&model.BillFund{}).Where("platform = 'seller' AND user_id = ?", storeNo) if info.StartTime != "" { db = db.Where("created_at >= ?", info.StartTime) } if info.EndTime != "" { if len(info.EndTime) == 10 { tmp, _ := time.ParseInLocation(utils.DateFormat, info.EndTime, time.Local) info.EndTime = tmp.AddDate(0, 0, 1).Format(utils.DateFormat) } db = db.Where("created_at < ?", info.EndTime) } _ = db.Count(&total) err = db.Order("id DESC").Offset(offset).Limit(limit).Find(&result).Error return err, result, total } func walletFundLock(tx *gorm.DB, info *request.FundLock) error { var ( err error wallet model.Wallet ) err = global.MG_DB.Model(&model.Wallet{}).Where("appid = ? AND user_id = ?", info.Appid, info.UserID).First(&wallet).Error if err != nil { return err } if wallet.Fund < info.Amount { return errors.New("insufficient marketing account balance") } err = tx.Model(&model.Wallet{}).Where("id = ?", wallet.ID).Updates(map[string]interface{}{"fund": gorm.Expr("fund - ?", info.Amount)}).Error return err } func updateWalletFundLock(tx *gorm.DB, info *request.FundLock) error { var ( err error wallet model.Wallet ) err = global.MG_DB.Model(&model.Wallet{}).Where("appid = ? AND user_id = ?", info.Appid, info.UserID).First(&wallet).Error if err != nil { return err } // TODO 重新计算锁定营销账户 return err } func PaypalCallback(info *dto.PaybackBody) error { // 开始交易 for { ok, err := global.MG_REDIS.SetNX("payback-"+info.TransactionId, "used", 10*time.Second).Result() if ok && err == nil { // 获取成功 break } } defer func() { // 释放锁 _, _ = utils.RedisDel("payback-" + info.TransactionId) }() switch info.ResourceType { case "pay": // 支付结果 if info.Status != "SUCCESS" { return nil } else { var ( err error billFund model.BillFund ) err = global.MG_DB.Model(&model.BillFund{}).Where("transaction_id = ?", info.OutTradeNo).First(&billFund).Error if err != nil { return err } tx := global.MG_DB.Begin() err = tx.Model(&model.BillFund{}).Where("id = ?", billFund.ID).UpdateColumn("status", 2).Error if err != nil { tx.Rollback() return err } err = tx.Model(&model.Wallet{}).Where("platform = 'seller' AND user_id = ?", billFund.UserID).UpdateColumn("fund", gorm.Expr("fund + ?", billFund.Price)).Error if err != nil { tx.Rollback() return err } tx.Commit() } case "withdrawal": // 提现结果 case "refund": // 退款 tx := global.MG_DB.Begin() var ( err error postSale model.OrderPostSale ) err = global.MG_DB.Model(&model.OrderPostSale{}).Where("order_id = ?", info.OutTradeNo).First(&postSale).Error if err != nil { return err } if info.Status != "SUCCESS" { err = tx.Model(&model.OrderPostSale{}).Where("id = ?", postSale.ID).Updates(map[string]interface{}{"refund_status": 3, "refund_time": time.Now()}).Error if err != nil { tx.Rollback() return err } } else { err = tx.Model(&model.OrderPostSale{}).Where("id = ?", postSale.ID).Updates(map[string]interface{}{"refund_status": 2, "refund_time": time.Now()}).Error if err != nil { tx.Rollback() return err } // 更新账单状态 err = tx.Model(&model.Bill{}).Where("platform = 'customer' AND order_id = ? AND type = '2' AND `status` = 2", postSale.OrderID).UpdateColumn("receipt", 1).Error if err != nil { tx.Rollback() return err } } tx.Commit() } return nil } func getWallet(platform, userId string) (error, model.Wallet) { var ( err error result model.Wallet ) err = global.MG_DB.Model(&model.Wallet{}).Where("`platform` = ? AND user_id = ?", platform, userId).First(&result).Error return err, result } func Test() { fmt.Println("test11111") ping, err := api.NewGreeterClient(global.PAY_CONN).Ping(context.Background(), &emptypb.Empty{}) if err != nil { fmt.Println(err.Error()) return } fmt.Println(ping) }