123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223 |
- package service
- import (
- "context"
- "fmt"
- "math/rand"
- "time"
- "go-common/app/job/main/ugcpay/dao"
- "go-common/app/job/main/ugcpay/model"
- "go-common/app/job/main/ugcpay/service/pay"
- xsql "go-common/library/database/sql"
- "go-common/library/log"
- "github.com/pkg/errors"
- )
- // 结算贝壳任务
- type taskRechargeShell struct {
- dao *dao.Dao
- pay *pay.Pay
- rnd *rand.Rand
- monthOffset int
- namePrefix string
- tl *taskLog
- }
- func (s *taskRechargeShell) Run() (err error) {
- var (
- ctx = context.Background()
- finished bool
- expectFN = func(ctx context.Context) (expect int64, err error) {
- var (
- beginTime, _ = monthRange(s.monthOffset)
- monthVer = monthlyBillVer(beginTime)
- )
- if expect, err = s.dao.CountMonthlyBillByVer(ctx, monthVer); err != nil {
- return
- }
- return
- }
- )
- if finished, err = checkOrCreateTaskFromLog(ctx, s, s.tl, expectFN); err != nil || finished {
- return
- }
- return s.run(ctx)
- }
- func (s *taskRechargeShell) TTL() int32 {
- return 3600 * 2
- }
- func (s *taskRechargeShell) Name() string {
- return fmt.Sprintf("%s_%d", s.namePrefix, monthlyBillVer(time.Now()))
- }
- func (s *taskRechargeShell) run(ctx context.Context) (err error) {
- ll := &monthlyBillLL{
- limit: 1000,
- dao: s.dao,
- }
- beginTime, _ := monthRange(s.monthOffset)
- ll.ver = monthlyBillVer(beginTime)
- return runLimitedList(ctx, ll, time.Millisecond*2, s.runMonthlyBill)
- }
- func (s *taskRechargeShell) runMonthlyBill(ctx context.Context, ele interface{}) (err error) {
- monthlyBill, ok := ele.(*model.Bill)
- if !ok {
- return errors.Errorf("runMonthlyBill convert ele: %+v failed", monthlyBill)
- }
- log.Info("taskRechargeShell start handle monthly bill: %+v", monthlyBill)
- var fn func(ctx context.Context, tx *xsql.Tx) (affected bool, err error)
- if monthlyBill.In-monthlyBill.Out > 0 {
- fn = s.fnRechargeShell(ctx, monthlyBill)
- } else {
- fn = s.fnRecordRecharge(ctx, monthlyBill)
- }
- if err = runTXCASTaskWithLog(ctx, s, s.tl, fn); err != nil {
- return
- }
- return
- }
- func (s *taskRechargeShell) fnRecordRecharge(ctx context.Context, monthlyBill *model.Bill) func(ctx context.Context, tx *xsql.Tx) (affected bool, err error) {
- return func(ctx context.Context, tx *xsql.Tx) (affected bool, err error) {
- affected = true
- var (
- readyRecharge = monthlyBill.In - monthlyBill.Out
- )
- // 记录贝壳订单
- orderRechargeShell := &model.OrderRechargeShell{
- MID: monthlyBill.MID,
- OrderID: orderID(s.rnd),
- Biz: model.BizAsset,
- Amount: readyRecharge,
- State: "finished",
- Ver: monthlyBill.Ver,
- }
- var (
- orderRechargeShellLog = &model.OrderRechargeShellLog{
- OrderID: orderRechargeShell.OrderID,
- FromState: "finished",
- ToState: "finished",
- BillUserMonthlyID: monthlyBill.BillID,
- }
- )
- _, err = s.dao.TXInsertOrderRechargeShell(ctx, tx, orderRechargeShell)
- if err != nil {
- tx.Rollback()
- return
- }
- // 插入 order_recharge_shell_log, uk: bill_monthly_bill_id
- _, err = s.dao.TXInsertOrderRechargeShellLog(ctx, tx, orderRechargeShellLog)
- if err != nil {
- tx.Rollback()
- return
- }
- log.Info("fnRecordRecharge : %+v, orderRechargeShell: %+v", monthlyBill, orderRechargeShell)
- return
- }
- }
- func (s *taskRechargeShell) fnRechargeShell(ctx context.Context, monthlyBill *model.Bill) func(ctx context.Context, tx *xsql.Tx) (affected bool, err error) {
- return func(ctx context.Context, tx *xsql.Tx) (affected bool, err error) {
- affected = true
- var (
- account *model.UserAccount
- readyRecharge = monthlyBill.In - monthlyBill.Out
- accountLog *model.AccountLog
- )
- // 获得该 mid 的 虚拟账户
- if account, err = s.dao.UserAccount(ctx, monthlyBill.MID, model.BizAsset, model.CurrencyBP); err != nil {
- return
- }
- if account == nil {
- err = errors.Errorf("runMonthlyBill not found valid user_account, monthly_bill: %+v", monthlyBill)
- return
- }
- // 检查虚拟账户余额是否足够
- if account.Balance-readyRecharge < 0 {
- err = errors.Errorf("runMonthlyBill failed, account.Balance - readyRecharge < 0 !!!! account: %+v, monthly bill: %+v", account, monthlyBill)
- return
- }
- accountLog = &model.AccountLog{
- AccountID: account.ID,
- Name: s.Name(),
- From: account.Balance,
- To: account.Balance - readyRecharge,
- Ver: account.Ver + 1,
- State: model.AccountStateWithdraw,
- }
- account.Balance -= readyRecharge
- // 扣减虚拟账户余额
- rowAffected, err := s.dao.TXUpdateUserAccount(ctx, tx, account)
- if err != nil {
- tx.Rollback()
- return
- }
- if rowAffected <= 0 {
- log.Error("TXUpdateUserAccount no affected user account: %+v", account)
- affected = false
- tx.Rollback()
- return
- }
- err = s.dao.TXInsertUserAccountLog(ctx, tx, accountLog)
- if err != nil {
- tx.Rollback()
- return
- }
- // 开始转贝壳
- orderRechargeShell := &model.OrderRechargeShell{
- MID: monthlyBill.MID,
- OrderID: orderID(s.rnd),
- Biz: model.BizAsset,
- Amount: readyRecharge,
- State: "created",
- Ver: monthlyBill.Ver,
- }
- var (
- orderRechargeShellLog = &model.OrderRechargeShellLog{
- OrderID: orderRechargeShell.OrderID,
- FromState: "created",
- ToState: "created",
- BillUserMonthlyID: monthlyBill.BillID,
- }
- )
- _, err = s.dao.TXInsertOrderRechargeShell(ctx, tx, orderRechargeShell)
- if err != nil {
- tx.Rollback()
- return
- }
- // 插入 order_recharge_shell_log, uk: bill_monthly_bill_id
- _, err = s.dao.TXInsertOrderRechargeShellLog(ctx, tx, orderRechargeShellLog)
- if err != nil {
- tx.Rollback()
- return
- }
- // 请求支付中心转贝壳
- _, payJSON, err := s.pay.RechargeShell(orderRechargeShell.OrderID, orderRechargeShell.MID, orderRechargeShell.Amount, orderRechargeShell.Amount)
- if err != nil {
- tx.Rollback()
- return
- }
- if err = s.dao.PayRechargeShell(ctx, payJSON); err != nil {
- tx.Rollback()
- return
- }
- log.Info("fnRechargeShell: %+v, account: %+v, orderRechargeShell: %+v", monthlyBill, account, orderRechargeShell)
- return
- }
- }
|