$moveId ] ); } public function init() { parent::init(); } /** * 加入错误错误 * @param $attr * @param $error */ public function addError($attr, $error){ $this->_errors[$attr][] = $error; } /** * 获取错误信息 * @return array */ public function getErrors(){ return $this->_errors; } /** * 初始化移动 * @param $netType * @param $moveUserId * @param $toConUserId * @param int $location * @param int $fromLocation * @throws \Exception */ public function initMove($netType, $moveUserId, $toConUserId, $location=0, $fromLocation = 0){ $this->_moveInfo = UserMove::findOneAsArray(['ID'=>$this->moveId]); $this->_moveUserId = $moveUserId; $this->_moveUserInfo = Info::baseInfo($moveUserId); if($netType == self::NET_TYPE_NETWORK){ $this->_fromConUserId = $this->_moveUserInfo['CON_UID']; } else { $this->_fromConUserId = $this->_moveUserInfo['REC_UID']; } // $this->_fromConUserInfo = UserInfo::findOneAsArray(['USER_ID'=>$this->_fromConUserId]); $this->_toConUserId = $toConUserId; // $this->_toConUserInfo = UserInfo::findOneAsArray(['USER_ID'=>$this->_toConUserId]); $this->_location = $location; $this->_fromLocation = $fromLocation; $this->_errors = []; $this->_clearChildUserFromRedis($netType); $this->allChildUserToRedisList($netType); } /** * 移动安置网络节点 * @param $moveUserId * @param $toConUserId * @param $location * @param $fromLocation * @return bool * @throws \Exception */ public function moveNetworkPoint($moveUserId, $toConUserId, $location, $fromLocation){ return $this->movePoint(self::NET_TYPE_NETWORK, $moveUserId, $toConUserId, $location, $fromLocation); } /** * 移动开拓网络节点 * @param $moveUserId * @param $toConUserId * @return bool * @throws \Exception */ public function moveRelationPoint($moveUserId, $toConUserId){ return $this->movePoint(self::NET_TYPE_RELATION, $moveUserId, $toConUserId); } /** * 移网 * @param $netType * @param $moveUserId * @param $toConUserId * @param int $location * @param int $fromLocation * @return bool * @throws \Exception */ public function movePoint($netType, $moveUserId, $toConUserId, $location=0, $fromLocation = 0){ $transaction = \Yii::$app->db->beginTransaction(); try { $this->initMove($netType, $moveUserId, $toConUserId, $location, $fromLocation); echo sprintf("时间:[%s],用户ID:[%s]移网,初始化成功".PHP_EOL, date('Y-m-d H:i:s', time()), $moveUserId); //修改移动会员以及子会员的深度、父ID、以及网体标记等 $this->_moveParentAndChildren($netType); // 把userInfo表的数据也改掉 if($netType == self::NET_TYPE_NETWORK){ $conNumField = 'CON_NUM'; } else { $conNumField = 'REC_NUM'; } // 原上级接点数量减少,新上级接点数量增加 UserInfo::updateAllCounters([$conNumField => -1], 'USER_ID=:USER_ID', [':USER_ID'=>$this->_fromConUserId]); UserInfo::updateAllCounters([$conNumField =>1], 'USER_ID=:USER_ID', [':USER_ID'=>$this->_toConUserId]); // 清除redis if ($netType == self::NET_TYPE_NETWORK) { \Yii::$app->redis->del(Cache::USER_NETWORK_PARENTS); } else { \Yii::$app->redis->del(Cache::USER_RELATION_PARENTS); } $this->_endHandle(); $transaction->commit(); } catch (\Exception $e){ echo $e->getMessage() . PHP_EOL; $transaction->rollBack(); $this->_errorHandle(); $this->addError($netType, $e->getMessage()); $this->_clearChildUserFromRedis($netType); return false; } $this->_clearChildUserFromRedis($netType); return true; } /** * 删除备份的表 */ public function dropBakTable(){ $oneMove = $this->_moveInfo; $createTableName = $oneMove['NET_TABLE_NAME']; if(ActiveRecord::isExistsTable('{{%'.$createTableName.'}}', 'dbNetPoint')){ ActiveRecord::deleteTable($createTableName, 'dbNetPoint'); } } /** * 把所有子会员数据存入缓存中 * @param $netType * @return bool */ public function allChildUserToRedisList($netType){ return $this->_getChildUserToRedis($this->_moveUserId, $netType); } private function _getChildUserToRedis($parentUid, $netType) { if($netType == self::NET_TYPE_NETWORK){ $field = 'CON_UID'; } else { $field = 'REC_UID'; } $childList = UserInfo::find()->select(['USER_ID'])->where("{$field}=:PARENT_UID", ['PARENT_UID'=>$parentUid])->asArray()->all(); if( !$childList ) { unset($childList, $field, $parentUid, $netType); return true; } foreach ($childList as $child) { // 会员ID加入缓存 $this->_addChildUserToRedis($netType, $child['USER_ID']); $this->_getChildUserToRedis($child['USER_ID'], $netType); } unset($childList, $field, $parentUid, $netType, $child); return true; } /** * 循环删除子节点对应的非公共节点的数据 * @param $netType * @param $parentUserId * @param int $offset */ public function _loopChildDelUnCommonParent($netType, $parentUserId, int $offset=0){ // 分页从缓存中获取子会员 $allData = $this->_getChildUserFromRedis($netType, $offset, $this->_limit); if($allData){ foreach($allData as $childUserId){ $modelClass = self::getModelClass($netType); $modelClass::deleteAll('PARENT_UID=:PARENT_UID AND USER_ID=:USER_ID', [':PARENT_UID'=>$parentUserId, ':USER_ID'=>$childUserId]); } unset($allData); $this->_loopChildDelUnCommonParent($netType, $parentUserId, $offset + $this->_limit); } } /** * 把移动的会员及子会员加入到直接新上级的节点数据 * @param $netType */ private function _moveParentAndChildren($netType){ $modelClass = self::getModelClass($netType); // 获取一条新上级的网络数据 $fromData = $modelClass::find()->where('USER_ID=:USER_ID', [':USER_ID'=>$this->_moveUserId])->asArray()->one(); $toParentData = $modelClass::find()->where('USER_ID=:USER_ID', [':USER_ID'=>$this->_toConUserId])->asArray()->one(); if( $toParentData['PARENT_UIDS'] ) { $updateParentUids = $toParentData['PARENT_UIDS'] . ',' . $this->_toConUserId; }else { $updateParentUids = $this->_toConUserId; } $updateData = [ 'PARENT_UID' => $this->_toConUserId, 'PARENT_UIDS' => $updateParentUids, 'TOP_UID' => $toParentData['TOP_UID'], 'TOP_DEEP' => $toParentData['TOP_DEEP'] + 1, 'UPDATED_AT' => Date::nowTime(), ]; if($netType == self::NET_TYPE_NETWORK){ $updateData['RELATIVE_LOCATION'] = $this->_location; $updateData['LOCATION_TAG'] = $toParentData['LOCATION_TAG'] . $this->_location; } $modelClass::updateAll($updateData, 'USER_ID=:USER_ID', [ 'USER_ID' => $this->_moveUserId ]); unset($modelClass, $toParentData, $updateParentUids); if($netType == self::NET_TYPE_NETWORK){ $conField = 'CON_UID'; } else { $conField = 'REC_UID'; } UserInfo::updateAll([ $conField => $this->_toConUserId, strtoupper($netType).'_DEEP' => $updateData['TOP_DEEP'], ], 'USER_ID=:USER_ID', [':USER_ID'=>$this->_moveUserId]); $this->_updatePercent(30); // 把子会员也更新、准备公共子会员需要的信息 $commonParentData = [ 'toConUserId' => $this->_toConUserId, 'topUserId' => $updateData['TOP_UID'], 'commonDiffDeep' => $updateData['TOP_DEEP'] - $fromData['TOP_DEEP'], 'oldParentUids' => $fromData['PARENT_UIDS'], 'newParentUids' => $updateData['PARENT_UIDS'], ]; if($netType == self::NET_TYPE_NETWORK){ $commonParentData['oldParentLocationTag'] = $fromData['LOCATION_TAG']; $commonParentData['newParentLocationTag'] = $updateData['LOCATION_TAG']; } unset($fromData, $updateData); $this->_updateChildData($netType, $commonParentData); $this->_changeNetPerfData($netType, $commonParentData); unset($netType, $commonParentData); } /** * 分页循环给子会员增加相较于上级的数据 * @param $netType * @param $params * [ * 'toConUserId' => $this->_toConUserId, * 'topUserId' => $updateData['TOP_UID'], * 'commonDiffDeep' => $updateData['TOP_DEEP'] - $fromData['TOP_DEEP'], * 'oldParentUids' => $fromData['PARENT_UIDS'], * 'newParentUids' => $updateData['PARENT_UIDS'], * ] * @param int $offset */ private function _updateChildData($netType, $params, int $offset = 0){ // 分页获取要移动的会员的子会员 $allData = $this->_getChildUserFromRedis($netType, $offset, $this->_limit); if($allData){ $modelClass = self::getModelClass($netType); foreach($allData as $childUserId){ $childData = $modelClass::find()->where('USER_ID=:USER_ID', [':USER_ID'=>$childUserId])->asArray()->one(); //原PARENT_UIDS、新PARENT_UIDS $childParentUids = substr($childData['PARENT_UIDS'], strlen($params['oldParentUids'])); $childUpdateData = [ 'PARENT_UIDS' => $params['newParentUids'] . $childParentUids,//不变 'TOP_UID' => $params['topUserId'],//和父的保持一致 'TOP_DEEP' => $childData['TOP_DEEP'] + $params['commonDiffDeep'],//所有子会员变化深度一致 'UPDATED_AT' => Date::nowTime(), ]; if($netType == self::NET_TYPE_NETWORK){ //RELATIVE_LOCATION不变 //找到moveUser的 原来 locationTag 的length $childLocationTag = substr($childData['LOCATION_TAG'], strlen($params['oldParentLocationTag'])); $childUpdateData['LOCATION_TAG'] = $params['newParentLocationTag'] . $childLocationTag; unset($childLocationTag); } $modelClass::updateAll($childUpdateData, 'USER_ID=:USER_ID', [ 'USER_ID' => $childUserId ]); UserInfo::updateAll([ strtoupper($netType).'_DEEP' => $childUpdateData['TOP_DEEP'], ], 'USER_ID=:USER_ID', [':USER_ID'=>$childUserId]); unset($childUserId, $childData, $childParentUids, $childUpdateData); } unset($allData, $modelClass); return $this->_updateChildData($netType, $params, $offset + $this->_limit); } unset($allData); return true; } /** * 移网业绩数据处理 * @param $netType * @param $commonData * @return bool */ private function _changeNetPerfData($netType, $commonData) { //获取未结算的月份 $noSentPeriod = Period::find()->where('IS_SENT=0')->orderBy('PERIOD_NUM ASC')->asArray()->one(); if( !$noSentPeriod ) return false; $thisYearMonth = $noSentPeriod['CALC_YEAR'].Tool::numFix($noSentPeriod['CALC_MONTH'], 2); // $lastYearMonth = Date::lastMonth($noSentPeriod['CALC_YEAR'].'-'.$noSentPeriod['CALC_MONTH'], 'Ym'); $thisYearMonthPerf=[]; if( $noSentPeriod['IS_MONTH'] == 1 ) { $thisYearMonthPerf = PerfMonth::find()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$this->_moveUserId, 'CALC_MONTH'=>$thisYearMonth])->asArray()->one(); } unset($noSentPeriod); //查找移动点位这个人的上个月的累计业绩 // $lastYearMonthPerf = PerfMonth::find()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$this->_moveUserId, 'CALC_MONTH'=>$lastYearMonth])->asArray()->one(); //本月的已结算业绩 $thisPerfPeriodList = PerfPeriod::find()->select(['PV_PCS', 'PV_PSS', 'PERIOD_NUM'])->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$this->_moveUserId, 'CALC_MONTH'=>$thisYearMonth])->asArray()->all(); //总的pss_total $userPerf = UserPerf::find()->where('USER_ID=:USER_ID', ['USER_ID'=>$this->_moveUserId])->asArray()->one(); $oldParentUids = $commonData['oldParentUids'] ? explode(',', $commonData['oldParentUids']) : []; $newParentUids = $commonData['newParentUids'] ? explode(',', $commonData['newParentUids']) : []; if( $netType === self::NET_TYPE_RELATION ) { //修改上个月的累计业绩 // if( $lastYearMonthPerf ) { // $lastYearMonthPssTotal = $lastYearMonthPerf['PV_PCS'] + $lastYearMonthPerf['PV_PSS_TOTAL']; // $lastYearMonthPss = $lastYearMonthPerf['PV_PCS'] + $lastYearMonthPerf['PV_PSS']; // foreach ($oldParentUids as $oldParentUid) {//减 // PerfMonth::updateAllCounters(['PV_PSS'=>(-1)*$lastYearMonthPss, 'PV_PSS_TOTAL'=>(-1)*$lastYearMonthPssTotal], 'USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$oldParentUid, 'CALC_MONTH'=>$lastYearMonth]); // unset($oldParentUid); // } // foreach ($newParentUids as $newParentUid) {//加 // PerfMonth::updateAllCounters(['PV_PSS'=>$lastYearMonthPss, 'PV_PSS_TOTAL'=>$lastYearMonthPssTotal], 'USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$newParentUid, 'CALC_MONTH'=>$lastYearMonth]); // unset($newParentUid); // } // unset($lastYearMonthPssTotal, $lastYearMonthPss); // } // unset($lastYearMonthPerf, $lastYearMonth); //修改本月的累计业绩 if( $thisYearMonthPerf ) { $thisYearMonthPssTotal = $thisYearMonthPerf['PV_PCS'] + $thisYearMonthPerf['PV_PSS_TOTAL']; $thisYearMonthPss = $thisYearMonthPerf['PV_PCS'] + $thisYearMonthPerf['PV_PSS']; foreach ($oldParentUids as $oldParentUid) {//减 $parentThisYearMonthPerf = PerfMonth::find()->where('USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$oldParentUid, 'CALC_MONTH'=>$thisYearMonth])->asArray()->one(); if( $parentThisYearMonthPerf ) { if( $parentThisYearMonthPerf['PV_PSS_TOTAL'] < $thisYearMonthPssTotal ) { PerfMonth::updateAll(['PV_PSS'=>(-1)*$thisYearMonthPss, 'PV_PSS_TOTAL'=>0], 'USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$oldParentUid, 'CALC_MONTH'=>$thisYearMonth]); }else { PerfMonth::updateAllCounters(['PV_PSS'=>(-1)*$thisYearMonthPss, 'PV_PSS_TOTAL'=>(-1)*$thisYearMonthPssTotal], 'USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$oldParentUid, 'CALC_MONTH'=>$thisYearMonth]); } } unset($oldParentUid, $parentThisYearMonthPerf); } foreach ($newParentUids as $newParentUid) {//加 PerfMonth::updateAllCounters(['PV_PSS'=>$thisYearMonthPss, 'PV_PSS_TOTAL'=>$thisYearMonthPssTotal], 'USER_ID=:USER_ID AND CALC_MONTH=:CALC_MONTH', ['USER_ID'=>$newParentUid, 'CALC_MONTH'=>$thisYearMonth]); unset($newParentUid); } unset($thisYearMonthPssTotal, $thisYearMonthPss); } unset($thisYearMonthPerf); //修改本月的已结算业绩 foreach ($thisPerfPeriodList as $periodPerf) { $periodPss = $periodPerf['PV_PCS'] + $periodPerf['PV_PSS']; if( $periodPss <= 0 ) continue; foreach ($oldParentUids as $oldParentUid) {//减 PerfPeriod::updateAllCounters(['PV_PSS'=>(-1)*$periodPss], 'USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM', ['USER_ID'=>$oldParentUid, 'PERIOD_NUM'=>$periodPerf['PERIOD_NUM']]); unset($oldParentUid); } foreach ($newParentUids as $newParentUid) {//加 PerfPeriod::updateAllCounters(['PV_PSS'=>$periodPss], 'USER_ID=:USER_ID AND PERIOD_NUM=:PERIOD_NUM', ['USER_ID'=>$newParentUid, 'PERIOD_NUM'=>$periodPerf['PERIOD_NUM']]); unset($newParentUid); } unset($periodPerf, $periodPss); } unset($thisPerfPeriodList, $thisYearMonth); if( $userPerf ) { $userPerfPss = $userPerf['PV_PCS_ZC'] + $userPerf['PV_PCS_FX'] + $userPerf['PV_PSS']; $userPerfPssTotal = $userPerf['PV_PCS_ZC'] + $userPerf['PV_PCS_FX'] + $userPerf['PV_PSS_TOTAL']; foreach ($oldParentUids as $oldParentUid) {//减 $parentPerf = UserPerf::find()->where('USER_ID=:USER_ID', ['USER_ID'=>$oldParentUid])->asArray()->one(); if( $parentPerf ) { if( $parentPerf['PV_PSS_TOTAL'] < $userPerfPssTotal ) { UserPerf::updateAll(['PV_PSS'=>0, 'PV_PSS_TOTAL'=>0], 'USER_ID=:USER_ID', ['USER_ID'=>$oldParentUid]); }else { UserPerf::updateAllCounters(['PV_PSS'=>(-1)*$userPerfPss, 'PV_PSS_TOTAL'=>(-1)*$userPerfPssTotal], 'USER_ID=:USER_ID', ['USER_ID'=>$oldParentUid]); } } unset($oldParentUid, $parentPerf); } foreach ($newParentUids as $newParentUid) {//加 UserPerf::updateAllCounters(['PV_PSS'=>$userPerfPss, 'PV_PSS_TOTAL'=>$userPerfPssTotal], 'USER_ID=:USER_ID', ['USER_ID'=>$newParentUid]); unset($newParentUid); } unset($userPerfPss, $userPerfPssTotal); } unset($userPerf); } if( $netType === self::NET_TYPE_NETWORK ) { //@todo 团队奖相关的,对碰往期对碰剩余业绩是否修改 } unset($oldParentUids, $newParentUids); } /** * 结束操作 * @throws Exception */ private function _endHandle(){ // 把移网申请记录的正在移网状态修改 $oneMove = UserMove::findOne(['ID'=>$this->moveId]); $oneMove->IS_MOVING = 0; $oneMove->AUDIT_STATUS = \Yii::$app->params['auditStatus']['true']['value']; $oneMove->ENDED_AT = Date::nowTime(); if(!$oneMove->save()){ throw new Exception(Form::formatErrorsForApi($oneMove->getErrors())); } $this->_updatePercent(100); } /** * 错误的时候,把移网状态改回原状 */ private function _errorHandle(){ // 把移网的审核状态回归 $oneMove = UserMove::findOne(['ID'=>$this->moveId]); $oneMove->IS_MOVING = 0; $oneMove->AUDIT_ADMIN_ID = null; $oneMove->AUDITED_AT = 0; $oneMove->AUDIT_STATUS = \Yii::$app->params['auditStatus']['false']['value']; $oneMove->save(); // 删除创建的表 $this->dropBakTable(); $this->_updatePercent(0); } /** * 更新百分比并发送 * @param $percent */ private function _updatePercent($percent){ // 把数据写入数据库中 UserMove::updateAll(['MOVE_PERCENT'=>$percent], 'ID=:ID', [':ID'=>$this->moveId]); \Yii::$app->swooleAsyncTimer->pushAsyncPercentToAdmin($percent, ['MODEL' => 'USER_MOVE' ,'ID' => $this->moveId, 'FIELD' => 'MOVE_PERCENT']); } /** * 把子会员存入到缓存中 * @param $netType * @param $userId */ private function _addChildUserToRedis($netType, $userId){ $cacheKey = sprintf(self::REDIS_KEY_PREFIX_CHILD_USER, $netType, $this->_moveUserId); \Yii::$app->redis->rpush($cacheKey, $userId); } /** * 从缓存中获取子会员数据 * @param $netType * @param $offset * @param $limit * @return mixed */ private function _getChildUserFromRedis($netType, $offset, $limit){ $cacheKey = sprintf(self::REDIS_KEY_PREFIX_CHILD_USER, $netType, $this->_moveUserId); return \Yii::$app->redis->lrange($cacheKey, $offset, ($offset + $limit - 1)); } /** * 清空子会员数据从缓存中 * @param $netType * @return mixed */ private function _clearChildUserFromRedis($netType){ $cacheKey = sprintf(self::REDIS_KEY_PREFIX_CHILD_USER, $netType, $this->_moveUserId); return \Yii::$app->redis->del($cacheKey); } /** * 获取model类 * @param $netType * @return null|string */ private static function getModelClass($netType){ if($netType == self::NET_TYPE_NETWORK){ return UserNetwork::class; } elseif($netType == self::NET_TYPE_RELATION){ return UserRelation::class; } else { return null; } } }