Browse Source

批量提现

theo 3 years ago
parent
commit
2fde68f46d

+ 1 - 0
backendApi/config/menu.php

@@ -280,6 +280,7 @@ return [
             ['name'=>'月业绩导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'perf-month-export', 'routePath'=>'bonus/perf-month-export', 'show'=>0,],
 //            ['name'=>'Score-month', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'score-month', 'routePath'=>'bonus/score-month', 'show'=>1,],//月积分
             ['name'=>'月积分导出', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'score-month-export', 'routePath'=>'bonus/score-month-export', 'show'=>0,],
+            ['name'=>'自动提现', 'class'=>'', 'icon'=>'', 'controller'=>'bonus', 'action'=>'auto-withdraw', 'routePath'=>'bonus/auto-withdraw', 'show'=>0,],
         ]
     ],
     /*'report'=>[

+ 1 - 0
backendApi/config/urlManagerRules.php

@@ -406,6 +406,7 @@ return [
             'GET yc-perf' => 'yc-perf',
             'GET period-perf' => 'period-perf',
             'GET period-perf-export' => 'period-perf-export',
+            'GET,POST auto-withdraw' => 'auto-withdraw'
         ],
     ],
     [

+ 21 - 0
backendApi/modules/v1/controllers/BonusController.php

@@ -62,6 +62,7 @@ use common\models\Config;
 use common\models\FlowBonus;
 use common\models\FlowExchangePoints;
 use common\models\forms\PeriodForm;
+use common\models\forms\UserBonusForm;
 use common\models\Period;
 use Exception;
 
@@ -2770,4 +2771,24 @@ class BonusController extends BaseController {
         }
         return static::notice('Starting exporting, please go to File Management - Export Files to view.'); // 导出开始,请到文件管理-导出文件查看
     }
+
+    /**
+     * 自动提现(奖金)
+     *
+     */
+    public function actionAutoWithdraw() {
+        $withdrawLock = Cache::getWithdrawLock();
+        if ($withdrawLock!=0){
+            return static::notice(Form::formatErrorsForApi('已有进程在生成'), 400);
+        }else{
+            $formModel = new UserBonusForm();
+            $formModel->scenario = 'autoWithdraw';
+            if ($formModel->autoWithdrawWebToAsync()) {
+                return static::notice('生成提现单 已开始处理,请等待');
+            } else {
+                return static::notice(Form::formatErrorsForApi($formModel->getErrors()), 400);
+            }
+        }
+    }
+
 }

+ 177 - 156
backendEle/src/views/bonus/period.vue

@@ -103,177 +103,198 @@
       <div class="white-box-footer">
         <pagination :total="totalCount" :page_size="pageSize" @size-change="handleSizeChange" @current-change="handleCurrentChange"></pagination>
       </div>
+      <div>
+        <el-button type="primary" size="small" @click="doAutoWithdraw()">
+          批量提现
+        </el-button>
+      </div>
     </div>
   </div>
 </template>
 
 <script>
-  import Vue from 'vue'
-  import {BONUS_WEBSOCKET_HOST} from '@/utils/config'
-  import userInfo from '@/utils/userInfo'
-  import network from './../../utils/network'
-  import tool from './../../utils/tool'
-  import store from '@/utils/vuexStore'
-  import FilterUser from '@/components/FilterUser'
-  import permission from '@/utils/permission'
-  import Pagination from '@/components/Pagination'
-  import filterHelper from '../../utils/filterHelper'
+import Vue from 'vue'
+import {BONUS_WEBSOCKET_HOST} from '@/utils/config'
+import userInfo from '@/utils/userInfo'
+import network from './../../utils/network'
+import tool from './../../utils/tool'
+import store from '@/utils/vuexStore'
+import FilterUser from '@/components/FilterUser'
+import permission from '@/utils/permission'
+import Pagination from '@/components/Pagination'
+import filterHelper from '../../utils/filterHelper'
 
-  export default {
-    name: 'bonus-period',
-    components: {FilterUser,Pagination},
-    created() {
-      let wsServer = BONUS_WEBSOCKET_HOST
-      let webSocket = new WebSocket(wsServer)
-      webSocket.onopen = function (evt) {
-        let userId = userInfo.userId()
-        let sendData = {app: 'admin', userId: userId}
-        webSocket.send(JSON.stringify(sendData))
+export default {
+  name: 'bonus-period',
+  components: {FilterUser, Pagination},
+  created () {
+    let wsServer = BONUS_WEBSOCKET_HOST
+    let webSocket = new WebSocket(wsServer)
+    webSocket.onopen = function (evt) {
+      let userId = userInfo.userId()
+      let sendData = {app: 'admin', userId: userId}
+      webSocket.send(JSON.stringify(sendData))
+    }
+    webSocket.onmessage = (env) => {
+      let data = JSON.parse(env.data)
+      if (data.handle === 'adminAsyncPercent') {
+        this.onMessageCallback(data)
       }
-      webSocket.onmessage = (env) => {
-        let data = JSON.parse(env.data)
-        if (data.handle === 'adminAsyncPercent') {
-          this.onMessageCallback(data)
-        }
+    }
+  },
+  mounted () {
+    this.getData(this.currentPage, this.pageSize)
+    store.state.socket.onMessageCallback = this.onMessageCallback
+  },
+  data () {
+    return {
+      tableData: null,
+      loading: true,
+      multipleSelection: [],
+      currentPage: 1,
+      totalPages: 1,
+      totalCount: 1,
+      pageSize: 10,
+      tool: tool,
+      permission: permission,
+      filterTypes: {
+        'periodNum': {isUserTable: false, name: 'Number of periods'}, // 期数
+        'year': {isUserTable: false, name: 'Bonus Year'}, // 所在结算年
+        'month': {isUserTable: false, name: 'Bonus Month'}, // 所在结算月
+        'startTime': {isUserTable: false, name: 'Period start time', other: 'date'}, // 期数开始时间
+        'endTime': {isUserTable: false, name: 'Period end time', other: 'date'}, // 期数结束时间
+        'closedAt': {isUserTable: false, name: 'Closing time', other: 'date'}, // 封期时间
+        'perfStartedAt': {isUserTable: false, name: 'Start time of generating performance sheet', other: 'date'}, // 生成业绩单开始时间
+        'perfedAt': {isUserTable: false, name: 'End time of generating performance sheet', other: 'date'}, // 生成业绩单结束时间
+        'calStartedAt': {isUserTable: false, name: 'Settlement start time', other: 'date'}, // 结算开始时间
+        'calculatedAt': {isUserTable: false, name: 'Settlement end time', other: 'date'}, // 结算结束时间
+        'sendStartedAt': {isUserTable: false, name: 'Network connection start time', other: 'date'}, // 挂网开始时间
+        'sentAt': {isUserTable: false, name: 'End time of network connection', other: 'date'} // 挂网结束时间
+      },
+      filterModel: {},
+      percentList: {
+        'PERF_PERCENT': {},
+        'CALC_PERCENT': {},
+        'SENT_PERCENT': {}
       }
+    }
+  },
+  methods: {
+    closeHandle (row) {
+      this.$confirm('Confirm to manually seal the current period?', 'Hint', { // '确定对当前期进行手动封期操作?', '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return network.getData(`bonus/close-period/${row.PERIOD_NUM}`)
+      }).then(response => {
+        this.$message({
+          message: response,
+          type: 'success'
+        })
+        this.getData(this.currentPage, this.pageSize)
+      }).catch(response => {
+      })
     },
-    mounted() {
-      this.getData(this.currentPage, this.pageSize)
-      store.state.socket.onMessageCallback = this.onMessageCallback
-    },
-    data() {
-      return {
-        tableData: null,
-        loading: true,
-        multipleSelection: [],
-        currentPage: 1,
-        totalPages: 1,
-        totalCount: 1,
-        pageSize: 10,
-        tool: tool,
-        permission: permission,
-        filterTypes: {
-          'periodNum': {isUserTable: false, name: 'Number of periods'},//期数
-          'year': {isUserTable: false, name: 'Bonus Year'},//所在结算年
-          'month': {isUserTable: false, name: 'Bonus Month'},//所在结算月
-          'startTime': {isUserTable: false, name: 'Period start time', other: 'date'},//期数开始时间
-          'endTime': {isUserTable: false, name: 'Period end time', other: 'date'},//期数结束时间
-          'closedAt': {isUserTable: false, name: 'Closing time', other: 'date'},//封期时间
-          'perfStartedAt': {isUserTable: false, name: 'Start time of generating performance sheet', other: 'date'},//生成业绩单开始时间
-          'perfedAt': {isUserTable: false, name: 'End time of generating performance sheet', other: 'date'},//生成业绩单结束时间
-          'calStartedAt': {isUserTable: false, name: 'Settlement start time', other: 'date'},//结算开始时间
-          'calculatedAt': {isUserTable: false, name: 'Settlement end time', other: 'date'},//结算结束时间
-          'sendStartedAt': {isUserTable: false, name: 'Network connection start time', other: 'date'},//挂网开始时间
-          'sentAt': {isUserTable: false, name: 'End time of network connection', other: 'date'},//挂网结束时间
-        },
-        filterModel: {},
-        percentList: {
-          'PERF_PERCENT': {},
-          'CALC_PERCENT': {},
-          'SENT_PERCENT': {},
-        },
-      }
+    calcHandle (row) {
+      this.$confirm('Confirm to perform settlement operation for the current period?', 'Hint', { // '确定对当前期进行结算操作?', '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return network.getData(`bonus/calc-period/${row.PERIOD_NUM}`)
+      }).then(response => {
+        this.$message({
+          message: response,
+          type: 'success'
+        })
+        this.getData(this.currentPage, this.pageSize)
+      }).catch(response => {
+      })
     },
-    methods: {
-      closeHandle(row) {
-        this.$confirm('Confirm to manually seal the current period?', 'Hint', {//'确定对当前期进行手动封期操作?', '提示'
-          confirmButtonText: 'confirm', // 确定
-          cancelButtonText: 'cancel', // 取消
-          type: 'warning'
-        }).then(() => {
-          return network.getData(`bonus/close-period/${row.PERIOD_NUM}`)
-        }).then(response => {
-          this.$message({
-            message: response,
-            type: 'success'
-          })
-          this.getData(this.currentPage, this.pageSize)
-        }).catch(response => {
+    perfHandle (row) {
+      this.$confirm('Confirm to generate performance sheet for the current period?', 'Hint', { // '确定对当前期进行生成业绩单操作?', '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return network.getData(`bonus/perf-period/${row.PERIOD_NUM}`)
+      }).then(response => {
+        this.$message({
+          message: response,
+          type: 'success'
         })
-      },
-      calcHandle(row) {
-        this.$confirm('Confirm to perform settlement operation for the current period?', 'Hint', {//'确定对当前期进行结算操作?', '提示'
-          confirmButtonText: 'confirm', // 确定
-          cancelButtonText:  'cancel', // 取消
-          type: 'warning'
-        }).then(() => {
-          return network.getData(`bonus/calc-period/${row.PERIOD_NUM}`)
-        }).then(response => {
-          this.$message({
-            message: response,
-            type: 'success'
-          })
-          this.getData(this.currentPage, this.pageSize)
-        }).catch(response => {
+        this.getData(this.currentPage, this.pageSize)
+      }).catch(response => {
+      })
+    },
+    sentHandle (row) {
+      this.$confirm('Are you sure to connect the current period? Performance sheet and settlement cannot be generated after network connection', 'Hint', { // '确定对当前期进行挂网操作?挂网后无法生成业绩单和结算', '提示'
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return network.getData(`bonus/send-period/${row.PERIOD_NUM}`)
+      }).then(response => {
+        this.$message({
+          message: response,
+          type: 'success'
         })
-      },
-      perfHandle(row) {
-        this.$confirm('Confirm to generate performance sheet for the current period?', 'Hint', {//'确定对当前期进行生成业绩单操作?', '提示'
-          confirmButtonText: 'confirm', // 确定
-          cancelButtonText:  'cancel', // 取消
-          type: 'warning'
-        }).then(() => {
-          return network.getData(`bonus/perf-period/${row.PERIOD_NUM}`)
-        }).then(response => {
-          this.$message({
-            message: response,
-            type: 'success'
-          })
-          this.getData(this.currentPage, this.pageSize)
-        }).catch(response => {
+        this.getData(this.currentPage, this.pageSize)
+      }).catch(response => {
+      })
+    },
+    doAutoWithdraw () {
+      this.$confirm('全部提现?', 'Hint', {
+        confirmButtonText: 'confirm', // 确定
+        cancelButtonText: 'cancel', // 取消
+        type: 'warning'
+      }).then(() => {
+        return network.getData(`bonus/auto-withdraw`)
+      }).then(response => {
+        this.$message({
+          message: response,
+          type: 'success'
         })
-      },
-      sentHandle(row) {
-        this.$confirm('Are you sure to connect the current period? Performance sheet and settlement cannot be generated after network connection', 'Hint', {//'确定对当前期进行挂网操作?挂网后无法生成业绩单和结算', '提示'
-          confirmButtonText: 'confirm', // 确定
-          cancelButtonText:  'cancel', // 取消
-          type: 'warning'
-        }).then(() => {
-          return network.getData(`bonus/send-period/${row.PERIOD_NUM}`)
-        }).then(response => {
-          this.$message({
-            message: response,
-            type: 'success'
-          })
+        this.getData(this.currentPage, this.pageSize)
+      }).catch(response => {
+      })
+    },
+    viewHandle (row) {
+      this.$router.push({path: `/bonus/period-detail/${row.PERIOD_NUM}`})
+    },
+    handleSelectionChange (val) {
+      this.multipleSelection = val
+    },
+    handleCurrentChange (page) {
+      this.getData(page, this.pageSize)
+    },
+    handleSizeChange (pageSize) {
+      this.getData(this.currentPage, pageSize)
+    },
+    handleFilterUser (filterData) {
+      filterHelper.handleFilterUser(this, filterData)
+    },
+    handleFilter () {
+      this.getData()
+    },
+    getData (page, pageSize) {
+      let filterData = this.filterModel
+      let vueObj = this
+      network.getPageData(this, 'bonus/period', page, pageSize, filterData, function (response) {
+        vueObj.allData = response
+      }, null, ['PERF_PERCENT', 'CALC_PERCENT', 'SENT_PERCENT'])
+    },
+    onMessageCallback (data) {
+      if (data) {
+        if (data.other && data.other.MODEL === 'PERIOD' && data.other.ID) {
+          this.$set(this.percentList[data.other.FIELD], data.other.ID, data.percent)
+        }
+        if (data.other && data.other.MODEL === 'PERIOD' && data.percent === 100) {
           this.getData(this.currentPage, this.pageSize)
-        }).catch(response => {
-        })
-      },
-      viewHandle(row) {
-        this.$router.push({path: `/bonus/period-detail/${row.PERIOD_NUM}`})
-      },
-      handleSelectionChange(val) {
-        this.multipleSelection = val
-      },
-      handleCurrentChange(page) {
-        this.getData(page, this.pageSize)
-      },
-      handleSizeChange(pageSize) {
-        this.getData(this.currentPage, pageSize)
-      },
-      handleFilterUser(filterData) {
-        filterHelper.handleFilterUser(this, filterData)
-      },
-      handleFilter() {
-        this.getData()
-      },
-      getData(page, pageSize) {
-        let filterData = this.filterModel
-        let vueObj = this
-        network.getPageData(this, 'bonus/period', page, pageSize, filterData, function (response) {
-          vueObj.allData = response
-        }, null, ['PERF_PERCENT', 'CALC_PERCENT', 'SENT_PERCENT'])
-      },
-      onMessageCallback(data) {
-        if (data) {
-          if (data.other && data.other.MODEL === 'PERIOD' && data.other.ID) {
-            this.$set(this.percentList[data.other.FIELD], data.other.ID, data.percent)
-          }
-          if (data.other && data.other.MODEL === 'PERIOD' && data.percent === 100) {
-            this.getData(this.currentPage, this.pageSize)
-          }
         }
-      },
+      }
     }
   }
+}
 </script>

+ 17 - 0
common/helpers/Cache.php

@@ -341,4 +341,21 @@ class Cache
         return UserRelation::getAllParentsFromRedis($userId);
     }
 
+    /**
+     * 设置 当前自动发放奖金的状态
+     *
+     *
+     */
+    public static function setWithdrawLock($status){
+        Yii::$app->cache->set('withdrawLock', $status);
+    }
+
+    /**
+     * 获取 当前自动发放奖金的状态
+     *
+     *
+     */
+    public static function getWithdrawLock(){
+        return Yii::$app->cache->get('withdrawLock');
+    }
 }

+ 59 - 0
common/models/forms/UserBonusForm.php

@@ -0,0 +1,59 @@
+<?php
+namespace common\models\forms;
+
+use common\components\Model;
+use yii\base\Exception;
+
+/**
+ * Login form
+ */
+class UserBonusForm extends Model
+{
+    public $periodNum;
+
+    private $_periodModel;
+    private $_limit = 1000;
+
+    /**
+     * @inheritdoc
+     */
+    public function rules()
+    {
+        return [];
+    }
+
+    public function scenarios()
+    {
+        $parentScenarios =  parent::scenarios();
+        $customScenarios = [
+            'autoWithdraw' => [],
+        ];
+        return array_merge($parentScenarios, $customScenarios);
+    }
+
+    public function attributeLabels()
+    {
+        return [];
+    }
+
+    /**
+     * 页面请求异步处理,生成提现单
+     * @return string | null
+     */
+    public function autoWithdrawWebToAsync(){
+        if(!$this->validate()){
+            return null;
+        }
+        // 异步处理添加任务
+        $settings = \Yii::$app->params['swooleAsyncTimer'];
+        $bonusSettings = \Yii::$app->params['swooleBonusConfig'];
+        $settings = array_merge($settings, $bonusSettings);
+        $taskKey = \Yii::$app->swooleAsyncTimer->asyncHandle('bonus/auto-withdraw', \Yii::$app->request->get(), $settings);
+        if($taskKey === false){
+            $this->addError('perf', '请求失败');
+            return null;
+        }
+        return 1;
+    }
+
+}

+ 64 - 0
common/models/forms/WithdrawForm.php

@@ -101,6 +101,7 @@ class WithdrawForm extends Model {
             'editByAdmin' => ['id', 'planPaidAt', 'createRemark'],
             'backByUser' => ['id', 'createRemark'],
             'excelPaidFalse' => ['sn', 'withdrawPeriodNum', 'paidAt', 'paidFailRemark', 'userName', 'realName', 'amount', 'bankRealName', 'bankNo'],
+            'batchWithdraw' => ['userName', 'applyAmount']
         ];
         return array_merge($parentScenarios, $customScenarios);
     }
@@ -703,4 +704,67 @@ class WithdrawForm extends Model {
         return true;
     }
 
+    /**
+     * 批量自动提现
+     *
+     *
+     * @throws \yii\db\Exception
+     */
+    public function batchWithdraw($limit, $start){
+        $config = Cache::getSystemConfig();
+        // 查找有奖金的用户
+        $allData = UserBonus::find()->select('USER_ID, USER_NAME, ID_CARD, BONUS')->from(UserBonus::tableName().' AS UB')->join('LEFT JOIN', User::tableName().' AS U','UB.USER_ID = U.ID')->where('BONUS>0')->offset(0)->limit($limit)->orderBy('U.ID')->asArray()->all();
+        if($allData){
+            foreach ($allData as $data){
+                $db = \Yii::$app->db;
+                $transaction = $db->beginTransaction();
+                try {
+                    $nowTime = $this->createdAt ?: Date::nowTime();
+                    $period = Withdraw::getPeriod($nowTime);
+                    //扣除会员奖金
+                    Balance::changeUserBonus($data['USER_ID'], 'BONUS', -abs($data['BONUS']), ['DEAL_TYPE_ID'=>DealType::WITHDRAW,'REMARK' => 'batch withdrawal', 'TIME' => $nowTime]);
+                    //手续费
+                    $fees = $data['BONUS'] * $config['withdrawFee']['VALUE']/100;
+                    $fees = Tool::formatPrice($fees);
+                    $realAmount = $data['BONUS'] - $fees;
+                    //判断付款类型
+                    $payType = Withdraw::PAY_TYPE_NO_INVOICE;
+                    $withdrawModel = new Withdraw();
+                    $withdrawModel->SN = $this->_generateSn();
+                    $withdrawModel->USER_ID = $data['USER_ID'];
+                    $withdrawModel->ID_CARD = $data['ID_CARD'];
+                    $withdrawModel->WITHDRAW_PERIOD_NUM = $period['nowPeriodNum'];
+                    $withdrawModel->WITHDRAW_YEAR = $period['nowYear'];
+                    $withdrawModel->WITHDRAW_MONTH = $period['nowMonth'];
+                    $withdrawModel->PAY_TYPE = $payType;
+                    $withdrawModel->IS_AUTO_WITHDRAW = $this->scenario == 'batchWithdraw' ? 1 : 0;
+                    $withdrawModel->AMOUNT = $data['BONUS'];
+                    $withdrawModel->FEES = $fees;
+                    $withdrawModel->REAL_AMOUNT = $realAmount;
+                    $withdrawModel->P_MONTH = Date::ociToDate($period['yearMonth'], Date::OCI_TIME_FORMAT_SHORT_MONTH);
+                    $withdrawModel->AUDIT_STATUS = Withdraw::STATUS_APPLIED;
+                    $withdrawModel->CREATED_AT = $nowTime;
+                    //预计付款时间
+                    $withdrawModel->PLAN_PAID_AT = $period['endTime'] + $config['withdrawFreezeDays']['VALUE'] * 3600 * 24;
+
+                    if (!$withdrawModel->save()) {
+                        throw new Exception(Form::formatErrorsForApi($withdrawModel->getErrors()));
+                    }
+//                    print_r($data['BONUS'].',,'.$i.PHP_EOL);
+                    $transaction->commit();
+                    unset($withdrawModel);
+                } catch (Exception $e) {
+                    $transaction->rollBack();
+                    $this->addError('add', $e->getMessage());
+                    return false;
+                }
+            }
+            unset($allData);
+            $start = $start + $limit;
+
+            return self::batchWithdraw($limit, $start);
+        }
+        return true;
+    }
+
 }

+ 13 - 0
console/controllers/BonusController.php

@@ -53,8 +53,10 @@ use common\helpers\http\RemoteUploadApi;
 use common\helpers\Log;
 use common\libs\export\module\BonusExport;
 use common\models\forms\PeriodForm;
+use common\models\forms\WithdrawForm;
 use common\models\LogAsync;
 use common\models\Withdraw;
+use common\models\UserBonus;
 use yii\db\Exception;
 
 class BonusController extends BaseController
@@ -547,4 +549,15 @@ class BonusController extends BaseController
         unset($factory, $taskId, $className, $listName);
         return false;
     }
+
+    /**
+     * 批量提现
+     *
+     */
+    public function actionAutoWithdraw($taskKey){
+        Cache::setWithdrawLock(1);
+        $formModel = new WithdrawForm();
+        $formModel->batchWithdraw(1000,0);
+        Cache::setWithdrawLock(0);
+    }
 }

+ 1 - 0
frontendApi/modules/v1/controllers/FinanceController.php

@@ -32,6 +32,7 @@ use common\models\Transfer;
 use common\models\Uploads;
 use common\models\UserInfo;
 use common\models\Withdraw;
+use common\models\UserBonus;
 use yii\helpers\Json;
 use yii\web\UploadedFile;