Explorar el Código

蓝星奖重构

kevin_zhangl hace 2 años
padre
commit
6fb5338e84

+ 283 - 8
common/helpers/bonus/BonusCalc.php

@@ -10,11 +10,15 @@ namespace common\helpers\bonus;
 
 use common\helpers\Cache;
 use common\helpers\Date;
+use common\helpers\LoggerTool;
 use common\helpers\snowflake\SnowFake;
 use common\helpers\Tool;
+use common\models\BsBonus103Calc;
+use common\models\BsBonus103CalcEvent;
 use common\models\CalcBonus;
 use common\models\CalcBonusBD;
 use common\models\CalcBonusBS;
+use common\models\CalcBonusBsDefaultBonus;
 use common\models\CalcBonusBT;
 use common\models\CalcBonusCF;
 use common\models\CalcBonusFL;
@@ -52,9 +56,11 @@ use common\models\User;
 use common\models\UserInfo;
 use common\models\UserPerf;
 use SebastianBergmann\CodeCoverage\Report\PHP;
+use Yii;
 use yii\base\BaseObject;
 use yii\base\Exception;
 use yii\base\StaticInstanceTrait;
+use yii\db\Expression;
 use yii\helpers\Json;
 
 class BonusCalc extends BaseObject {
@@ -107,6 +113,10 @@ class BonusCalc extends BaseObject {
     //最小报单pv
     const MIN_BD_PV = 980;
 
+    const QUALIFIED_NONE = 0;   // 无达标状态
+    const QUALIFIED_SELF = 1;       // 自身业绩达标
+    const QUALIFIED_CASCADE = 2;   // 级联被动达标
+
     /**
      * 1、抓取所有报单、订单,把能当时产生业绩的报单存入业绩单。例如注册单,订单
      * 2、从业绩单中循环,并计算上下级业绩
@@ -240,14 +250,44 @@ class BonusCalc extends BaseObject {
             $t17 = microtime(true);
             // 蓝星奖入库,实际上是插入有奖金会员数据缓存中.
             // 调用存储过程,计算蓝星管理奖金
-            $this->calcBsProcedure();
-            // 将有蓝星管理奖金的用户加入到有奖金缓存用户中
-            $this->calcBonusBsGL();
-            $this->calcBonusBsGLCF();
-            $this->calcBonusBsYJCF();
-            $t18 = microtime(true);
-            echo('计算蓝星管理奖'.($this->_sysConfig['openGL']['VALUE']?'完成':'关闭').',耗时:' . round($t18 - $t17, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
-            $this->_updatePercent(65);
+//            $this->calcBsProcedure();
+//            // 将有蓝星管理奖金的用户加入到有奖金缓存用户中
+//            $this->calcBonusBsGL();
+//            $this->calcBonusBsGLCF();
+//            $this->calcBonusBsYJCF();
+
+            // 不是结算月,则不进行计算
+            if ($this->_isCalcMonth) {
+                echo('计算蓝星管理奖开始,' . PHP_EOL);
+                // 期数配置
+                $calcData = Period::findOneAsArray('PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
+                // 删除日志
+                BsBonus103CalcEvent::deleteAll();
+                // 清除数据
+                $this->calcClean($this->_periodNum);
+                // 初始化
+                $this->calcBsInitProcedure($this->_periodNum, $calcData['CALC_MONTH'], $calcData['CALC_YEAR']);
+
+                // 推荐网最大层级,用于循环
+                $maxLayer = BsBonus103Calc::getMaxLayer($periodNum);
+
+                // 报单业绩上推
+                $this->calcBsPushPerf($this->_periodNum, $maxLayer);
+                // 业绩汇总
+                $this->calcBsSummaryPerf($this->_periodNum);
+                // 第一次紧缩网络、连带达标
+                $this->calcBsNetworkAusterity($this->_periodNum, $maxLayer);
+                // 计算1星奖金、赋星级
+//                $this->calcBsBonus($this->_periodNum);
+
+                // TODO: 任务进度
+                $this->calcTask(10, '完成', $this->_periodNum);
+
+                $t18 = microtime(true);
+                echo('计算蓝星管理奖'.($this->_sysConfig['openGL']['VALUE']?'完成':'关闭').',耗时:' . round($t18 - $t17, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
+                $this->_updatePercent(65);
+
+            }
 
             //把奖金会员写入缓存
             $this->loopMonthBonusUserFromDbToCache();
@@ -1701,6 +1741,241 @@ class BonusCalc extends BaseObject {
         return $result;
     }
 
+    /**
+     * 记录任务进度
+     * @param $taskId
+     * @param $taskName
+     * @param $period
+     * @return int
+     * @throws \yii\db\Exception
+     */
+    public function calcTask($taskId, $taskName, $period) {
+        // 写任务进度
+        return \Yii::$app->db->createCommand("CALL CalcRecord(:taskId, :taskName, :period, :time)")
+            ->bindValues([':taskId' => $taskId, ':taskName' => $taskName, ':period' => $period, ':time' => date('Y-m-d H:i:s')])
+            ->execute();
+    }
+
+    /**
+     * 清除数据
+     * @param $periodNum
+     * @return int
+     * @throws \yii\db\Exception
+     */
+    public function calcClean($periodNum)
+    {
+        // 任务进度
+        $this->calcTask(1, '清除数据', $periodNum);
+        // 蓝星奖初始化
+        return \Yii::$app->db->createCommand("CALL CalcClean(:periodNum)")
+            ->bindValue(':periodNum' , $this->_periodNum )
+            ->execute();
+    }
+
+    /**
+     * 蓝星奖初始化
+     * @throws \yii\db\Exception
+     */
+    public function calcBsInitProcedure($periodNum, $calcMonth, $calcYear) {
+        // 任务进度
+        $this->calcTask(2, '初始化', $periodNum);
+        // 蓝星奖初始化
+        return \Yii::$app->db->createCommand("CALL CalcInit(:periodNum, :calcMonth, :calcYear)")
+            ->bindValues([':periodNum' => $periodNum, ':calcMonth' => $calcMonth, ':calcYear' => $calcYear])
+            ->execute();
+    }
+
+    /**
+     * 报单业绩上推
+     * @param $periodNum
+     * @param $maxLayer
+     * @return bool
+     * @throws \yii\db\Exception
+     */
+    public function calcBsPushPerf($periodNum, $maxLayer) {
+        // 任务进度
+        $this->calcTask(3, '报单业绩上推', $periodNum);
+        for ($i = $maxLayer; $i > 0; $i--) {
+            // 查询本层会员
+            $calcLayers = BsBonus103Calc::findAllAsArray('CALC_PERIOD_ID=:CALC_PERIOD_ID AND LAYER=:LAYER AND PV_ZC>0', [':CALC_PERIOD_ID' => $periodNum, ':LAYER' => $i]);
+            foreach ($calcLayers as $data) {
+                // 会员报单业绩上推
+                BsBonus103Calc::updateAll(
+                    ['PV_UP_ZC' => new Expression('PV_UP_ZC+' . $data['PV_ZC'])],
+                    'USER_ID=:USER_ID AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                    [':USER_ID' => $data['INTRODUCER_ID'], ':CALC_PERIOD_ID' => $data['CALC_PERIOD_ID']]);
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 业绩汇总
+     * @param $periodNum
+     * @return int
+     * @throws \yii\db\Exception
+     */
+    public function calcBsSummaryPerf($periodNum) {
+        // 任务进度
+        $this->calcTask(4, '业绩汇总', $periodNum);
+        return BsBonus103Calc::updateAll(['GPV10' => new Expression('PV_UP_ZC+PV_FX')], 'CALC_PERIOD_ID=:CALC_PERIOD_ID', [':CALC_PERIOD_ID' => $periodNum]);
+    }
+
+    /**
+     * 第一次紧缩网络、连带达标、赋星级
+     * @param $periodNum
+     * @param $maxLayer
+     * @return bool
+     * @throws \yii\db\Exception
+     */
+    public function calcBsNetworkAusterity($periodNum, $maxLayer): bool
+    {
+        // 任务进度
+        $this->calcTask(5, '第一次紧缩网络&连带达标&赋星', $periodNum);
+        // 一星达标业绩
+        $achievePv = Cache::getEmpLevelConfig()['E121497617216708615']['ACHIEVE_PV'];
+
+        for ($i = $maxLayer; $i >= 0; $i--) {
+            if ($i > 0) {
+                // 需要清空业绩的会员
+                $unQualified = [];
+                // 查询本层会员
+                $calcLayers = BsBonus103Calc::findAllAsArray('CALC_PERIOD_ID=:CALC_PERIOD_ID AND LAYER=:LAYER AND GPV10 > 0', [':CALC_PERIOD_ID' => $periodNum, ':LAYER' => $i]);
+
+                foreach ($calcLayers as $data) {
+                    LoggerTool::debug(['qualified', $data['USER_ID'], $data['LAYER'], $data['GPV10']]);
+                    $t1 = microtime(true);
+                    // 业绩达标
+                    if ($data['GPV10'] >= $achievePv) {
+                        // 标记自身业绩达标、赋星级、汇总业绩
+                        BsBonus103Calc::updateAll(
+                            ['QUALIFIED' => self::QUALIFIED_SELF, 'USER_TYPE10' => 10],
+                            'USER_ID=:USER_ID AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                            [':USER_ID' => $data['USER_ID'], ':CALC_PERIOD_ID' => $data['CALC_PERIOD_ID']]);
+
+                        // 所有上级
+                        $introducerList = $this->getIntroducerList($data['USER_ID'], $data['CALC_PERIOD_ID']);
+                        LoggerTool::debug([$data['USER_ID'], $introducerList]);
+                        if ($introducerList) {
+                            $introducerList = implode(',', $introducerList);
+                            // 连带达标
+                            BsBonus103Calc::updateAll(
+                                ['QUALIFIED' => self::QUALIFIED_CASCADE],
+                                'USER_ID IN (:USER_ID) AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                                [':USER_ID' => $introducerList, ':CALC_PERIOD_ID' => $data['CALC_PERIOD_ID']]);
+                        }
+                    } else if ($data['QUALIFIED'] == self::QUALIFIED_NONE) {
+                        // 未达标会员,且未被连带达标,业绩上推给上级
+                        BsBonus103Calc::updateAll(
+                            ['GPV10' => new Expression('GPV10+' . $data['GPV10'])],
+                            'USER_ID=:INTRODUCER_ID AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                            [':INTRODUCER_ID' => $data['INTRODUCER_ID'], ':CALC_PERIOD_ID' => $data['CALC_PERIOD_ID']]);
+                        // 清空自身业绩
+                        $unQualified[] = $data['USER_ID'];
+                    }
+
+                    $t2 = microtime(true);
+                    LoggerTool::notice(['calcBsNetworkAusterityForEach', $i, round($t2 - $t1, 3)]);
+                }
+
+                if ($unQualified) {
+                    // 清空自身业绩
+                    BsBonus103Calc::updateAll(
+                        ['GPV10' => 0],
+                        'USER_ID IN (:USER_ID) AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                        [':USER_ID' => implode(',', $unQualified), ':CALC_PERIOD_ID' => $periodNum]);
+                }
+            } else {
+                // 查询本层会员
+                $calcLayers = BsBonus103Calc::findAllAsArray('CALC_PERIOD_ID=:CALC_PERIOD_ID AND LAYER=:LAYER AND GPV10 > 0', [':CALC_PERIOD_ID' => $periodNum, ':LAYER' => $i]);
+
+                foreach ($calcLayers as $data) {
+                    LoggerTool::debug(['qualified', $data['USER_ID'], $data['LAYER'], $data['GPV10']]);
+                    $t1 = microtime(true);
+                    // 自身业绩达标
+                    if ($data['GPV10'] >= $achievePv) {
+                        // 标记自身业绩达标
+                        BsBonus103Calc::updateAll(
+                            ['QUALIFIED' => self::QUALIFIED_SELF, 'USER_TYPE10' => 10, 'GPV10' => new Expression('GPV10+' . $data['GPV10'])],
+                            'USER_ID=:USER_ID AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                            [':USER_ID' => $data['USER_ID'], ':CALC_PERIOD_ID' => $data['CALC_PERIOD_ID']]);
+                    } else if ($data['QUALIFIED'] == self::QUALIFIED_NONE) {
+                        // 未达标会员,且未被连带达标,清空自身业绩
+                        BsBonus103Calc::updateAll(
+                            ['GPV10' => 0],
+                            'USER_ID IN (:USER_ID) AND CALC_PERIOD_ID=:CALC_PERIOD_ID',
+                            [':USER_ID' => $data['USER_ID'], ':CALC_PERIOD_ID' => $periodNum]);
+                    }
+
+                    $t2 = microtime(true);
+                    LoggerTool::notice(['calcBsNetworkAusterityForEach', $i, round($t2 - $t1, 3)]);
+                }
+            }
+        }
+
+        return true;
+    }
+
+    /**
+     * 计算奖金
+     * @param $periodNum
+     * @return bool
+     * @throws \yii\db\Exception
+     */
+    public function calcBsBonus($periodNum): bool
+    {
+        // 任务进度
+        $this->calcTask(4, '计算一星奖金', $periodNum);
+        // 一星奖金比例
+        $percent = Cache::getEmpLevelConfig()['E121497617216708615']['BS_PERCENT'] / 100;
+        // 推荐网最大层级,用于循环
+        $maxLayer = BsBonus103Calc::getMaxLayer($periodNum);
+
+        $rows = [];
+        for ($i = $maxLayer; $i >= 0; $i--) {
+            // 查询本层会员
+            $calcLayers = BsBonus103Calc::find()->where('CALC_PERIOD_ID=:CALC_PERIOD_ID AND LAYER=:LAYER AND QUALIFIED>:QUALIFIED', [':CALC_PERIOD_ID' => $periodNum, ':LAYER' => $i, ':QUALIFIED' => 0])->all();
+
+            foreach ($calcLayers as $data) {
+                $rows[] = [
+                    $data['USER_ID'],
+                    $data['INTRODUCER_ID'],
+                    $data['USER_TYPE10'],
+                    $data['GPV10'] * $percent,
+                    $data['GPV10'],
+                    $percent,
+                    $data['CALC_PERIOD_ID'],
+                ];
+            }
+        }
+
+        if ($rows) {
+            // 奖金入库
+            $columns = ['USER_ID', 'INTRODUCER_ID', 'LAST_EMP_LV', 'LAST_EMP_LV', 'ORI_BONUS', 'PV', 'RATE', 'PERIOD_NUM'];
+            Yii::$app->db->createCommand()->batchInsert(CalcBonusBsDefaultBonus::tableName(), $columns, $rows)->execute();
+        }
+
+        return true;
+    }
+
+    /**
+     * 获取上级
+     * @param $userId
+     * @param $period
+     * @param array $introducerList
+     * @return array
+     */
+    public function getIntroducerList($userId, $period, array $introducerList = []): array
+    {
+        $introducer = BsBonus103Calc::getIntroducer($userId, $period);
+        // 如果会员的上级已经被标记达标,则不再向上查找
+        if ($introducer['QUALIFIED'] == self::QUALIFIED_NONE) {
+            $introducerList[] = $introducer['INTRODUCER_ID'];
+            $this->getIntroducerList($introducer['INTRODUCER_ID'], $period, $introducerList);
+        }
+        return $introducerList;
+    }
 
     /**
      * 蓝星管理奖金未拆分

+ 41 - 0
common/models/BsBonus103Calc.php

@@ -0,0 +1,41 @@
+<?php
+
+namespace common\models;
+use common\components\ActiveRecord;
+
+
+/**
+ * This is the model class for table "{{%BS_BONUS_103_CALC}}".
+ *
+ */
+class BsBonus103Calc extends ActiveRecord
+{
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%BS_BONUS_103_CALC}}';
+    }
+
+    /**
+     * 查询指定期数最大推荐网层级.
+     * @param integer $period 期数
+     * @return bool|mixed|string|null
+     */
+    public static function getMaxLayer(int $period)
+    {
+        return static::find()->where('CALC_PERIOD_ID=:CALC_PERIOD_ID', [':CALC_PERIOD_ID' => $period])->max('LAYER');
+    }
+
+    /**
+     * 会员的上级
+     * @param $userId
+     * @param $period
+     * @return array|null
+     */
+    public static function getIntroducer($userId, $period)
+    {
+        return static::findOneAsArray('USER_ID=:USER_ID AND CALC_PERIOD_ID=:CALC_PERIOD_ID', [':USER_ID' => $userId, ':CALC_PERIOD_ID' => $period]);
+    }
+}

+ 20 - 0
common/models/BsBonus103CalcEvent.php

@@ -0,0 +1,20 @@
+<?php
+
+namespace common\models;
+use common\components\ActiveRecord;
+
+
+/**
+ * This is the model class for table "{{%BS_BONUS_103_CALC_EVENT}}".
+ *
+ */
+class BsBonus103CalcEvent extends ActiveRecord
+{
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%BS_BONUS_103_CALC_EVENT}}';
+    }
+}

+ 14 - 0
common/models/CalcBonusBsDefaultBonus.php

@@ -0,0 +1,14 @@
+<?php
+
+namespace common\models;
+
+class CalcBonusBsDefaultBonus extends \common\components\ActiveRecord
+{
+    /**
+     * @inheritdoc
+     */
+    public static function tableName()
+    {
+        return '{{%CALC_BONUS_BS_DETAIL_BONUS}}';
+    }
+}