CalcServePerfCalc.php 31 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697
  1. <?php
  2. /**
  3. */
  4. namespace common\helpers\bonus;
  5. use common\helpers\Cache;
  6. use common\helpers\Date;
  7. use common\helpers\snowflake\SnowFake;
  8. use common\models\PerfOrder;
  9. use common\models\PerfPeriod;
  10. use common\models\Period;
  11. use common\models\PerfMonth;
  12. use common\models\ServeProcess;
  13. use common\models\UserNetwork;
  14. use yii\base\Exception;
  15. use yii\base\StaticInstanceTrait;
  16. class CalcServePerfCalc {
  17. use StaticInstanceTrait;
  18. private $_limit = 3000;
  19. private $_companyMonthPerf = 0;
  20. private $_cfTotalPercent = 0;
  21. private $_lxTotalPercent = 0;
  22. private $_sysConfig = [];
  23. private $_decLevelConfig = [];
  24. private $_empLevelConfig = [];
  25. private $_decRoleConfig = [];
  26. private $_periodNum = 0;
  27. private $_isCalcMonth = 0;
  28. private $_calcYear;
  29. private $_calcMonth;
  30. private $_calcYearMonth;
  31. private $_lastCalcYear;
  32. private $_lastCalcMonth;
  33. private $_lastCalcYearMonth;
  34. private $_lastPeriodNum;
  35. private $_periodObj;
  36. const LOOP_FINISH = 1;
  37. const LOOP_CONTINUE = 2;
  38. const ORDER_PAY_TYPE_CASH = 'cash';
  39. /**
  40. * 获取期数
  41. * @return int
  42. */
  43. public function getPeriodNum() {
  44. return $this->_periodNum;
  45. }
  46. // 校验是否可进行计算
  47. public function isCalcIng($periodNum) {
  48. $periodObj = Period::instance();
  49. $periodDataArr = $periodObj->setPeriodNum($periodNum);
  50. if (empty($periodDataArr)) {
  51. return false;
  52. }
  53. if ($periodDataArr['IS_PREPARE'] != 1) {
  54. return false;
  55. }
  56. $this->_periodNum = $periodDataArr['PERIOD_NUM'];
  57. $this->_periodObj = $periodObj;
  58. return true;
  59. }
  60. /**
  61. * 累计业绩数据
  62. * @param $periodNum
  63. * @return bool
  64. */
  65. public function calcStep($periodNum = null) {
  66. try {
  67. // // $userId="317189059070005248";
  68. // $userId="376748282036228096";
  69. // $sql = "SELECT t2.USER_ID
  70. // FROM
  71. // (
  72. // SELECT
  73. // @r AS _id,
  74. // (SELECT @r := PARENT_UID FROM AR_USER_NETWORK_NEW WHERE USER_ID = _id) AS PARENT_UID,
  75. // @l := @l + 1 AS lvl
  76. // FROM
  77. // (SELECT @r := '".$userId."', @l := 0) vars, AR_USER_NETWORK_NEW AS h
  78. // WHERE @r <> 0
  79. // ) t1
  80. // JOIN AR_USER_NETWORK_NEW t2
  81. // ON t1._id = t2.USER_ID AND t1._id != '".$userId."';";
  82. // $parentUidsArr = \Yii::$app->db->createCommand($sql)->queryAll();
  83. // if (empty($parentUidsArr)) {
  84. // return [];
  85. // }
  86. // $allUserIds = array_column($parentUidsArr, 'USER_ID');
  87. // $allUserIds = array_reverse($allUserIds);
  88. // $allkey = array_values($allUserIds);
  89. // $allvalue = array_keys($allUserIds);
  90. // $resourceData = array_combine($allkey, $allvalue);
  91. // // echo '<pre>';var_dump($resourceData);
  92. // if(empty($allUserIds)) return [];
  93. // $topDeep = count($allUserIds);
  94. // $pageParentUids = array_slice($allUserIds, 0, 100);
  95. // $parentList = [];
  96. // foreach ($pageParentUids as $parentUid) {
  97. // $nowKey = $resourceData[$parentUid];
  98. // $nearSon = $nowKey+1;
  99. // if ($nearSon == $topDeep) {
  100. // $locationInfoUid = $userId;
  101. // } else {
  102. // $locationInfoUid = $allUserIds[$nearSon];
  103. // }
  104. // $parentNetInfo = UserNetwork::find()
  105. // ->select(['RELATIVE_LOCATION', 'PARENT_UID'])
  106. // ->where('USER_ID=:USER_ID', ['USER_ID'=>$locationInfoUid])
  107. // ->asArray()
  108. // ->one();
  109. // $location = $parentNetInfo['RELATIVE_LOCATION'];
  110. // $parentList[] = [
  111. // 'USER_ID' => $userId,
  112. // 'TOP_DEEP' => $topDeep,
  113. // 'PARENT_UID' => $parentUid,
  114. // 'LOCATION' => $location,
  115. // ];
  116. // }
  117. // echo '<pre>';var_dump($parentList);exit;
  118. // unset($allUserIds);
  119. // return '1111';exit;
  120. //////////////////////////////////////////////////////////////////////////////////////
  121. $requestTime = date('Y-m-d H:i:s', time());
  122. if (empty($periodNum)) {
  123. echo('触发时间:【'.$requestTime.'】'.'定时器执行累计业绩计算 ,内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  124. } else {
  125. echo('触发时间:【'.$requestTime.'】'.'手动触发累计业绩计算 ,内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  126. }
  127. //一、查询此业绩状态,是否能进行计算
  128. $calcIng = $this->isCalcIng($periodNum);
  129. ServeProcess::recordRequest($requestTime, $this->_periodNum, '', true);
  130. if ($calcIng !== true) {
  131. echo('触发时间:【'.date('Y-m-d H:i:s', time()).'】'.'业绩期表中,此期状态不正确');
  132. //ServeProcess::recordRequest($requestTime, $this->_periodNum, '业绩期表中,此期状态不正确');
  133. return false;
  134. } else {
  135. // 将IS_PREPARE改成2,计算中
  136. Period::updateCalcProcess(2, $this->_periodNum);
  137. ServeProcess::recordRequest($requestTime, $this->_periodNum, '调整IS_PREPARE值为2,计算开始');
  138. }
  139. // 记录初始化数据,用户总数,业绩单业绩总pv值.
  140. ServeProcess::recordDataInfo(date('Y-m-d H:i:s',time()), $this->_periodNum);
  141. $t1 = microtime(true);
  142. //二、初始化
  143. $this->initCalcTask();
  144. echo '业绩期为:'.$this->_periodNum;
  145. Period::updatePercent(10, $this->_periodNum);
  146. ServeProcess::recordProcess($t1, time(), $this->_periodNum, '初始化---初始化配置');
  147. $initT2 = microtime(true);
  148. //三、 设置结算状态
  149. $this->setCalcStatus('start', $this->_periodNum);
  150. ServeProcess::recordProcess($initT2, time(), $this->_periodNum, '初始化---设置结算状态');
  151. $initT3 = microtime(true);
  152. //四、 清空所有本期结算用到的缓存
  153. CalcCache::clearAll($this->_periodNum);
  154. ServeProcess::recordProcess($initT3, time(), $this->_periodNum, '初始化---清空业绩缓存');
  155. $initT4 = microtime(true);
  156. //五、 清空会员推荐和接点关系缓存
  157. CalcCache::clearNetCache();
  158. ServeProcess::recordProcess($initT4, time(), $this->_periodNum, '初始化---清空会员推荐和接点关系缓存');
  159. $initT5 = microtime(true);
  160. //六、 清空相关表数据
  161. $this->clearTableData();
  162. $this->_updatePercent(15);
  163. ServeProcess::recordProcess($initT5, time(), $this->_periodNum, '初始化---清空相关表数据');
  164. $t2 = microtime(true);
  165. echo(date('Y-m-d H:i:s',time()).'初始化、清空缓存及相关数据表完成,耗时:' . round($t2 - $t1, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  166. ServeProcess::recordProcess($t1, $t2, $this->_periodNum, '初始化---初始化、清空缓存及相关数据表完成');
  167. //七、 添加缓存中用户数据
  168. CalcCache::addUsers($this->_periodNum);
  169. $t3 = microtime(true);
  170. echo(date('Y-m-d H:i:s',time()).'计算业绩向缓存中加入用户完成,耗时:' . round($t3 - $t2, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  171. ServeProcess::recordProcess($t2, $t3, $this->_periodNum, '计算业绩向缓存中加入用户完成');
  172. $this->_updatePercent(20);
  173. // 八、循环累计用户各项业绩数据
  174. $this->loopGrandPerf();
  175. $t4 = microtime(true);
  176. echo(date('Y-m-d H:i:s',time()).'累计用户业绩完成' . round($t4 - $t3, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  177. ServeProcess::recordProcess($t3, $t4, $this->_periodNum, '累计用户业绩完成');
  178. $this->_updatePercent(60);
  179. // 九、本期业绩入库
  180. $this->loopWriteNowPerf();
  181. $t6 = microtime(true);
  182. echo(date('Y-m-d H:i:s',time()).'本期业绩入库完成,耗时:' . round($t6 - $t4, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  183. ServeProcess::recordProcess($t4, $t6, $this->_periodNum, '本期业绩入库完成');
  184. $this->_updatePercent(70);
  185. //十、计算月业绩表中的数据
  186. $this->loopCalcMonthPerfTableData();
  187. $t7 = microtime(true);
  188. echo(date('Y-m-d H:i:s',time()).'计算月业绩表中的数据完成,耗时:' . round($t7 - $t6, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  189. if($this->_isCalcMonth) {
  190. ServeProcess::recordProcess($t6, $t7, $this->_periodNum, '计算月业绩表中的数据完成');
  191. }
  192. $this->_updatePercent(80);
  193. //十一、本月业绩入库
  194. $this->loopWriteMonthPerf();
  195. $t8 = microtime(true);
  196. echo(date('Y-m-d H:i:s',time()).'本月业绩入库完成,耗时:' . round($t8 - $t7, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  197. if($this->_isCalcMonth) {
  198. ServeProcess::recordProcess($t7, $t8, $this->_periodNum, '本月业绩入库完成');
  199. }
  200. $this->_updatePercent(100);
  201. $t9 = microtime(true);
  202. ServeProcess::recordProcess($t6, $t7, $this->_periodNum, '计算业绩业绩结算全部完成');
  203. echo(date('Y-m-d H:i:s',time()).'计算业绩业绩结算全部完成,共耗时:' . round($t9 - $t1, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  204. } catch (\Exception $e) {
  205. $this->errorCalcTask();
  206. var_dump($e->getMessage());
  207. return false;
  208. }
  209. $this->endCalcTask();
  210. return true;
  211. }
  212. /**
  213. * 结算完成
  214. * @return bool
  215. */
  216. public function endCalcTask() {
  217. // 更新结算状态
  218. $this->setCalcStatus('end');
  219. }
  220. /**
  221. * 结算错误
  222. */
  223. public function errorCalcTask() {
  224. // 清空所有本期结算用到的缓存
  225. CalcCache::clearAll($this->_periodNum);
  226. // 更新结算状态
  227. $this->setCalcStatus('fail');
  228. }
  229. /**
  230. * 设置生成业绩单状态
  231. * @param $type
  232. * start|end|fail
  233. */
  234. public function setCalcStatus($type, $periodNum = null) {
  235. if ($type == 'start') {
  236. Period::updateAll(['IS_PERFING' => 1, 'IS_PERFED' => Period::PERF_NONE, 'PERF_STARTED_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  237. } elseif ($type == 'end') {
  238. Period::updateAll(['IS_PERFING' => 0, 'IS_PERFED' => Period::PERF_FINISH, 'PERFED_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  239. } elseif ($type == 'fail') {
  240. Period::updateAll(['IS_PERFING' => 0, 'IS_PERFED' => Period::PERF_FAIL, 'PERFED_AT' => 0], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  241. }
  242. }
  243. /**
  244. * 初始化结算任务
  245. * @throws \yii\db\Exception
  246. */
  247. public function initCalcTask() {
  248. try {
  249. $periodObj = Period::instance();
  250. $this->_sysConfig = Cache::getSystemConfig();
  251. $this->_decLevelConfig = Cache::getDecLevelConfig();
  252. $this->_empLevelConfig = Cache::getEmpLevelConfig();
  253. $this->_decRoleConfig = CalcCache::getDecRoleConfig($this->_periodNum);
  254. $this->_isCalcMonth = $periodObj->isCalcMonth($this->_periodNum);
  255. $this->_calcYear = $periodObj->getYear($this->_periodNum);
  256. $this->_calcMonth = $periodObj->getMonth($this->_periodNum);
  257. $this->_calcYearMonth = $periodObj->getYearMonth($this->_periodNum);
  258. } catch(Exception $e) {
  259. var_dump($e->getMessage());
  260. }
  261. }
  262. /**
  263. * 清空相关表数据
  264. */
  265. public function clearTableData() {
  266. PerfPeriod::pageDeleteAll('PERIOD_NUM='.$this->_periodNum);// 周业绩
  267. if ($this->_isCalcMonth) {
  268. PerfMonth::pageDeleteAll("CALC_MONTH='{$this->_calcYearMonth}'");// 月业绩表
  269. }
  270. }
  271. /**
  272. * 累计用户业绩
  273. * @param int $offset
  274. * @return bool
  275. * @throws \yii\db\Exception
  276. */
  277. public function loopGrandPerf($offset = 0) {
  278. $allData = PerfOrder::findUseDbCalc()
  279. ->select('ORDER_AMOUNT,PERF_TYPE,USER_ID,PV,PERIOD_NUM,DEC_USER_ID,PAY_TYPE')
  280. ->where(
  281. "PERIOD_NUM=:PERIOD_NUM",
  282. [':PERIOD_NUM' => $this->_periodNum]
  283. )
  284. ->orderBy('CREATED_AT DESC,ID DESC')
  285. ->offset($offset)
  286. ->limit($this->_limit)
  287. ->asArray()
  288. ->all();
  289. if (!empty($allData)) {
  290. foreach ($allData as $data) {
  291. // 循环累计报单业绩
  292. try{
  293. echo "开始累计用户业绩,用户ID为:".$data['USER_ID'].PHP_EOL;
  294. if ($data['PERF_TYPE'] == PerfOrder::ZC_TYPE) {
  295. // 给自己增加PCS(个人消费)
  296. CalcCache::nowPeriodPerf($data['USER_ID'], $this->_periodNum, [
  297. 'PV_PCS' => $data['PV'],
  298. 'PV_PCS_ZC' => $data['PV'],
  299. ]);
  300. // 把该会员加入到能拿到业绩的会员缓存中
  301. CalcCache::addHasPerfUsers($data['USER_ID'], $this->_periodNum);
  302. //加入到报单会员中
  303. $toInfo = CalcCache::getUserInfo($data['USER_ID'], $this->_periodNum);
  304. CalcCache::addHasBDUsers($data['USER_ID'], $this->_periodNum, [
  305. 'TO_USER_ID' => $data['USER_ID'],
  306. 'USER_ID' => $toInfo['DEC_ID'],
  307. 'DEC_ID' => $toInfo['DEC_ID'],
  308. //考虑可能会移网的情况
  309. 'REC_USER_ID' => $toInfo['REC_UID'] ?? '',
  310. 'CON_USER_ID' => $toInfo['CON_UID'] ?? '',
  311. 'DEC_AMOUNT' => $data['ORDER_AMOUNT'],
  312. 'DEC_PV' => $data['PV'],
  313. ]);
  314. // 给上追加业绩
  315. $this->loopNetworkParentDo($data['USER_ID'], function ($parent) use (&$data) {
  316. // 给上级会员追加本期业绩到缓存中
  317. CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
  318. 'PV_' . $parent['LOCATION'] . 'L' => $data['PV'],
  319. 'PV_' . $parent['LOCATION'] . 'L_TOUCH' => $data['PV'],
  320. 'PV_' . $parent['LOCATION'] . 'L_' . $data['PERF_TYPE'] => $data['PV'],
  321. ]);
  322. // 把该会员加入到能拿到业绩的会员缓存中
  323. CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
  324. unset($parent);
  325. });
  326. //给推荐关系累计增加业绩
  327. $this->loopRelationParentDo($data['USER_ID'], function ($parent) use (&$data) {
  328. // 给上级会员追加本期业绩到缓存中
  329. CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
  330. 'PV_PSS' => $data['PV'],
  331. ]);
  332. // 把该会员加入到能拿到业绩的会员缓存中
  333. CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
  334. unset($parent);
  335. });
  336. }
  337. } catch(Exception $e) {
  338. var_dump(__LINE__,__FILE__,$e->getMessage(), $data);
  339. }
  340. // 循环累计复消业绩
  341. try{
  342. if ($data['PERF_TYPE'] == PerfOrder::FX_TYPE) {
  343. if( $data['PAY_TYPE'] === self::ORDER_PAY_TYPE_CASH ) {
  344. $orderCashAmount = $data['ORDER_AMOUNT'];
  345. $payPv = $data['PV'] * $this->_sysConfig['cashReconsumeBonusPercent']['VALUE'] / 100;
  346. $cacheDataKey = 'PV_PCS_FX_CASH';
  347. } else {
  348. $orderCashAmount = 0;
  349. $payPv = $data['PV'];
  350. $cacheDataKey = 'PV_PCS_FX_POINT';
  351. }
  352. if( $payPv <= 0 ) continue;
  353. // 给自己增加PCS(个人消费)
  354. CalcCache::nowPeriodPerf($data['USER_ID'], $this->_periodNum, [
  355. 'FX_AMOUNT_CASH' => $orderCashAmount,
  356. 'PV_PCS' => $payPv,
  357. 'PV_PCS_FX' => $payPv,
  358. $cacheDataKey => $payPv,
  359. ]);
  360. // 把该会员加入到能拿到业绩的会员缓存中
  361. CalcCache::addHasPerfUsers($data['USER_ID'], $this->_periodNum);
  362. // 给上追加业绩
  363. $this->loopNetworkParentDo($data['USER_ID'], function ($parent) use (&$data, $payPv) {
  364. // 给上级会员追加本期业绩到缓存中
  365. CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
  366. 'PV_' . $parent['LOCATION'] . 'L' => $payPv,
  367. 'PV_' . $parent['LOCATION'] . 'L_TOUCH' => $payPv,
  368. 'PV_' . $parent['LOCATION'] . 'L_FX' => $payPv,
  369. ]);
  370. // 把该会员加入到能拿到业绩的会员缓存中
  371. CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
  372. });
  373. //给推荐关系累计增加业绩
  374. $this->loopRelationParentDo($data['USER_ID'], function ($parent) use ($data, $payPv) {
  375. // 给上级会员追加本期业绩到缓存中
  376. CalcCache::nowPeriodPerf($parent['PARENT_UID'], $this->_periodNum, [
  377. 'PV_PSS' => $payPv,
  378. ]);
  379. // 把该会员加入到能拿到业绩的会员缓存中
  380. CalcCache::addHasPerfUsers($parent['PARENT_UID'], $this->_periodNum);
  381. });
  382. }
  383. }catch(Exception $e) {
  384. var_dump(__LINE__,__FILE__,$e->getMessage(), $data);
  385. }
  386. }
  387. return $this->loopGrandPerf($offset + $this->_limit);
  388. }
  389. unset($allData);
  390. return true;
  391. }
  392. /**
  393. * 计算月业绩表相关的数据并写入数据库
  394. * @param int $offset
  395. * @return bool
  396. * @throws Exception
  397. * @throws \yii\db\Exception
  398. */
  399. public function loopCalcMonthPerfTableData(int $offset = 0) {
  400. if (!$this->_isCalcMonth) {
  401. return true;
  402. }
  403. echo sprintf("时间:[%s]月业绩,当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
  404. $allData = PerfPeriod::findUseDbCalc()
  405. ->select('USER_ID, SUM(FX_AMOUNT_CASH) AS FX_AMOUNT_CASH_SUM,SUM(PV_PCS) AS PV_PCS_SUM,SUM(PV_PCS_FX) AS PV_PCS_FX_SUM,
  406. SUM(PV_PSS) AS PV_PSS_SUM,SUM(PV_1L) AS PV_1L_SUM,SUM(PV_2L) AS PV_2L_SUM,SUM(PV_3L) AS PV_3L_SUM,
  407. SUM(PV_4L) AS PV_4L_SUM,SUM(PV_5L) AS PV_5L_SUM,SUM(PV_1L_ZC) AS PV_1L_ZC_SUM,SUM(PV_2L_ZC) AS PV_2L_ZC_SUM,
  408. SUM(PV_3L_ZC) AS PV_3L_ZC_SUM,SUM(PV_4L_ZC) AS PV_4L_ZC_SUM,SUM(PV_5L_ZC) AS PV_5L_ZC_SUM')
  409. ->where('CALC_MONTH=:CALC_MONTH', [':CALC_MONTH' => $this->_calcYearMonth])
  410. ->groupBy('USER_ID')
  411. ->orderBy('USER_ID DESC')
  412. ->offset($offset)
  413. ->limit($this->_limit)
  414. ->asArray()
  415. ->all();
  416. if ($allData) {
  417. // 月度业绩表
  418. foreach ($allData as $everyData) {
  419. $userId = $everyData['USER_ID'];
  420. //往期业绩
  421. $userLastPerf = CalcCache::userPerf($userId, $this->_periodNum);
  422. //本期业绩
  423. $periodPerf = CalcCache::nowPeriodPerf($userId, $this->_periodNum);
  424. $userBaseInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
  425. $nowMonthPerf = [
  426. 'USER_ID' => $userId,
  427. 'FX_AMOUNT_CASH' => $everyData['FX_AMOUNT_CASH_SUM'],
  428. 'PV_PCS' => $everyData['PV_PCS_SUM'],
  429. 'PV_PCS_FX' => $everyData['PV_PCS_FX_SUM'],
  430. 'PV_PSS' => $everyData['PV_PSS_SUM'],
  431. 'PV_1L' => $everyData['PV_1L_SUM'],
  432. 'PV_2L' => $everyData['PV_2L_SUM'],
  433. 'PV_3L' => $everyData['PV_3L_SUM'],
  434. 'PV_4L' => $everyData['PV_4L_SUM'],
  435. 'PV_5L' => $everyData['PV_5L_SUM'],
  436. //总数据,历史+本期。不能用上月加本月,因为上月可能没业绩,上上个月有业绩。
  437. 'PV_1L_TOTAL' => $periodPerf['PV_1L'] + $userLastPerf['PV_1L'],
  438. 'PV_2L_TOTAL' => $periodPerf['PV_2L'] + $userLastPerf['PV_2L'],
  439. 'PV_3L_TOTAL' => $periodPerf['PV_3L'] + $userLastPerf['PV_3L'],
  440. 'PV_4L_TOTAL' => $periodPerf['PV_4L'] + $userLastPerf['PV_4L'],
  441. 'PV_5L_TOTAL' => $periodPerf['PV_5L'] + $userLastPerf['PV_5L'],
  442. 'PV_PSS_TOTAL' => $periodPerf['PV_PSS'] + $userLastPerf['PV_PSS_TOTAL'],
  443. ];
  444. // 把会员的月业绩写入缓存中,以便下面的奖金计算从缓冲中获取数据效率高
  445. CalcCache::addHasMonthPerfUsers($userId, $this->_periodNum);
  446. CalcCache::nowMonthPerf($userId, $this->_periodNum, $nowMonthPerf);
  447. unset($userId, $everyData, $nowMonthPerf, $lastMonthData, $userBaseInfo, $isVip);
  448. }
  449. unset($allData);
  450. $this->loopCalcMonthPerfTableData($offset + $this->_limit);
  451. }
  452. unset($allData);
  453. return true;
  454. }
  455. /**
  456. * 循环有业绩会员,并入库
  457. * @param int $offset
  458. * @return bool
  459. * @throws \yii\db\Exception
  460. */
  461. public function loopWriteNowPerf($offset = 0) {
  462. echo sprintf("时间:[%s]缓存本期业绩数据入库,当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
  463. // 从缓存列表里面从底层往上倒序获取会员
  464. $allData = CalcCache::getHasPerfUsers($this->_periodNum, $offset, $this->_limit);
  465. if($allData){
  466. $insertDataPeriodPerf = [];
  467. foreach($allData as $userId){
  468. $insertDataPeriodPerf[] = $this->nowPeriodPerfData($userId);
  469. unset($userId);
  470. }
  471. PerfPeriod::batchInsert($insertDataPeriodPerf);
  472. unset($insertDataPeriodPerf, $allData);
  473. return $this->loopWriteNowPerf($offset + $this->_limit);
  474. }
  475. unset($allData);
  476. return true;
  477. }
  478. /**
  479. * 循环有月业绩会员,并入库
  480. * @param int $offset
  481. * @return bool
  482. * @throws \yii\db\Exception
  483. */
  484. public function loopWriteMonthPerf($offset = 0) {
  485. if(!$this->_isCalcMonth){
  486. return true;
  487. }
  488. echo sprintf("时间:[%s]缓存本月业绩数据入库,当前offset为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()) , $offset);
  489. // 从缓存列表里面从底层往上倒序获取会员
  490. $allData = CalcCache::getHasMonthPerfUsers($this->_periodNum, $offset, $this->_limit);
  491. if($allData){
  492. $insertDataMonthPerf = [];
  493. foreach($allData as $userId){
  494. $insertDataMonthPerf[] = $this->nowMonthPerfData($userId);
  495. unset($userId);
  496. }
  497. PerfMonth::batchInsert($insertDataMonthPerf);
  498. unset($insertDataMonthPerf, $allData);
  499. return $this->loopWriteMonthPerf($offset + $this->_limit);
  500. }
  501. unset($allData);
  502. return true;
  503. }
  504. /**
  505. * 本期业绩数据
  506. * @param $userId
  507. * @return array
  508. */
  509. public function nowPeriodPerfData($userId){
  510. $data = CalcCache::nowPeriodPerf($userId, $this->_periodNum);
  511. $result = [
  512. 'ID' => SnowFake::instance()->generateId(),
  513. 'USER_ID' => $userId,
  514. 'FX_AMOUNT_CASH' => $data['FX_AMOUNT_CASH'],
  515. 'PV_PCS' => $data['PV_PCS'],
  516. 'PV_PSS' => $data['PV_PSS'],
  517. 'PV_PCS_ZC' => $data['PV_PCS_ZC'],
  518. 'PV_PCS_FX' => $data['PV_PCS_FX'],
  519. 'PV_PCS_FX_CASH' => $data['PV_PCS_FX_CASH'],
  520. 'PV_PCS_FX_POINT' => $data['PV_PCS_FX_POINT'],
  521. 'PV_1L' => $data['PV_1L'],
  522. 'PV_1L_TOUCH' => $data['PV_1L_TOUCH'],
  523. 'PV_1L_ZC' => $data['PV_1L_ZC'],
  524. 'PV_1L_FX' => $data['PV_1L_FX'],
  525. 'PV_2L' => $data['PV_2L'],
  526. 'PV_2L_TOUCH' => $data['PV_2L_TOUCH'],
  527. 'PV_2L_ZC' => $data['PV_2L_ZC'],
  528. 'PV_2L_FX' => $data['PV_2L_FX'],
  529. 'PV_3L' => $data['PV_3L'],
  530. 'PV_3L_TOUCH' => $data['PV_3L_TOUCH'],
  531. 'PV_3L_ZC' => $data['PV_3L_ZC'],
  532. 'PV_3L_FX' => $data['PV_3L_FX'],
  533. 'PV_4L' => $data['PV_4L'],
  534. 'PV_4L_TOUCH' => $data['PV_4L_TOUCH'],
  535. 'PV_4L_ZC' => $data['PV_4L_ZC'],
  536. 'PV_4L_FX' => $data['PV_4L_FX'],
  537. 'PV_5L' => $data['PV_5L'],
  538. 'PV_5L_TOUCH' => $data['PV_5L_TOUCH'],
  539. 'PV_5L_ZC' => $data['PV_5L_ZC'],
  540. 'PV_5L_FX' => $data['PV_5L_FX'],
  541. 'SURPLUS_1L' => $data['SURPLUS_1L'],
  542. 'SURPLUS_2L' => $data['SURPLUS_2L'],
  543. 'SURPLUS_3L' => $data['SURPLUS_3L'],
  544. 'SURPLUS_4L' => $data['SURPLUS_4L'],
  545. 'SURPLUS_5L' => $data['SURPLUS_5L'],
  546. 'PERIOD_NUM' => $this->_periodNum,
  547. 'CALC_MONTH' => $this->_calcYearMonth,
  548. 'CREATED_AT' => Date::nowTime(),
  549. ];
  550. unset($data);
  551. return $result;
  552. }
  553. /**
  554. * 本月业绩
  555. * @param $userId
  556. * @return array
  557. */
  558. public function nowMonthPerfData($userId){
  559. $data = CalcCache::nowMonthPerf($userId, $this->_periodNum);
  560. $result = [
  561. 'ID' => SnowFake::instance()->generateId(),
  562. 'USER_ID' => $userId,
  563. 'FX_AMOUNT_CASH' => $data['FX_AMOUNT_CASH'],
  564. 'PV_PCS' => $data['PV_PCS'],
  565. 'PV_PCS_FX' => $data['PV_PCS_FX'],
  566. 'PV_PSS' => $data['PV_PSS'],
  567. 'PV_1L' => $data['PV_1L'],
  568. 'PV_2L' => $data['PV_2L'],
  569. 'PV_3L' => $data['PV_3L'],
  570. 'PV_4L' => $data['PV_4L'],
  571. 'PV_5L' => $data['PV_5L'],
  572. 'PV_1L_TOTAL' => $data['PV_1L_TOTAL'],
  573. 'PV_2L_TOTAL' => $data['PV_2L_TOTAL'],
  574. 'PV_3L_TOTAL' => $data['PV_3L_TOTAL'],
  575. 'PV_4L_TOTAL' => $data['PV_4L_TOTAL'],
  576. 'PV_5L_TOTAL' => $data['PV_5L_TOTAL'],
  577. 'PV_PSS_TOTAL' => $data['PV_PSS_TOTAL'],
  578. 'CALC_MONTH' => $this->_calcYearMonth,
  579. 'CREATED_AT' => Date::nowTime(),
  580. ];
  581. unset($data);
  582. return $result;
  583. }
  584. /**
  585. * 循环父级并执行回调函数
  586. * @param $userId
  587. * @param callable $callbackFunc
  588. * @param int $offset
  589. * @return bool
  590. */
  591. public function loopNetworkParentDo($userId, callable $callbackFunc, int $offset = 0) {
  592. $allParents = Cache::getAllNetworkParents($userId, true);
  593. $allData = array_slice($allParents, $offset, $this->_limit);
  594. unset($allParents);
  595. if ($allData) {
  596. foreach ($allData as $data) {
  597. $funcResult = $callbackFunc($data);
  598. if ($funcResult === self::LOOP_FINISH) {
  599. return true;
  600. } elseif ($funcResult === self::LOOP_CONTINUE) {
  601. continue;
  602. }
  603. unset($data, $funcResult);
  604. }
  605. unset($allData);
  606. return $this->loopNetworkParentDo($userId, $callbackFunc, $offset + $this->_limit);
  607. }
  608. return true;
  609. }
  610. /**
  611. * 循环推荐网络的父级
  612. * @param $userId
  613. * @param callable $callbackFunc
  614. * @param int $offset
  615. * @return bool
  616. */
  617. public function loopRelationParentDo($userId, callable $callbackFunc, int $offset = 0) {
  618. $allParents = Cache::getAllRelationParents($userId,true);
  619. $allData = array_slice($allParents, $offset, $this->_limit);
  620. unset($allParents);
  621. if ($allData) {
  622. foreach ($allData as $data) {
  623. $funcResult = $callbackFunc($data);
  624. if ($funcResult === self::LOOP_FINISH) {
  625. return true;
  626. } elseif ($funcResult === self::LOOP_CONTINUE) {
  627. continue;
  628. }
  629. unset($data, $funcResult);
  630. }
  631. unset($allData);
  632. return $this->loopRelationParentDo($userId, $callbackFunc, $offset + $this->_limit);
  633. }
  634. return true;
  635. }
  636. /**
  637. * 更新百分比并发送
  638. * @param $percent
  639. */
  640. private function _updatePercent($percent) {
  641. // 把数据写入数据库中
  642. Period::updateAll(['PERF_PERCENT' => $percent], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  643. }
  644. }