BonusSend.php 48 KB

1234567891011121314151617181920212223242526272829303132333435363738394041424344454647484950515253545556575859606162636465666768697071727374757677787980818283848586878889909192939495969798991001011021031041051061071081091101111121131141151161171181191201211221231241251261271281291301311321331341351361371381391401411421431441451461471481491501511521531541551561571581591601611621631641651661671681691701711721731741751761771781791801811821831841851861871881891901911921931941951961971981992002012022032042052062072082092102112122132142152162172182192202212222232242252262272282292302312322332342352362372382392402412422432442452462472482492502512522532542552562572582592602612622632642652662672682692702712722732742752762772782792802812822832842852862872882892902912922932942952962972982993003013023033043053063073083093103113123133143153163173183193203213223233243253263273283293303313323333343353363373383393403413423433443453463473483493503513523533543553563573583593603613623633643653663673683693703713723733743753763773783793803813823833843853863873883893903913923933943953963973983994004014024034044054064074084094104114124134144154164174184194204214224234244254264274284294304314324334344354364374384394404414424434444454464474484494504514524534544554564574584594604614624634644654664674684694704714724734744754764774784794804814824834844854864874884894904914924934944954964974984995005015025035045055065075085095105115125135145155165175185195205215225235245255265275285295305315325335345355365375385395405415425435445455465475485495505515525535545555565575585595605615625635645655665675685695705715725735745755765775785795805815825835845855865875885895905915925935945955965975985996006016026036046056066076086096106116126136146156166176186196206216226236246256266276286296306316326336346356366376386396406416426436446456466476486496506516526536546556566576586596606616626636646656666676686696706716726736746756766776786796806816826836846856866876886896906916926936946956966976986997007017027037047057067077087097107117127137147157167177187197207217227237247257267277287297307317327337347357367377387397407417427437447457467477487497507517527537547557567577587597607617627637647657667677687697707717727737747757767777787797807817827837847857867877887897907917927937947957967977987998008018028038048058068078088098108118128138148158168178188198208218228238248258268278288298308318328338348358368378388398408418428438448458468478488498508518528538548558568578588598608618628638648658668678688698708718728738748758768778788798808818828838848858868878888898908918928938948958968978988999009019029039049059069079089099109119129139149159169179189199209219229239249259269279289299309319329339349359369379389399409419429439449459469479489499509519529539549559569579589599609619629639649659669679689699709719729739749759769779789799809819829839849859869879889899909919929939949959969979989991000100110021003100410051006100710081009101010111012101310141015101610171018101910201021102210231024102510261027102810291030103110321033103410351036103710381039104010411042104310441045104610471048104910501051105210531054105510561057105810591060106110621063106410651066106710681069107010711072107310741075107610771078
  1. <?php
  2. /**
  3. * Created by PhpStorm.
  4. * User: leo
  5. * Date: 2018/3/18
  6. * Time: 上午11:06
  7. */
  8. namespace common\helpers\bonus;
  9. use common\components\ActiveRecord;
  10. use common\helpers\DataBak;
  11. use common\helpers\Form;
  12. use common\helpers\Tool;
  13. use common\helpers\user\Balance;
  14. use common\helpers\user\Info;
  15. use common\helpers\user\Reconsume;
  16. use common\helpers\user\Status;
  17. use common\libs\api\sms\SmsApi;
  18. use common\libs\swoole\Process;
  19. use common\models\DealType;
  20. use common\models\FlowRemainPv;
  21. use common\models\PerfPeriod;
  22. use common\models\DecOrder;
  23. use common\models\EmployLevel;
  24. use common\models\UserBonus;
  25. use common\models\UserPerfMonthUpdate;
  26. use common\models\UserPeriodPoints;
  27. use common\models\UserWallet;
  28. use common\models\UserInfo;
  29. use common\models\UserPerf;
  30. use common\models\UserPerfUpdate;
  31. use common\models\UserTeamwork;
  32. use common\models\YearHighestEmpLv;
  33. use common\models\Order;
  34. use common\models\RemainPv;
  35. use yii\base\BaseObject;
  36. use yii\base\StaticInstanceTrait;
  37. use common\helpers\Cache;
  38. use common\helpers\Date;
  39. use common\helpers\user\Cash;
  40. use common\models\CalcBonus;
  41. use common\models\CalcBonusBD;
  42. use common\models\CalcBonusBS;
  43. use common\models\CalcBonusGX;
  44. use common\models\CalcBonusQY;
  45. use common\models\CalcBonusTG;
  46. use common\models\FlowBonus;
  47. use common\models\PerfActiveUser;
  48. use common\models\PerfMonth;
  49. use common\models\User;
  50. use Yii;
  51. use common\models\Period;
  52. use common\models\Transfer;
  53. use yii\base\Exception;
  54. use yii\db\Expression;
  55. class BonusSend extends BaseObject {
  56. use StaticInstanceTrait;
  57. private $_limit = 1000;
  58. private $_appUserId = null;
  59. private $_sysConfig = [];
  60. private $_decLevelConfig = [];
  61. private $_empLevelConfig = [];
  62. private $_decRoleConfig = [];
  63. private $_errors = [];
  64. private $_periodNum = 0;
  65. private $_periodId;
  66. private $_isCalcMonth = 0;
  67. private $_isCalcYear = 0;
  68. private $_calcYear;
  69. private $_calcMonth;
  70. private $_calcYearMonth;
  71. private $_lastCalcYear;
  72. private $_lastCalcMonth;
  73. private $_lastCalcYearMonth;
  74. private $_workerId;
  75. private $_workerNum;
  76. public function init(int $periodNum = 0, $appUserId = null, $workerId = null, $workerNum = null) {
  77. parent::init();
  78. $this->_sysConfig = Cache::getSystemConfig();
  79. $this->_decLevelConfig = Cache::getDecLevelConfig();
  80. $this->_empLevelConfig = Cache::getEmpLevelConfig();
  81. $this->_decRoleConfig = CalcCache::getDecRoleConfig($this->_periodNum);
  82. $this->_periodNum = $periodNum;
  83. $this->_appUserId = $appUserId;
  84. $this->_workerId = $workerId;
  85. $this->_workerNum = $workerNum;
  86. }
  87. /**
  88. * 设置期数
  89. * @param int $periodNum
  90. * @return int
  91. */
  92. public function setPeriodNum(int $periodNum) {
  93. return $this->_periodNum = $periodNum;
  94. }
  95. /**
  96. * 获取期数
  97. * @return int
  98. */
  99. public function getPeriodNum() {
  100. return $this->_periodNum;
  101. }
  102. /**
  103. * 加入错误错误
  104. * @param $attr
  105. * @param $error
  106. */
  107. public function addError($attr, $error) {
  108. $this->_errors[$attr][] = $error;
  109. }
  110. /**
  111. * 获取错误信息
  112. * @return array
  113. */
  114. public function getErrors() {
  115. return $this->_errors;
  116. }
  117. /**
  118. * 挂网时处理虚假订单
  119. *
  120. */
  121. public function putFakeOrder() {
  122. echo('开始处理-假订单' . PHP_EOL);
  123. $sysConfig = Cache::getSystemConfig();
  124. $mesureUpCondition = $sysConfig['monthPcsPvFxCondition']['VALUE']; // 月达标条件 NC默认300
  125. $fakeOrder= Order::find()->where(['PERIOD_NUM'=>$this->_periodNum, 'IS_AUTO'=>'1'])->asArray()->all();
  126. // print_r($fakeOrder);exit;
  127. foreach($fakeOrder as $fOrder){
  128. $oRemainPv=RemainPv::findOne(["USER_ID"=>$fOrder['USER_ID']]);
  129. $transactionRemain = \Yii::$app->db->beginTransaction();
  130. try{
  131. $flowRemainPvModel = new FlowRemainPv();
  132. $flowRemainPvModel->ID = $this->_generateSn();
  133. $flowRemainPvModel->USER_ID = $fOrder['USER_ID'];
  134. $flowRemainPvModel->REMAIN_PV_FLOW = 0 - $mesureUpCondition;
  135. $flowRemainPvModel->REMAIN_PV_TOTAL = $oRemainPv->REMAIN_PV - $mesureUpCondition;
  136. $flowRemainPvModel->PERIOD_NUM = $this->_periodNum;
  137. $flowRemainPvModel->UPDATED_AT = Date::nowTime();
  138. $flowRemainPvModel->ORDER_SN = $fOrder['SN'];
  139. if(!$flowRemainPvModel->save()){
  140. $this->addErrors($flowRemainPvModel->getErrors());
  141. return false;
  142. }
  143. $oRemainPv->updateCounters(['REMAIN_PV'=> 0 - $mesureUpCondition]);
  144. $transactionRemain->commit();
  145. } catch (Exception $e) {
  146. $transactionRemain->rollBack();
  147. $this->addError('add', $e->getMessage());
  148. return null;
  149. }
  150. }
  151. echo('假订单处理完' . PHP_EOL);
  152. return true; // $flowRemainPvModel;
  153. }
  154. /**
  155. * 生成流水号
  156. * @return string
  157. */
  158. private function _generateSn() {
  159. return Date::today('Ymd') . $this->_random(10, 1);
  160. }
  161. /**
  162. * 生成随机数
  163. * @param $length
  164. * @param int $numeric
  165. * @return string
  166. */
  167. private function _random($length, $numeric = 0) {
  168. $seed = base_convert(md5(microtime() . $_SERVER['DOCUMENT_ROOT']), 16, $numeric ? 10 : 35);
  169. $seed = $numeric ? (str_replace('0', '', $seed) . '012340567890') : ($seed . 'zZ' . strtoupper($seed));
  170. $hash = '';
  171. $max = strlen($seed) - 1;
  172. for ($i = 0; $i < $length; $i++) {
  173. $hash .= $seed[mt_rand(0, $max)];
  174. }
  175. return $hash;
  176. }
  177. /**
  178. * 进行奖金发放步骤
  179. * @return bool
  180. */
  181. public function sendStep() {
  182. try {
  183. $t1 = microtime(true);
  184. // 初始化
  185. $this->initTask();
  186. echo('挂网开始');
  187. $this->putFakeOrder();
  188. // 先把有remainPv的订单处理一下,将remainPv加入到remain_pv及流水表
  189. echo('处理当期REMAIN PV ' . date('Y-m-d H:i:s', time()) . PHP_EOL);
  190. $this->_calcRemainPv();
  191. $t2 = microtime(true);
  192. echo('初始化完成,当前期数【' . $this->_periodNum . '】,耗时:' . round($t2 - $t1, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  193. // 改变状态
  194. $this->setSendStatus('start');
  195. $t3 = microtime(true);
  196. echo('改变状态完成,耗时:' . round($t3 - $t2, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  197. $this->_updatePercent(20);
  198. //Yii::$app->db->close();
  199. //Yii::$app->dbShop->close();
  200. // 更新聘级
  201. $this->updateEmpLevel();
  202. $this->_updatePercent(40);
  203. $t4 = microtime(true);
  204. echo('更新聘级完成,耗时:' . round($t4 - $t3, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  205. // 发放奖金
  206. $this->sendBonusLoop();
  207. $this->_updatePercent(60);
  208. $t5 = microtime(true);
  209. echo('发放奖金完成,耗时:' . round($t5 - $t4, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  210. // 更新会员上次报单级别
  211. // $this->updateUserDevLv();
  212. // $this->_updatePercent(80);
  213. $t6 = microtime(true);
  214. // echo('更新会员上次报单级别完成,耗时:' . round($t6 - $t5, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  215. // 更新会员累计业绩
  216. $this->updateUserPerf();
  217. $this->_updatePercent(80);
  218. $t7 = microtime(true);
  219. echo('更新会员累计业绩完成,耗时:' . round($t7 - $t6, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  220. $this->updateUserPerfMonth();
  221. $this->_updatePercent(90);
  222. $t8 = microtime(true);
  223. echo('更新会员累计月业绩完成,耗时:' . round($t8 - $t7, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  224. // 更新活跃用户状态,更新为已处理
  225. // $this->updateActiveUser();
  226. // $this->_updatePercent(95);
  227. // $t9 = microtime(true);
  228. // echo('更新会员累计月业绩完成,耗时:' . round($t9 - $t8, 3) . ',内存使用:' . (round(memory_get_usage() / 1024 / 1024, 3)) . 'MB' . PHP_EOL);
  229. // 开启子进程去完成下面的循环发放和循环改聘级和循环更新累计业绩
  230. /*$process = new Process('sendBonus', 3);
  231. $process->run(function($workId, $pmid){
  232. $this->processStep($workId);
  233. });
  234. while (true){
  235. if($process->isFinish()) break;
  236. }
  237. unset($process);
  238. $this->_updatePercent(90);
  239. $t4 = microtime(true);
  240. echo('所有子进程的任务完成,耗时:'.round($t4 - $t3, 3).',内存使用:'.(round(memory_get_usage()/1024/1024, 3)).'MB'.PHP_EOL);*/
  241. echo('全部奖金发放完成,耗时:'.round($t7 - $t1, 3).',内存使用:'.(round(memory_get_usage()/1024/1024, 3)).'MB'.PHP_EOL);
  242. $this->_updatePercent(100);
  243. } catch (\Exception $e) {
  244. $this->addError('sendBonus', $e->getMessage());
  245. return false;
  246. }
  247. if (count($this->_errors) > 0) {
  248. return false;
  249. }
  250. return true;
  251. }
  252. /**
  253. * 处理order表中有remain_pv的订单
  254. * 将结果写入到remainPv相关表中
  255. *
  256. */
  257. private function _calcRemainPv(){
  258. $orders = Order::find()->where('PERIOD_NUM=:PERIOD_NUM AND REMAIN_PV>0 AND IS_DELETE=0',[':PERIOD_NUM'=>$this->_periodNum])->asArray()->all();
  259. foreach($orders as $order){
  260. $oRemainPv = RemainPv::find()->where(['USER_ID' => $order['USER_ID']])->one();
  261. $transactionRemain = \Yii::$app->db->beginTransaction();
  262. try{
  263. $flowRemainPvModel = new FlowRemainPv();
  264. $flowRemainPvModel->ID = $this->_generateSn();
  265. $flowRemainPvModel->USER_ID = $order['USER_ID'];
  266. $flowRemainPvModel->REMAIN_PV_FLOW = $order['REMAIN_PV'];
  267. $flowRemainPvModel->REMAIN_PV_TOTAL = $oRemainPv['REMAIN_PV'] + $order['REMAIN_PV'];
  268. $flowRemainPvModel->PERIOD_NUM = $this->_periodNum;
  269. $flowRemainPvModel->UPDATED_AT = Date::nowTime();
  270. $flowRemainPvModel->ORDER_SN = $order['SN'];
  271. if(!$flowRemainPvModel->save()){
  272. $this->addErrors($flowRemainPvModel->getErrors());
  273. return false;
  274. }
  275. $oRemainPv = RemainPv::find()->where(['USER_ID' => $order['USER_ID']])->one();
  276. if($oRemainPv){
  277. $oRemainPv->updateCounters(['REMAIN_PV'=>$order['REMAIN_PV']]);
  278. }else{
  279. $remainPvModel = new RemainPv();
  280. $remainPvModel->ID = $this->_generateSn();
  281. $remainPvModel->USER_ID = $order['USER_ID'];
  282. $remainPvModel->UPDATED_AT = Date::nowTime();
  283. $remainPvModel->REMAIN_PV = $order['REMAIN_PV'];
  284. $remainPvModel->STATUS = 1;
  285. if(!$remainPvModel->save()){
  286. $this->addErrors($remainPvModel->getErrors());
  287. return false;
  288. }
  289. }
  290. $transactionRemain->commit();
  291. } catch (Exception $e) {
  292. $transactionRemain->rollBack();
  293. $this->addError('add', $e->getMessage());
  294. return null;
  295. }
  296. }
  297. return null;
  298. }
  299. /**
  300. * 需要多进程执行的任务
  301. * @param $workId
  302. * @throws \yii\db\Exception
  303. */
  304. public function processStep($workId = null) {
  305. if ($workId == 1 || $workId === null) {
  306. // 发放奖金
  307. $this->sendBonusLoop();
  308. }
  309. if ($workId == 2 || $workId === null) {
  310. // 更新聘级
  311. $this->updateEmpLevel();
  312. }
  313. if ($workId == 3 || $workId === null) {
  314. // 更新会员累计业绩
  315. $this->updateUserPerf();
  316. }
  317. Yii::$app->db->close();
  318. Yii::$app->dbShop->close();
  319. }
  320. /**
  321. * 初始化发放任务
  322. * @throws Exception
  323. */
  324. public function initTask() {
  325. $this->_errors = [];
  326. $periodNum = $this->_periodNum;
  327. // 获取传入期数的相关信息
  328. $periodObj = Period::instance();
  329. $periodDataArr = $periodObj->setPeriodNum($periodNum);
  330. $this->_periodId = $periodDataArr['ID'];
  331. $this->_isCalcMonth = $periodObj->isCalcMonth($periodNum);
  332. $this->_calcYear = $periodObj->getYear($periodNum);
  333. $this->_calcMonth = $periodObj->getMonth($periodNum);
  334. $this->_calcYearMonth = $periodObj->getYearMonth($periodNum);
  335. $lastYearMonthArr = $periodObj->getLastMonth($periodNum);
  336. $this->_lastCalcYear = $lastYearMonthArr['year'];
  337. $this->_lastCalcMonth = $lastYearMonthArr['month'];
  338. $this->_lastCalcYearMonth = $lastYearMonthArr['yearMonth'];
  339. }
  340. /**
  341. * 设置结算状态
  342. * @param $type
  343. * start|end|fail
  344. */
  345. public function setSendStatus($type) {
  346. Yii::$app->db->close();
  347. if ($type == 'start') {
  348. Period::updateAll(['IS_SENDING' => 1, 'SEND_STARTED_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  349. } elseif ($type == 'end') {
  350. Period::updateAll(['IS_SENDING' => 0, 'IS_SENT' => Period::SEND_FINISH, 'SENT_AT' => Date::nowTime()], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  351. } elseif ($type == 'fail') {
  352. Period::updateAll(['IS_SENDING' => 0, 'IS_SENT' => Period::SEND_FAIL, 'SENT_AT' => 0], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  353. }
  354. }
  355. /**
  356. * 结束计算任务
  357. * @throws \yii\db\Exception
  358. */
  359. public function endTask() {
  360. CalcCache::clearAll($this->_periodNum);
  361. $this->setSendStatus('end');
  362. //@todo 先不备份数据
  363. // DataBak::backup($this->_periodNum);
  364. //发送复销短信
  365. // if ($this->_isCalcMonth && $this->_sysConfig['smsOpen']['VALUE']) {
  366. // $this->sendSmsLoop();
  367. // }
  368. }
  369. /**
  370. * 出现错误
  371. */
  372. public function errorTask() {
  373. $this->setSendStatus('fail');
  374. }
  375. /**
  376. * 发放奖金
  377. * @param int $page
  378. * @return bool
  379. * @throws \yii\db\Exception
  380. */
  381. public function sendBonusLoop($page=1) {
  382. echo sprintf("时间:[%s]数据库发奖,当前page为:【%s】" . PHP_EOL, date('Y-m-d H:i:s', time()), $page);
  383. $periodNum = $this->_periodNum;
  384. // 从奖金结算表中获取当期未发放的所有数据
  385. $allData = CalcBonus::findUseDbCalc()
  386. ->yearMonth($this->_calcYearMonth)
  387. ->where(
  388. '(IS_SENT=0 OR IS_SENT=2) AND CALC_MONTH=:CALC_MONTH AND PERIOD_NUM=:PERIOD_NUM',
  389. [':CALC_MONTH' => $this->_calcYearMonth, ':PERIOD_NUM' => $periodNum]
  390. )
  391. ->limit($this->_limit)
  392. ->asArray()
  393. ->all();
  394. if ($allData) {
  395. $transaction = Yii::$app->db->beginTransaction();
  396. try {
  397. foreach ($allData as $key => $data) {
  398. // 期奖金
  399. // $periodAmount = $data['BONUS_QY'] + $data['BONUS_YC'] + $data['BONUS_XF'] + $data['BONUS_BD'] + $data['BONUS_TG'] + $data['BONUS_YJ'] + $data['BONUS_GX'] + $data['BONUS_GL'];
  400. $periodAmount = $data['BONUS_REAL'];
  401. // 获取本期结算的管理员
  402. // $period = Period::findOneAsArray(['PERIOD_NUM'=>$periodNum]);
  403. // $updateAminId = $period['CALC_ADMIN_ID'];
  404. if ($periodAmount > 0) {
  405. Balance::changeUserBonus($data['USER_ID'], 'bonus', $periodAmount, [
  406. 'CALC_ID' => $data['ID'],
  407. 'REMARK' => 'From ' . $periodNum . '期',
  408. 'PERIOD_NUM' => $periodNum,
  409. 'QY' => $data['BONUS_QY'],
  410. 'FW' => $data['BONUS_FW'],
  411. 'YC' => $data['BONUS_YC'],
  412. 'VIP' => $data['BONUS_VIP'],
  413. 'BD' => $data['BONUS_BD'],
  414. 'TG' => $data['BONUS_TG'],
  415. 'YJ' => $data['BONUS_YJ'],
  416. 'GX' => $data['REAL_BONUS_GX'],
  417. 'GL' => $data['BONUS_GL'],
  418. 'BS' => $data['BONUS_BS'],
  419. 'ST' => $data['BONUS_ST'],
  420. 'ORI_QY' => $data['ORI_BONUS_QY'],
  421. 'ORI_YC' => $data['ORI_BONUS_YC'],
  422. 'ORI_VIP' => $data['ORI_BONUS_VIP'],
  423. 'ORI_STANDARD' => $data['ORI_BONUS_STANDARD'],
  424. 'ORI_BD' => $data['ORI_BONUS_BD'],
  425. 'ORI_TG' => $data['ORI_BONUS_TG'],
  426. 'ORI_YJ' => $data['ORI_BONUS_YJ'],
  427. 'ORI_GX' => $data['ORI_BONUS_GX'],
  428. 'ORI_GL' => $data['ORI_BONUS_GL'],
  429. 'ORI_BS' => $data['ORI_BONUS_BS'],
  430. 'ORI_ST' => $data['ORI_BONUS_ST'],
  431. //'RECONSUME_POINTS_TOTAL' => $data['RECONSUME_POINTS'], 2022/05/17 复消积分,直接发放到余额账户
  432. 'RECONSUME_POINTS_TOTAL' => $data['RECONSUME_POINTS'],
  433. 'EXCHANGE_POINTS_TOTAL' => $data['EXCHANGE_POINTS'],
  434. 'MANAGE_TAX' => $data['MANAGE_TAX'],
  435. 'BONUS_TOTAL' => $data['BONUS_TOTAL'],
  436. 'DEAL_TYPE_ID' => DealType::BONUS_SEND,
  437. 'SORT' => $key * 10,
  438. ]);
  439. // $this->_teamworkBonus($data['USER_ID'], $periodAmount, $key);
  440. }
  441. //发放重消积分
  442. if ($data['RECONSUME_POINTS'] > 0) {
  443. Balance::changeUserBonus($data['USER_ID'], 'reconsume_points', $data['RECONSUME_POINTS'], [
  444. 'CALC_ID' => $data['ID'],
  445. 'REMARK' => 'From ' . $periodNum . '期',
  446. 'PERIOD_NUM' => $periodNum,
  447. 'RECONSUME_POINTS' => $data['RECONSUME_POINTS'],
  448. 'DEAL_TYPE_ID' => DealType::RECONSUME_POINTS_SEND,
  449. ]);
  450. // 2022/05/17 复消积分,直接发放到余额账户
  451. // Cash::changeUserCash(
  452. // $data['USER_ID'],
  453. // 'CASH',
  454. // abs($data['RECONSUME_POINTS']),
  455. // [
  456. // 'TRANSFER_SN' => Transfer::generateSN(),
  457. // 'DEAL_TYPE_ID' => DealType::BONUS_SEND,
  458. // 'REMARK' => '复销点数发放'
  459. // ]
  460. // );
  461. }
  462. //发放兑换积分
  463. if ($data['EXCHANGE_POINTS'] > 0) {
  464. Balance::changeUserBonus($data['USER_ID'], 'exchange_points', $data['EXCHANGE_POINTS'], [
  465. 'CALC_ID' => $data['ID'],
  466. 'REMARK' => 'From ' . $periodNum . '期',
  467. 'PERIOD_NUM' => $periodNum,
  468. 'EXCHANGE_POINTS' => $data['EXCHANGE_POINTS'],
  469. 'DEAL_TYPE_ID' => DealType::EXCHANGE_POINTS_SEND,
  470. ]);
  471. }
  472. // 把记录标记为已发放状态
  473. CalcBonus::updateAll(['IS_SENT' => 1, 'SENT_AT' => Date::nowTime()], 'ID=:ID', [':ID' => $data['ID']]);
  474. unset($periodAmount, $key, $data);
  475. }
  476. $transaction->commit();
  477. } catch (Exception $e) {
  478. $transaction->rollBack();
  479. $this->addError('sendBonus', '奖金发放失败,原因:' . $e->getMessage());
  480. return false;
  481. }
  482. unset($allData, $transaction);
  483. $page++;
  484. return $this->sendBonusLoop($page);
  485. }
  486. unset($allData);
  487. return true;
  488. }
  489. /**
  490. * 蓝星奖金(即新的管理奖),更新会员聘级
  491. * @param int $offset
  492. * @return bool
  493. * @throws \yii\db\Exception
  494. */
  495. public function updateEmpLevel(int $offset = 0) {
  496. if ($this->_isCalcMonth) {
  497. $empLv = EmployLevel::getIdConvertLevelSortCache();
  498. $allData = CalcBonusBS::findUseDbCalc()
  499. ->yearMonth($this->_calcYearMonth)
  500. ->where(
  501. 'CALC_MONTH=:CALC_MONTH AND PERIOD_NUM=:PERIOD_NUM',
  502. [
  503. ':CALC_MONTH' => $this->_calcYearMonth,
  504. ':PERIOD_NUM' =>$this->_periodNum
  505. ]
  506. )
  507. ->orderBy('CREATED_AT DESC')
  508. ->groupBy('USER_ID')
  509. ->offset($offset)
  510. ->limit($this->_limit)
  511. ->all();
  512. //@todo 用户级别不变则不更新
  513. $defaultEmpLv = EmployLevel::getDefaultLevelId();
  514. if ($allData) {
  515. $transaction = Yii::$app->db->beginTransaction();
  516. try {
  517. foreach ($allData as $data) {
  518. //@todo 用户级别不变则不更新
  519. if( $data['LEVEL_ID'] === $defaultEmpLv ) continue;
  520. $nowBsEmpLv = $data['LEVEL_ID']; // 当前蓝星奖计算(即管理奖) 的等级
  521. $user = CalcCache::getUserInfo($data['USER_ID'], $this->_periodNum);
  522. $userEmpLv = $user['EMP_LV']; // 用户的历史最高聘级
  523. $userEmpLvSort = $empLv[$userEmpLv]; // 历史最高聘级的 级别值
  524. $nowBsEmpLvSort = $empLv[$nowBsEmpLv]; // 当前蓝星计算的聘级 级别值
  525. if ($nowBsEmpLvSort > $userEmpLvSort) {
  526. // 如果当前期的级别值大于历史最高级别,则更新用户表里的最高聘级
  527. User::updateAll(['EMP_LV' => $data['LEVEL_ID']], 'ID=:USER_ID', [':USER_ID' => $data['USER_ID']]);
  528. User::deleteBaseInfoFromRedis($data['USER_ID']);
  529. }
  530. // 更新最新级别
  531. User::updateAll([
  532. 'LAST_EMP_LV' => $nowBsEmpLv,
  533. 'LAST_EMP_LV_UPDATED_AT' => time(),
  534. 'LAST_EMP_LV_UPDATED_PERIOD' => $this->_periodNum
  535. ], 'ID=:USER_ID', [':USER_ID' => $data['USER_ID']]);
  536. User::deleteBaseInfoFromRedis($data['USER_ID']);
  537. unset($data);
  538. }
  539. $transaction->commit();
  540. } catch (Exception $e) {
  541. $transaction->rollBack();
  542. $this->addError('updateEmpLevel', '更新聘级失败,原因:' . $e->getMessage());
  543. return false;
  544. }
  545. unset($transaction, $allData, $defaultEmpLv);
  546. return $this->updateEmpLevel($offset + $this->_limit);
  547. }
  548. // 刷新会员EmpLv为0
  549. User::updateAll([
  550. 'LAST_EMP_LV' => '',
  551. 'LAST_EMP_LV_UPDATED_AT' => time(),
  552. 'LAST_EMP_LV_UPDATED_PERIOD' => $this->_periodNum,
  553. ], 'LAST_EMP_LV_UPDATED_PERIOD < :PERIOD_NUM AND LAST_EMP_LV <> ""', [':PERIOD_NUM' => $this->_periodNum]);
  554. User::deleteAllBaseInfoFromRedis();
  555. unset($allData);
  556. }
  557. // 刷新会员EmpLv为0
  558. User::updateAll([
  559. 'LAST_EMP_LV' => '',
  560. 'LAST_EMP_LV_UPDATED_AT' => time(),
  561. 'LAST_EMP_LV_UPDATED_PERIOD' => $this->_periodNum,
  562. ], 'LAST_EMP_LV_UPDATED_PERIOD < :PERIOD_NUM AND LAST_EMP_LV <> ""', [':PERIOD_NUM' => $this->_periodNum]);
  563. User::deleteAllBaseInfoFromRedis();
  564. return true;
  565. }
  566. // /**
  567. // * 更新会员聘级
  568. // * @param int $offset
  569. // * @return bool
  570. // * @throws \yii\db\Exception
  571. // */
  572. // public function updateEmpLevel(int $offset = 0) {
  573. // if ($this->_isCalcMonth) {
  574. // $allData = PerfMonth::findUseDbCalc()->yearMonth($this->_calcYearMonth)->where('CALC_MONTH=:CALC_MONTH', [':CALC_MONTH' => $this->_calcYearMonth])->offset($offset)->limit($this->_limit)->all();
  575. // //@todo 用户级别不变则不更新
  576. // $defaultEmpLv = EmployLevel::getDefaultLevelId();
  577. // if ($allData) {
  578. // $transaction = Yii::$app->db->beginTransaction();
  579. // try {
  580. // foreach ($allData as $data) {
  581. // //@todo 用户级别不变则不更新
  582. // if( $data['LAST_EMP_LV'] === $defaultEmpLv ) continue;
  583. // User::updateAll(['EMP_LV' => $data['LAST_EMP_LV']], 'ID=:USER_ID', [':USER_ID' => $data['USER_ID']]);
  584. // User::deleteBaseInfoFromRedis($data['USER_ID']);
  585. // unset($data);
  586. // }
  587. // $transaction->commit();
  588. // } catch (Exception $e) {
  589. // $transaction->rollBack();
  590. // $this->addError('updateEmpLevel', '更新聘级失败,原因:' . $e->getMessage());
  591. // return false;
  592. // }
  593. // unset($transaction, $allData, $defaultEmpLv);
  594. // return $this->updateEmpLevel($offset + $this->_limit);
  595. // }
  596. // unset($allData);
  597. // }
  598. // return true;
  599. // }
  600. // 更活跃会员,将is_send改成1
  601. public function updateActiveUser() {
  602. try {
  603. $ret = PerfActiveUser::updateAll(
  604. ['IS_SENT' => 1],
  605. 'PERIOD_NUM=:PERIOD_NUM AND IS_SENT=:IS_SENT',
  606. ['IS_SENT'=>0, 'PERIOD_NUM'=>$this->_periodNum]
  607. );
  608. return $ret;
  609. } catch(Exception $e) {
  610. $this->addError('updateActiveUser', '更新活跃会员业绩期处理状态失败,原因:' . $e->getMessage());
  611. return false;
  612. }
  613. }
  614. /**
  615. * 更新会员的累计业绩
  616. * @param int $offset
  617. * @return bool
  618. * @throws \yii\db\Exception
  619. */
  620. public function updateUserPerf(int $offset = 0) {
  621. $allData = PerfPeriod::findUseDbCalc()->yearMonth($this->_calcYearMonth)->where('PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum])->orderBy('ID ASC')->offset($offset)->limit($this->_limit)->all();
  622. if ($allData) {
  623. $transaction = Yii::$app->db->beginTransaction();
  624. try {
  625. foreach ($allData as $data) {
  626. $isUpdate = false;
  627. if (UserPerf::findUseDbCalc()->where('USER_ID=:USER_ID', [':USER_ID' => $data['USER_ID']])->exists()) {
  628. // 判断本期是否已经更新过业绩
  629. if (!UserPerfUpdate::findUseDbCalc()->yearMonth($this->_calcYearMonth)->where('USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM', [':USER_ID' => $data['USER_ID'], ':PERIOD_NUM' => $this->_periodNum])->exists()) {
  630. $isUpdate = true;
  631. // 更新业绩
  632. UserPerf::updateAll([
  633. 'PV_PCS_ZC' => new Expression('PV_PCS_ZC+' . $data['PV_PCS_ZC']),
  634. 'PV_PCS_YH' => new Expression('PV_PCS_YH+' . $data['PV_PCS_YH']),
  635. 'PV_PCS_ZG' => new Expression('PV_PCS_ZG+' . $data['PV_PCS_ZG']),
  636. 'PV_PCS_LS' => new Expression('PV_PCS_LS+' . $data['PV_PCS_LS']),
  637. 'PV_PCS_FX' => new Expression('PV_PCS_FX+' . $data['PV_PCS_FX']),
  638. 'PV_PSS' => new Expression('PV_PSS+' . $data['PV_PSS']),
  639. 'PV_PSS_TOTAL' => new Expression('PV_PSS_TOTAL+' . $data['PV_PSS']),
  640. 'PV_1L' => new Expression('PV_1L+' . $data['PV_1L']),
  641. 'PV_2L' => new Expression('PV_2L+' . $data['PV_2L']),
  642. 'PV_3L' => new Expression('PV_3L+' . $data['PV_3L']),
  643. 'PV_4L' => new Expression('PV_4L+' . $data['PV_4L']),
  644. 'PV_5L' => new Expression('PV_5L+' . $data['PV_5L']),
  645. 'SURPLUS_1L' => $data['SURPLUS_1L'],
  646. 'SURPLUS_2L' => $data['SURPLUS_2L'],
  647. 'SURPLUS_3L' => $data['SURPLUS_3L'],
  648. 'SURPLUS_4L' => $data['SURPLUS_4L'],
  649. 'SURPLUS_5L' => $data['SURPLUS_5L'],
  650. 'SURPLUS_1L_ZC' => $data['SURPLUS_1L_ZC'],
  651. 'SURPLUS_2L_ZC' => $data['SURPLUS_2L_ZC'],
  652. 'SURPLUS_3L_ZC' => $data['SURPLUS_3L_ZC'],
  653. 'SURPLUS_4L_ZC' => $data['SURPLUS_4L_ZC'],
  654. 'SURPLUS_5L_ZC' => $data['SURPLUS_5L_ZC'],
  655. 'SURPLUS_1L_FX' => $data['SURPLUS_1L_FX'],
  656. 'SURPLUS_2L_FX' => $data['SURPLUS_2L_FX'],
  657. 'SURPLUS_3L_FX' => $data['SURPLUS_3L_FX'],
  658. 'SURPLUS_4L_FX' => $data['SURPLUS_4L_FX'],
  659. 'SURPLUS_5L_FX' => $data['SURPLUS_5L_FX'],
  660. ], 'USER_ID=:USER_ID', [':USER_ID' => $data['USER_ID']]);
  661. }
  662. } else {
  663. $isUpdate = true;
  664. UserPerf::insertOne([
  665. 'USER_ID' => $data['USER_ID'],
  666. 'PV_PCS_ZC' => $data['PV_PCS_ZC'],
  667. 'PV_PCS_YH' => $data['PV_PCS_YH'],
  668. 'PV_PCS_ZG' => $data['PV_PCS_ZG'],
  669. 'PV_PCS_LS' => $data['PV_PCS_LS'],
  670. 'PV_PCS_FX' => $data['PV_PCS_FX'],
  671. 'PV_PSS' => $data['PV_PSS'],
  672. 'PV_PSS_TOTAL' => $data['PV_PSS'],
  673. 'PV_1L' => $data['PV_1L'],
  674. 'PV_2L' => $data['PV_2L'],
  675. 'PV_3L' => $data['PV_3L'],
  676. 'PV_4L' => $data['PV_4L'],
  677. 'PV_5L' => $data['PV_5L'],
  678. 'SURPLUS_1L' => $data['SURPLUS_1L'],
  679. 'SURPLUS_2L' => $data['SURPLUS_2L'],
  680. 'SURPLUS_3L' => $data['SURPLUS_3L'],
  681. 'SURPLUS_4L' => $data['SURPLUS_4L'],
  682. 'SURPLUS_5L' => $data['SURPLUS_5L'],
  683. 'SURPLUS_1L_ZC' => $data['SURPLUS_1L_ZC'],
  684. 'SURPLUS_2L_ZC' => $data['SURPLUS_2L_ZC'],
  685. 'SURPLUS_3L_ZC' => $data['SURPLUS_3L_ZC'],
  686. 'SURPLUS_4L_ZC' => $data['SURPLUS_4L_ZC'],
  687. 'SURPLUS_5L_ZC' => $data['SURPLUS_5L_ZC'],
  688. 'SURPLUS_1L_FX' => $data['SURPLUS_1L_FX'],
  689. 'SURPLUS_2L_FX' => $data['SURPLUS_2L_FX'],
  690. 'SURPLUS_3L_FX' => $data['SURPLUS_3L_FX'],
  691. 'SURPLUS_4L_FX' => $data['SURPLUS_4L_FX'],
  692. 'SURPLUS_5L_FX' => $data['SURPLUS_5L_FX'],
  693. 'CREATED_AT' => Date::nowTime(),
  694. ]);
  695. }
  696. if ($isUpdate) {
  697. // 变为已更新
  698. UserPerfUpdate::insertOne(['USER_ID' => $data['USER_ID'], 'PERIOD_NUM' => $this->_periodNum, 'P_CALC_MONTH' => Date::ociToDate($this->_calcYearMonth, Date::OCI_TIME_FORMAT_SHORT_MONTH), 'CREATED_AT' => Date::nowTime()]);
  699. }
  700. unset($data, $isUpdate);
  701. }
  702. $transaction->commit();
  703. } catch (Exception $e) {
  704. $transaction->rollBack();
  705. $this->addError('updateUserPerf', '更新会员业绩失败,原因:' . $e->getMessage());
  706. return false;
  707. }
  708. unset($allData, $transaction);
  709. return $this->updateUserPerf($offset + $this->_limit);
  710. }
  711. unset($allData);
  712. return true;
  713. }
  714. /**
  715. * 更新会员的月剩余业绩
  716. * @param int $offset
  717. * @return bool
  718. * @throws \yii\db\Exception
  719. */
  720. public function updateUserPerfMonth(int $offset = 0) {
  721. // 月结,如果不是月结点,则直接退出
  722. if (!$this->_isCalcMonth) {
  723. return true;
  724. }
  725. $allData = PerfMonth::findUseDbCalc()->where('CALC_MONTH=:CALC_MONTH', [':CALC_MONTH' => $this->_calcYearMonth])->orderBy('ID ASC')->offset($offset)->limit($this->_limit)->all();
  726. if ($allData) {
  727. $transaction = Yii::$app->db->beginTransaction();
  728. try {
  729. foreach ($allData as $data) {
  730. $isUpdate = false;
  731. if (UserPerf::findUseDbCalc()->where('USER_ID=:USER_ID', [':USER_ID' => $data['USER_ID']])->exists()) {
  732. // 判断本期是否已经更新过业绩
  733. if (!UserPerfMonthUpdate::findUseDbCalc()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', [':USER_ID' => $data['USER_ID'], ':CALC_MONTH' => $this->_calcYearMonth])->exists()) {
  734. $isUpdate = true;
  735. // 更新业绩
  736. UserPerf::updateAll([
  737. 'VIP_SURPLUS_1L_ZC' => $data['VIP_SURPLUS_1L_ZC'],
  738. 'VIP_SURPLUS_2L_ZC' => $data['VIP_SURPLUS_2L_ZC'],
  739. 'VIP_SURPLUS_3L_ZC' => $data['VIP_SURPLUS_3L_ZC'],
  740. 'VIP_SURPLUS_4L_ZC' => $data['VIP_SURPLUS_4L_ZC'],
  741. 'VIP_SURPLUS_5L_ZC' => $data['VIP_SURPLUS_5L_ZC']
  742. ], 'USER_ID=:USER_ID', [':USER_ID' => $data['USER_ID']]);
  743. }
  744. } else {
  745. $isUpdate = true;
  746. UserPerf::insertOne([
  747. 'USER_ID' => $data['USER_ID'],
  748. 'VIP_SURPLUS_1L_ZC' => $data['VIP_SURPLUS_1L_ZC'],
  749. 'VIP_SURPLUS_2L_ZC' => $data['VIP_SURPLUS_2L_ZC'],
  750. 'VIP_SURPLUS_3L_ZC' => $data['VIP_SURPLUS_3L_ZC'],
  751. 'VIP_SURPLUS_4L_ZC' => $data['VIP_SURPLUS_4L_ZC'],
  752. 'VIP_SURPLUS_5L_ZC' => $data['VIP_SURPLUS_5L_ZC'],
  753. 'CREATED_AT' => Date::nowTime(),
  754. ]);
  755. }
  756. if ($isUpdate) {
  757. // 变为已更新
  758. UserPerfMonthUpdate::insertOne(['USER_ID' => $data['USER_ID'], 'CALC_MONTH' => $this->_calcYearMonth, 'CREATED_AT' => Date::nowTime()]);
  759. }
  760. unset($data, $isUpdate);
  761. }
  762. $transaction->commit();
  763. } catch (Exception $e) {
  764. $transaction->rollBack();
  765. $this->addError('updateUserPerf', '更新会员月业绩失败,原因:' . $e->getMessage());
  766. return false;
  767. }
  768. unset($allData, $transaction);
  769. return $this->updateUserPerfMonth($offset + $this->_limit);
  770. }
  771. unset($allData);
  772. return true;
  773. }
  774. /**
  775. * 检测复消积分是否过期
  776. * @return bool
  777. * @throws \yii\db\Exception
  778. */
  779. public function checkReconsumePointsExpired(int $offset = 0) {
  780. $periodNum = $this->_periodNum;
  781. //一期为7天,那么365天为52.14即53期
  782. $expiredPeriodNum = $periodNum - 53;
  783. if( $expiredPeriodNum <= 0 ) return true;
  784. //查询需要过期的期数
  785. $allData = UserPeriodPoints::find()->select('ID,USER_ID,REMAINDER_POINTS')->where('PERIOD_NUM<=:PERIOD_NUM AND EXPIRED=0', ['PERIOD_NUM'=>$expiredPeriodNum])->orderBy('ID ASC')->offset($offset)->limit($this->_limit)->asArray()->all();
  786. if( $allData ) {
  787. $transaction = Yii::$app->db->beginTransaction();
  788. try{
  789. //扣除钱包的复消积分
  790. foreach ($allData as $everyData) {
  791. //过期
  792. UserPeriodPoints::updateAll([
  793. 'REMAINDER_POINTS' => 0,
  794. 'EXPIRED' => 1,
  795. 'EXPIRED_PERIOD' => $periodNum,
  796. 'EXPIRED_AT' => Date::nowTime(),
  797. ], 'ID=:ID', ['ID'=>$everyData['ID']]);
  798. if( !isset($everyData['REMAINDER_POINTS']) || !$everyData['REMAINDER_POINTS'] ) continue;
  799. UserBonus::updateAllCounters([
  800. 'RECONSUME_POINTS' => (-1) * $everyData['REMAINDER_POINTS'],
  801. ], 'USER_ID=:USER_ID', $everyData['USER_ID']);
  802. unset($everyData);
  803. }
  804. unset($periodNum, $expiredPeriodNum, $allData);
  805. $transaction->commit();
  806. }catch (\Exception $e){
  807. $transaction->rollBack();
  808. $this->addError('checkReconsumePointsExpired', '检测过期在复消积分失败,原因:' . $e->getMessage());
  809. return false;
  810. }
  811. return $this->checkReconsumePointsExpired($offset + $this->_limit);
  812. }
  813. unset($allData);
  814. return true;
  815. }
  816. /**
  817. * 更新会员上次报单级别
  818. * @return bool
  819. */
  820. public function updateUserDevLv() {
  821. $transaction = Yii::$app->dbShop->beginTransaction();
  822. try {
  823. \Yii::$app->dbShop->createCommand()->update(User::tableName(), ['LAST_DEC_LV' => new Expression('DEC_LV'), 'LAST_DEC_LV_UPDATED_AT' => Date::nowTime(), 'LAST_DEC_LV_UPDATED_PERIOD' => $this->_periodNum], 'LAST_DEC_LV!=DEC_LV')->execute();
  824. $transaction->commit();
  825. } catch (Exception $e) {
  826. $transaction->rollBack();
  827. $this->addError('updateUserDevLv', '更新会员上次报单级别失败,原因:' . $e->getMessage());
  828. return false;
  829. }
  830. return true;
  831. }
  832. /**
  833. * 给商城会员增加货款
  834. * @param $userId
  835. * @param $amount
  836. * @param $remark
  837. * @throws Exception
  838. */
  839. private function _shopAddPaymentForGoods($userId, $amount, $remark) {
  840. $db = \Yii::$app->dbShop;
  841. $transaction = $db->beginTransaction();
  842. try {
  843. ActiveRecord::batchUpdate(['PAYMENT_FOR_GOODS' => new Expression('PAYMENT_FOR_GOODS+' . abs($amount))], 'USER_ID=:USER_ID', [':USER_ID' => $userId], '{{%USER_WALLET}}', 'dbShop');
  844. // 增加流水
  845. $flowInsertData[] = [
  846. 'USER_ID' => $userId,
  847. 'USER_NAME' => Cache::getUserBaseInfo($userId)['USER_NAME'],
  848. 'DEC_LV' => Cache::getUserBaseInfo($userId)['DEC_LV'],
  849. 'ORDER_SN' => null,
  850. 'AMOUNT' => $amount,
  851. 'CREATED_AT' => Date::nowTime(),
  852. 'PERIOD_AT' => $this->_periodNum,
  853. 'IS_INCR' => 1,
  854. 'REMARK' => $remark,
  855. 'PARTITION_DATE' => Date::ociToDate(),
  856. 'WALLET_TYPE' => 'payment_for_goods',
  857. 'FROM_TYPE' => 'incr',
  858. ];
  859. ActiveRecord::batchInsert($flowInsertData, '{{%FLOW_WALLET}}', 'dbShop');
  860. $transaction->commit();
  861. } catch (Exception $e) {
  862. $transaction->rollBack();
  863. throw new Exception($e->getMessage());
  864. }
  865. }
  866. /**
  867. * 更新百分比并发送
  868. * @param $percent
  869. */
  870. private function _updatePercent($percent) {
  871. // 把数据写入数据库中
  872. Period::updateAll(['SENT_PERCENT' => $percent], 'PERIOD_NUM=:PERIOD_NUM', [':PERIOD_NUM' => $this->_periodNum]);
  873. \Yii::$app->swooleAsyncTimer->pushAsyncPercentToAdmin($percent, ['MODEL' => 'PERIOD', 'ID' => $this->_periodId, 'FIELD' => 'SENT_PERCENT']);
  874. }
  875. /**
  876. * 更新最高聘级
  877. * @param $user_id
  878. * @return bool
  879. * @throws Exception
  880. */
  881. private function _updateHighestEmpLv($user_id) {
  882. $empLv = Info::getEmpLv($user_id);
  883. $highEmpLv = Info::getHighEmpLv($user_id);
  884. $empLvSort = EmployLevel::getSortById($empLv);
  885. $empLvHighSort = EmployLevel::getSortById($highEmpLv);
  886. if ($empLvHighYear = YearHighestEmpLv::findOneAsArray('USER_ID=:USER_ID AND YEAR=:YEAR', [':USER_ID' => $user_id, ':YEAR' => $this->_calcYear], 'HIGHEST_EMP_LV_SORT')) {
  887. if ($empLvSort > $empLvHighYear['HIGHEST_EMP_LV_SORT']) {
  888. YearHighestEmpLv::updateAll(['HIGHEST_EMP_LV' => $empLv, 'HIGHEST_EMP_LV_SORT' => $empLvSort, 'HIGHEST_EMP_LV_PERIOD' => $this->_periodNum, 'UPDATED_AT' => Date::nowTime()], 'USER_ID=:USER_ID AND YEAR=:YEAR', [':USER_ID' => $user_id, ':YEAR' => $this->_calcYear]);
  889. }
  890. } else {
  891. $yearHighest = new YearHighestEmpLv();
  892. $yearHighest->USER_ID = $user_id;
  893. $yearHighest->YEAR = $this->_calcYear;
  894. $yearHighest->HIGHEST_EMP_LV = $empLv;
  895. $yearHighest->HIGHEST_EMP_LV_SORT = $empLvSort;
  896. $yearHighest->HIGHEST_EMP_LV_PERIOD = $this->_periodNum;
  897. $yearHighest->CREATED_AT = Date::nowTime();
  898. if (!$yearHighest->save()) {
  899. throw new \yii\db\Exception(Form::formatErrorsForApi($yearHighest->getErrors()));
  900. }
  901. }
  902. if ($empLvSort > $empLvHighSort) {
  903. UserInfo::updateAll(['HIGHEST_EMP_LV' => $empLv, 'HIGHEST_EMP_LV_PERIOD' => $this->_periodNum], 'USER_ID=:USER_ID', [':USER_ID' => $user_id]);
  904. //发送历史最高聘级短信
  905. if($this->_sysConfig['smsEmpOpen']['VALUE']){
  906. if(in_array($empLvSort,explode(",",$this->_sysConfig['smsEmp']['VALUE']))){
  907. $realName = Info::getUserRealNameByUserId($user_id);
  908. $empLvDate = Date::convert();
  909. $empLvName = EmployLevel::getNameById($empLv);
  910. $content = str_replace(['{%REAL_NAME%}', '{%EMP_LV_DATE%}', '{%EMP_LV%}'], [$realName, $empLvDate, $empLvName], $this->_sysConfig['smsContent']['VALUE']);
  911. $params = [
  912. 'mobiles' => Info::getUserMobileByUserId($user_id),
  913. 'content' => $content,
  914. ];
  915. SmsApi::instance()->clearError();
  916. SmsApi::instance()->goSend($params);
  917. }
  918. }
  919. return true;
  920. }
  921. return false;
  922. }
  923. /**
  924. * 点位合作奖金
  925. * @param $userId
  926. * @param $amount
  927. * @param null $type
  928. * @return bool
  929. * @throws Exception
  930. * @throws \yii\db\Exception
  931. */
  932. private function _teamworkBonus($userId, $amount, $key) {
  933. if (!$teamwork = UserTeamwork::findAllAsArray('USER_ID!=:MAIN_UID AND MAIN_UID=:MAIN_UID AND IS_DEL=0', [':MAIN_UID' => $userId], 'USER_ID,DIVIDE_PERCENT')) return false;
  934. $fromUserInfo = CalcCache::getUserInfo($userId, $this->_periodNum);
  935. foreach ($teamwork as $value) {
  936. $bonus = Tool::formatPrice($amount * $value['DIVIDE_PERCENT'] * 0.01);
  937. if ($bonus <= 0) continue;
  938. $toUserInfo = CalcCache::getUserInfo($value['USER_ID'], $this->_periodNum);
  939. Balance::changeUserBonus($userId, 'bonus', -abs($bonus), ['SORT' => $key*10+1, 'DEAL_TYPE_ID' => DealType::TEAMWORK_TRANSFER_OUT, 'REMARK' => 'To:' . $toUserInfo['USER_NAME'] . ' Per:' . $value['DIVIDE_PERCENT'] . '%']);
  940. Balance::changeUserBonus($value['USER_ID'], 'bonus', abs($bonus), ['SORT' => $key*10+2, 'DEAL_TYPE_ID' => DealType::TEAMWORK_TRANSFER_IN, 'REMARK' => 'From: ' . $fromUserInfo['USER_NAME'] . ' Per:' . $value['DIVIDE_PERCENT'] . '%']);
  941. }
  942. }
  943. /**
  944. * 发送短信
  945. * @param int $offset
  946. * @return bool
  947. * @throws \yii\db\Exception
  948. */
  949. public function sendSmsLoop(int $offset = 0) {
  950. $allData = UserInfo::findUseDbCalc()->select('USER_ID,ALLOW_RECONSUME_SMS_TO')->where('ALLOW_RECONSUME_SMS=1')->offset($offset)->limit($this->_limit)->all();
  951. if ($allData) {
  952. $smsWallet = explode(",", $this->_sysConfig['smsWallet']['VALUE']);
  953. $smsFee = $this->_sysConfig['smsFee']['VALUE'];
  954. //获取剩余月份
  955. $period = Period::instance();
  956. $year = $period->getYear($this->_periodNum);
  957. $monthLeft = Period::getMonthLeft($this->_periodNum);
  958. $smsFee = Tool::formatPrice($smsFee * $monthLeft);
  959. $to = Date::yearEnd();
  960. $transaction = Yii::$app->db->beginTransaction();
  961. try {
  962. foreach ($allData as $data) {
  963. $userId = $data['USER_ID'];
  964. //过期续费
  965. if ($data['ALLOW_RECONSUME_SMS_TO'] < Date::nowTime()) {
  966. foreach ($smsWallet as $item) {
  967. //1奖金钱包2现金钱包
  968. if ($item == 1) {
  969. //看余额是否充足
  970. if (Balance::getAvailableBalance($userId) < $smsFee){
  971. UserInfo::updateAll(['ALLOW_RECONSUME_SMS' => 0], 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
  972. continue;
  973. };
  974. Balance::changeUserBonus($userId, 'bonus', -abs($smsFee), ['DEAL_TYPE_ID' => DealType::SMS, 'REMARK' => $year . '年复销提醒短信服务费'], false);
  975. UserInfo::updateAll(['ALLOW_RECONSUME_SMS_TO' => $to], 'USER_ID=:USER_ID', [':USER_ID' => $userId]);
  976. $data['ALLOW_RECONSUME_SMS_TO'] = $to;
  977. break;
  978. } elseif ($item == 2) {
  979. throw new Exception('不存在此方式');
  980. break;
  981. }
  982. }
  983. }
  984. if ($data['ALLOW_RECONSUME_SMS_TO'] > Date::nowTime() && $mobile = Info::getUserMobileByUserId($userId)) {
  985. $realName = Info::getUserRealNameByUserId($userId);
  986. $reconsumPool = Reconsume::getUserReconsumePool($userId);
  987. $lastRechargeDate = $reconsumPool['toRechargeDate'];
  988. $isPass = $reconsumPool['isPass'] == 1 ? '合格' : '不合格';
  989. $month = $period->getNowMonth();
  990. $content = str_replace(['{%REAL_NAME%}', '{%LAST_RECHARGE_DATE%}', '{%MONTH%}', '{%IS_PASS%}'], [$realName, $lastRechargeDate, $month, $isPass], $this->_sysConfig['smsContent']['VALUE']);
  991. //todo 发短信函数 待测试
  992. $params = [
  993. 'mobiles' => $mobile,
  994. 'content' => $content,
  995. ];
  996. SmsApi::instance()->clearError();
  997. SmsApi::instance()->goSend($params);
  998. }
  999. unset($userId,$mobile,$realName,$reconsumPool,$lastRechargeDate,$isPass,$month,$content);
  1000. }
  1001. $transaction->commit();
  1002. } catch (Exception $e) {
  1003. $transaction->rollBack();
  1004. return false;
  1005. }
  1006. unset($data);
  1007. return $this->sendSmsLoop($offset + $this->_limit);
  1008. }
  1009. unset($allData);
  1010. return true;
  1011. }
  1012. }