BonusSend.php 52 KB

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