/** * @args {"description": "Delay: Stats of StatsMemberGrowthMonthly every day"} * @author Rex Chen */ public function perform() { $args = $this->args; $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m', $datetime); $startTime = new \MongoDate(strtotime($dateStr . '-01')); $endTime = new \MongoDate(strtotime($dateStr . '-01 +1 month')); $accounts = Account::findAll(['enabledMods' => 'member']); foreach ($accounts as $account) { $accountId = $account->_id; $totalMember = Member::countByAccount($accountId, null, $endTime); $totalActive = MemberLogs::getTotalActiveByAccount($accountId, $startTime, $endTime); $totalNew = Member::countByAccount($accountId, $startTime, $endTime); $statsGrowth = ModelStatsMemberGrowthMonthly::getByMonthAndAccount($accountId, $dateStr); if (empty($statsGrowth)) { $statsGrowth = new ModelStatsMemberGrowthMonthly(); $statsGrowth->accountId = $accountId; $statsGrowth->month = $dateStr; } $statsGrowth->totalNew = $totalNew; $statsGrowth->totalActive = $totalActive; $statsGrowth->totalInactive = $totalMember - $totalActive; try { $statsGrowth->save(); } catch (Exception $e) { ResqueUtil::log(['Update StatsMemberGrowthMonthly error' => $e->getMessage(), 'StatsMemberGrowthMonthly' => $statsGrowth]); continue; } } return true; }
/** * @args {"description": "Delay: Stats of StatsMemberDaily", "runNextJob": true} * @author Rex Chen */ public function perform() { $args = $this->args; $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m-d', $datetime); if (!empty(WECONNECT_DOMAIN)) { $channelNameMap = $this->_getChannelNameMap(); } $start = new \MongoDate($datetime); $end = new \MongoDate(strtotime('+1 day', $datetime)); $memberStats = Member::getNewMemberStats($start, $end); $rowStats = []; foreach ($memberStats as $stats) { $accountId = $stats['_id']['accountId']; $origin = $stats['_id']['origin']; $socialAccountId = $stats['_id']['socialAccountId']; $originName = empty($channelNameMap[$socialAccountId]) ? '' : $channelNameMap[$socialAccountId]; $total = $stats['total']; $statsMember = ModelStatsMemberDaily::getByDateAndOriginInfo($dateStr, $origin, $originName, $accountId); if (!empty($statsMember)) { $statsMember->total = $total; try { $statsMember->save(true, ['total']); } catch (Exception $e) { ResqueUtil::log(['Update StatsMemberDaily error' => $e->getMessage(), 'StatsMemberDaily' => $statsMember]); continue; } } else { $rowStats[] = ['date' => $dateStr, 'origin' => $origin, 'originName' => $originName, 'total' => $total, 'accountId' => $accountId]; } } ModelStatsMemberDaily::batchInsert($rowStats); return true; }
/** * @args {"description": "Delay: Stats of questionnaire"} */ public function perform() { $args = $this->args; //Get date from args or today $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m-d', $datetime); $stats = QuestionnaireLog::getStats($dateStr); $statsRows = []; foreach ($stats as $stat) { $questionnaireId = $stat['_id']['questionnaireId']; $accountId = $stat['_id']['accountId']; //if $dailyStats exists, update it; else , create $dailyStats = ModelStatsQuestionnaireDaily::getByQuestionnaireAndDate($accountId, $questionnaireId, $dateStr); if (empty($dailyStats)) { $statsRows[] = ['accountId' => $accountId, 'questionnaireId' => $questionnaireId, 'date' => $dateStr, 'count' => $stat['count']]; } else { $dailyStats->count = $stat['count']; //catch exception to avoid block batch insert try { $dailyStats->save(true, ['count']); } catch (Exception $e) { LogUtil::error(['Update StatsQuestionnaireDaily error' => $e->getMessage(), 'StatsQuestionnaireDaily' => $dailyStats]); continue; } } } ModelStatsQuestionnaireDaily::batchInsert($statsRows); return true; }
/** * @args {"description": "Delay: Clean offline client and helpdesk every minute"} */ public function perform() { $accounts = Account::findAll([]); foreach ($accounts as $account) { $accountId = $account->_id; $setting = HelpDeskSetting::findOne(['accountId' => $accountId]); if (!empty($setting)) { $maxWaitTime = $setting->maxWaitTime; // Close timeout conversation $chatConversations = ChatConversation::findAll(['accountId' => $accountId, 'status' => ChatConversation::STATUS_OPEN, 'lastChatTime' => ['$lt' => TimeUtil::msTime(time() - $maxWaitTime * 60)]]); foreach ($chatConversations as $chatConversation) { HelpDesk::disconnect($chatConversation->_id, ['type' => 'brake']); } // Delete timeout pending client $pendingClients = PendingClient::findAll(['accountId' => $accountId, 'lastPingTime' => ['$lt' => TimeUtil::msTime(time() - PendingClient::PING_THRESHOLD)]]); foreach ($pendingClients as $pendingClient) { $pendingClient->delete(); } // Clean offline helpdesk $cache = Yii::$app->cache; $onlineHelpDesks = $cache->get(HelpDesk::CACHE_PREFIX_HELPDESK_PING . $accountId); if (!empty($onlineHelpDesks)) { foreach ($onlineHelpDesks as $deskId => $lastPingTime) { if ($lastPingTime < TimeUtil::msTime(time() - HelpDesk::PING_THRESHOLD)) { HelpDesk::leave($deskId, $accountId, ['type' => 'droping']); } } } } } }
public function perform() { $args = $this->args; $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m', $datetime); $monthData = ModelStatsMemberDaily::getMonthData($dateStr); $rowsMonthly = []; foreach ($monthData as $item) { $origin = $item['_id']['origin']; $originName = $item['_id']['originName']; $accountId = $item['_id']['accountId']; $total = $item['total']; $statsMemberMonthly = ModelStatsMemberMonthly::getByDateAndOriginInfo($dateStr, $origin, $originName, $accountId); if (!empty($statsMemberMonthly)) { $statsMemberMonthly->total = $total; try { $statsMemberMonthly->save(true, ['total']); } catch (Exception $e) { ResqueUtil::log(['Update StatsMemberMonthly error' => $e->getMessage(), 'StatsMemberMonthly' => $statsMemberMonthly]); continue; } } else { $rowsMonthly[] = ['month' => $dateStr, 'origin' => $origin, 'originName' => $originName, 'accountId' => $accountId, 'total' => $total]; } } ModelStatsMemberMonthly::batchInsert($rowsMonthly); return true; }
public function perform() { $args = $this->args; $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $accountId = $args['accountId']; return ModelStatsCampaignProductCodeQuarterly::generateByYearAndQuarter($accountId, $datetime); }
/** * @args {"description": "Direct: Stats of coupon"} */ public function perform() { $args = $this->args; //Get date from args or today $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m-d', $datetime); $stats = CouponLog::getStats($dateStr); if (!empty($stats)) { self::createStatsCouponLog($dateStr, $stats); } return true; }
/** * @args {"description": "Delay: Stats of questionnaire answer"} */ public function perform() { $args = $this->args; //Get date from args or today $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m-d', $datetime); //in case of too much data, get stats by questionnaire $skip = 0; $limit = 100; $query = Questionnaire::find()->orderBy(['_id' => SORT_ASC]); $query = $query->offset($skip)->limit($limit); $questionnaires = $query->all(); while (!empty($questionnaires)) { $statsRows = []; foreach ($questionnaires as $questionnaire) { $stats = QuestionnaireLog::getAnswerStats($questionnaire->_id, $dateStr); //group stats by questionId $rows = []; foreach ($stats as $stat) { $questionIdStr = (string) $stat['_id']['questionId']; $optionValue = $stat['_id']['value']; $rows[$questionIdStr][] = ['option' => $optionValue, 'count' => $stat['count']]; } //format stats data, and save it foreach ($rows as $questionIdStr => $answerStats) { $questionId = new MongoId($questionIdStr); $statsAnswerDaily = ModelStatsQuestionnaireAnswerDaily::getByQuestionIdAndDate($questionId, $dateStr); if (empty($statsAnswerDaily)) { $statsRows[] = ['questionId' => $questionId, 'stats' => $answerStats, 'date' => $dateStr, 'accountId' => $questionnaire->accountId]; } else { $statsAnswerDaily->stats = $answerStats; try { $statsAnswerDaily->save(); } catch (Exception $e) { ResqueUtil::log(['Update StatsQuestionnaireAnswerDaily error' => $e->getMessage(), 'StatsQuestionnaireAnswerDaily' => $statsAnswerDaily]); continue; } } } } ModelStatsQuestionnaireAnswerDaily::batchInsert($statsRows); $skip += $limit; $query = $query->offset($skip)->limit($limit); //free $questionnaires unset($questionnaires); $questionnaires = $query->all(); } return true; }
private function _transformMessages($result, $channelId) { $items = $item = []; if (!empty($result) && !empty($result['results']) && count($result['results']) > 0) { foreach ($result['results'] as $message) { $messages = $message['message']; if (!empty($messages)) { $item = ['id' => empty($messages['messageId']) ? '' : $messages['messageId'], 'channelId' => $channelId, 'message' => !isset($messages['content']) ? '' : $messages['content'], 'msgType' => $messages['msgType'], 'keycode' => !isset($message['keycode']) ? '' : $message['keycode'], 'interactTime' => TimeUtil::msTime2String($messages['createTime'], 'Y-m-d H:i:s')]; $items[] = $item; } } } return $items; }
/** * Login * * <b>Request Type</b>: POST<br/><br/> * <b>Request Endpoint</b>:http://{server-domain}/chat/site/login<br/><br/> * <b>Content-type</b>: application/json<br/><br/> * <b>Summary</b>: This api is used for the help desk to login. * <br/><br/> * * <b>Request Params</b>:<br/> * email: string, the user email, required<br/> * password: string, the user password, required<br/> * <br/><br/> * * <b>Response Params:</b><br/> * ack: integer, mark the create result, 0 means create successfully, 1 means create fail<br/> * msg: string, if create fail, it contains the error message<br/> * data: array, json array to describe the users detail information<br/> * <br/><br/> * * <b>Request Example:</b><br/> * <pre> * { * "email" : "*****@*****.**", * "password" : "abc123" * } * </pre> * <br/><br/> * * <b>Response Example</b>:<br/> * <pre> * { * 'ack' : 1, * 'data' : { * "accessToken" : "7f2d1e92-9629-8429-00be-2d9c6d64acdb", * "userInfo" : { * "name" : "harry", * "avatar" : "path/to/avatar" * } * } * } * </pre> */ public function actionLogin() { $params = $this->getParams(); $deviceToken = $this->getParams('deviceToken'); $environment = $this->getParams('environment'); if (empty($params['email']) || empty($params['password'])) { throw new BadRequestHttpException("parameters missing"); } $helpdesk = HelpDesk::getByEmail($params['email']); if (empty($helpdesk)) { throw new ForbiddenHttpException("用戶不存在"); } if (!$helpdesk->isActivated) { throw new ForbiddenHttpException("用戶未激活,请激活后使用"); } if (!$helpdesk->isEnabled) { throw new ForbiddenHttpException("该账号已被禁用,请与管理员联系"); } if ($helpdesk->validatePassword($params['password'])) { $tokens = Token::getUnexpiredByUserId($helpdesk->_id); if (!empty($tokens)) { $data = ['isForcedOffline' => true, 'id' => $helpdesk->_id . '']; $accountId = $tokens[0]->accountId; Yii::$app->tuisongbao->triggerEvent(ChatConversation::EVENT_FORCED_OFFLINE, $data, [ChatConversation::CHANNEL_GLOBAL . $accountId]); //deviceToken changed, push forcedOffline if (empty($deviceToken) && !empty($helpdesk->deviceToken) || !empty($deviceToken) && !empty($helpdesk->deviceToken) && $deviceToken != $helpdesk->deviceToken) { $extra = ['deskId' => $helpdesk->_id . '', 'sentTime' => TimeUtil::msTime()]; ChatConversation::pushMessage($helpdesk->_id, ChatConversation::EVENT_FORCED_OFFLINE, $extra); } Token::updateAll(['$set' => ['expireTime' => new \MongoDate()]], ['_id' => ['$in' => Token::getIdList($tokens)]]); } $isFirstLogin = empty($helpdesk->lastLoginAt); $accessToken = Token::createByHelpDesk($helpdesk); if (isset($deviceToken)) { $helpdesk->loginDevice = HelpDesk::MOBILEAPP; } else { $helpdesk->loginDevice = HelpDesk::BROWSER; } $helpdesk->deviceToken = $deviceToken; $helpdesk->environment = $environment; $helpdesk->lastLoginAt = new \MongoDate(); $helpdesk->save(true, ['deviceToken', 'loginDevice', 'environment', 'lastLoginAt']); $userInfo = ['badge' => $helpdesk->badge, 'name' => $helpdesk->name, 'email' => $helpdesk->email, 'language' => $helpdesk->language, 'avatar' => empty($helpdesk->avatar) ? '' : $helpdesk->avatar, 'id' => (string) $helpdesk->_id, 'accountId' => (string) $helpdesk['accountId'], 'notificationType' => $helpdesk->notificationType, 'isFirstLogin' => $isFirstLogin]; return ["accessToken" => $accessToken['accessToken'], 'userInfo' => $userInfo]; } else { throw new ForbiddenHttpException("密码错误"); } }
public function perform() { $args = $this->args; $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $accountId = $args['accountId']; //Assume that the subChannel is the secode element in properties $propertyKey = $args['properties'][1]; $memberProperty = MemberProperty::findOne(['propertyId' => $propertyKey]); if ($memberProperty != null) { return ModelStatsMemberPropTradeCodeQuarterly::generateByYearAndQuarter((string) $memberProperty['_id'], $accountId, $datetime); } else { ResqueUtil::log("Fail to get memberProperty with propertyId {$propertyKey}"); } return false; }
/** * Provide card * * <b>Request Type</b>: POST<br/><br/> * <b>Request Endpoint</b>:http://{server-domain}/api/member/card/provide-card<br/><br/> * <b>Response Content-type</b>: application/json<br/><br/> * <b>Summary</b>: This api is used for provide card. * <br/><br/> * * <b>Request Params</b>:<br/> * cardId: string<br/> * cardNumbers: Array, card number<br/> * names: Array * tags: Array<br/> * cardExpiredAt: timestamp<br/> * <br/><br/> * * <b>Response Params:</b><br/> * message: * <br/><br/> * * <br/><br/> * * <b>Response Example</b>:<br/> * <pre> * {"message" : "OK"} * </pre> */ public function actionProvideCard() { $params = $this->getParams(); $accountId = $this->getAccountId(); $params['accountId'] = $accountId . ''; if (empty($params['cardId'])) { throw new BadRequestHttpException('param error'); } if (empty($params['cardExpiredAt'])) { throw new InvalidParameterException(['schedule-picker' => \Yii::t('common', 'required_filed')]); } $cardId = new \MongoId($params['cardId']); $card = MemberShipCard::findByPk($cardId); if (empty($card)) { throw new BadRequestHttpException(\Yii::t('member', 'no_card_find')); } if ($card->isAutoUpgrade) { throw new InvalidParameterException(Yii::t('member', 'error_issue_auto_card')); } if ($params['cardExpiredAt'] < TimeUtil::msTime()) { throw new InvalidParameterException(['schedule-picker' => \Yii::t('member', 'not_less_than_current')]); } $members = []; if (!empty($params['cardNumbers']) && is_array($params['cardNumbers'])) { $members = Member::getByCardNumbers($params['cardNumbers']); if (empty($members)) { throw new InvalidParameterException(['cardNumber' => \Yii::t('member', 'no_member_find')]); } } else { if (!empty($params['names']) && is_array($params['names'])) { $members = Member::getByNames($params['names']); if (empty($members)) { throw new InvalidParameterException(['memberNames' => \Yii::t('member', 'no_member_find')]); } } else { if (!empty($params['tags']) && is_array($params['tags'])) { $members = Member::getByTags($params['tags']); if (empty($members)) { throw new InvalidParameterException(['memberTags' => \Yii::t('member', 'no_member_find')]); } } } } $memberIds = Member::getIdList($members); Member::updateAll(['$set' => ['cardId' => $cardId, 'cardExpiredAt' => $params['cardExpiredAt']]], ['_id' => ['$in' => $memberIds]]); return ['message' => 'OK']; }
/** * @args {"description": "Direct: Analysis daily promotion code "} */ public function perform() { $yesterday = ModelPromotionCodeAnalysis::getTime(-1); $type = new MongoInt32(ModelPromotionCodeAnalysis::PROMOTION_CODE_ANALYSIS_TOTAL); $where = ['createdAt' => $yesterday, 'type' => $type]; $status = ModelPromotionCodeAnalysis::checkExistData($where); if ($status) { $yesterdayStamp = TimeUtil::today() - 24 * 3600; $yesterday = new MongoDate($yesterdayStamp); //get campaignlogs in yesterday $campaignLogs = ModelPromotionCodeAnalysis::getMemberCampaignLog(); //create datas if (!empty($campaignLogs)) { $campaignData = []; foreach ($campaignLogs as $key => $campaignLog) { //get total the day before yesterday $beforeYesterday = new MongoDate(TimeUtil::today() - 2 * 24 * 3600); $productId = $campaignLog['_id']['productId']; $campaignId = $campaignLog['_id']['campaignId']; $accountId = $campaignLog['_id']['accountId']; $condition = ['productId' => $productId, 'campaignId' => $campaignId, 'accountId' => $accountId, 'createdAt' => $beforeYesterday, 'type' => $type]; $beforeYesterdayData = ModelPromotionCodeAnalysis::findOne($condition); if (empty($beforeYesterdayData)) { $beforeYesterdayData['total'] = 0; } $condition = ['campaignId' => $campaignId, 'accountId' => $accountId, 'productId' => $productId]; $number = ModelPromotionCodeAnalysis::checkMemberUnique($condition, TimeUtil::today()); //subtract the member who is recorded before $total = $beforeYesterdayData['total'] + $number; $campaignLogs[$key]['total'] = $total; } $campaignData = ModelPromotionCodeAnalysis::createAnalysisData($campaignLogs, $type, $yesterday); if (false === ModelPromotionCodeAnalysis::batchInsert($campaignData)) { LogUtil::error(['message' => 'Faild to create daily data', 'date' => date('Y-m-d H:i:s'), 'data' => json_encode($campaignData)], 'resque'); } } //set the default value when the value is not exists $yesterdayStamp -= 3600 * 24; ModelPromotionCodeAnalysis::setDefault($yesterdayStamp, $type); } else { LogUtil::info(['message' => 'Total analysis data is exists', 'date' => date('Y-m-d H:i:s')], 'resque'); } return true; }
private static function _setStatsMemberPropTradeQuarterly($startTime, $endTime, $args) { //Assume that the subChannel is the secode element in properties $propertyKey = $args['properties'][1]; $memberProperty = MemberProperty::findOne(['propertyId' => $propertyKey]); if (!empty($memberProperty)) { $startQuarter = TimeUtil::getQuarter($startTime); $endQuarter = TimeUtil::getQuarter($endTime); for ($quarter = $startQuarter; $quarter <= $endQuarter; ++$quarter) { $year = date('Y', $startTime); $condition = ['accountId' => $args['accountId'], 'year' => $year, 'quarter' => $quarter]; StatsMemberPropTradeQuarterly::deleteAll($condition); self::generateStatsMemberPropTradeQuarterlyData((string) $memberProperty['_id'], $condition); LogUtil::info(['message' => $quarter . ' :Run StatsMemberPropTradeQuarterly'], 'update_job'); } } else { LogUtil::info(['message' => 'Can not find this propertyId:' . $propertyKey], 'update_job'); } }
public function perform() { //accountId, properties are required fileds $args = $this->args; if (empty($args['accountId']) || empty($args['properties'])) { ResqueUtil::log('Missing required arguments accountId or properties!'); return false; } $date = empty($args['date']) ? '' : $args['date']; $datetime = TimeUtil::getDatetime($date); $dateStr = date('Y-m-d', $datetime); $start = new MongoDate($datetime); $end = new MongoDate(strtotime('+1 day', $datetime)); $accountId = new MongoId($args['accountId']); $condition = ['accountId' => $accountId, 'createdAt' => ['$gte' => $start, '$lt' => $end]]; $campaignLogs = self::getCampaignLog($condition); if (empty($campaignLogs)) { LogUtil::info(['date' => date('Y-m-d H:i:s'), 'message' => $dateStr . ': campaignLogs is empty,no need to store data'], 'resque'); return true; } //get all member info $memberInfos = self::getMemberInfo($condition); //Get all the property mongo id for comparison $condition = ['propertyId' => ['$in' => $args['properties']], 'accountId' => $accountId]; $propertyIdStrs = self::getPropertyIds($condition); //Generate the meta data for inserting $statsRows = []; foreach ($campaignLogs as $campaignLog) { $campaignLog = $campaignLog['_id']; $redeemTime = self::getRedeemTime($campaignLog); //check the redeem time whether exists $condition = ['code' => $campaignLog['code'], 'productId' => $campaignLog['productId'], 'month' => date('Y-m', $redeemTime)]; $memberCampaignLogDaily = ModelStatsMemberCampaignLogDaily::findOne($condition); if (empty($memberCampaignLogDaily)) { $memProperty = self::getProperty((string) $campaignLog['member']['id'], $memberInfos, $propertyIdStrs); $statsRows[] = ['memberId' => $campaignLog['member']['id'], 'memProperty' => $memProperty, 'productId' => $campaignLog['productId'], 'code' => $campaignLog['code'], 'year' => date('Y', $redeemTime), 'month' => date('Y-m', $redeemTime), 'quarter' => TimeUtil::getQuarter($redeemTime), 'accountId' => $accountId, 'createdAt' => new MongoDate(strtotime('+1 day', $datetime) - 1)]; } } ModelStatsMemberCampaignLogDaily::batchInsert($statsRows); unset($statsRows, $memberCampaignLogDaily, $condition, $memProperty, $memberInfos); return true; }
/** * @args {"description": "Direct: Analysis participate promotion code "} */ public function perform() { $yesterday = ModelPromotionCodeAnalysis::getTime(-1); $type = new MongoInt32(ModelPromotionCodeAnalysis::PROMOTION_CODE_ANALYSIS_PARTICIPATE); $where = ['createdAt' => $yesterday, 'type' => $type]; $status = ModelPromotionCodeAnalysis::checkExistData($where); if ($status) { $yesterdayStamp = TimeUtil::today() - 24 * 3600; $yesterday = new MongoDate($yesterdayStamp); $createWhere = ModelPromotionCodeAnalysis::getCreateTime(); $campaignIds = CampaignLog::distinct('campaignId', $createWhere); $campaignLogs = []; if (!empty($campaignIds)) { $where = array_merge($createWhere, ['campaignId' => ['$in' => $campaignIds]]); $campaignLogs = CampaignLog::getCollection()->aggregate([['$match' => $where], ['$group' => ['_id' => ['campaignId' => '$campaignId', 'memberId' => '$member.id', 'accountId' => '$accountId', 'productId' => '$productId']]]]); } if (!empty($campaignLogs)) { //get total for take part in a campaign $campaignData = []; foreach ($campaignLogs as $data) { $campaignId = $data['_id']['campaignId']; $key = (string) $campaignId . (string) $data['_id']['productId']; if (isset($campaignData[$key])) { //to sum the total in every product in same campaign $campaignData[$key]['total'] += 1; } else { $product = Product::findByPk($data['_id']['productId']); $productName = empty($product['name']) ? '' : $product['name']; $result = ['productId' => $data['_id']['productId'], 'productName' => $productName, 'campaignId' => $campaignId, 'accountId' => $data['_id']['accountId'], 'createdAt' => $yesterday, 'total' => 1, 'type' => $type]; $campaignData[$key] = $result; } } if (false === ModelPromotionCodeAnalysis::batchInsert($campaignData)) { LogUtil::error(['message' => 'Faild to create daily data', 'date' => date('Y-m-d H:i:s'), 'data' => json_encode($campaignData)], 'resque'); } unset($datas, $campaignIds, $campaignData); } } else { LogUtil::info(['message' => 'Participate analysis data is exists', 'date' => date('Y-m-d H:i:s')], 'resque'); } return true; }
/** * @args {"description": "Direct: Analysis total participate"} */ public function perform() { $yesterday = ModelPromotionCodeAnalysis::getTime(-1); $type = new MongoInt32(ModelPromotionCodeAnalysis::PROMOTION_CODE_ANALYSIS_TOTAL_PARTICIPATE); $where = ['createdAt' => $yesterday, 'type' => $type]; $status = ModelPromotionCodeAnalysis::checkExistData($where); if ($status) { $yesterdayStamp = TimeUtil::today() - 24 * 3600; $yesterday = new MongoDate($yesterdayStamp); $where = ModelPromotionCodeAnalysis::getCreateTime(); $campaignData = ModelPromotionCodeAnalysis::getMemberAllTimes($where); $campaignData = ModelPromotionCodeAnalysis::createAnalysisData($campaignData, $type, $yesterday); if (false === ModelPromotionCodeAnalysis::batchInsert($campaignData)) { LogUtil::error(['message' => 'Faild to create daily data', 'date' => date('Y-m-d H:i:s'), 'data' => json_encode($campaignData)], 'resque'); } } else { LogUtil::info(['message' => 'Total participate analysis data is exists', 'date' => date('Y-m-d H:i:s')], 'resque'); } return true; }
public function perform() { $args = $this->args; if (empty($args['accountId']) || empty($args['properties'][0])) { ResqueUtil::log('Missing required arguments accountId or properties!'); return false; } $accountId = new MongoId($args['accountId']); $property = $args['properties'][0]; $memberProperty = MemberProperty::getByPropertyId($accountId, $property); if (empty($memberProperty)) { ResqueUtil::log('Can not find member property with propertyId:' . $property); return false; } $date = empty($args['date']) ? '' : $args['date']; $date = TimeUtil::getDatetime($date); $year = date('Y', $date); $quarter = TimeUtil::getQuarter($date); self::generateData($memberProperty, $property, $year, $quarter, $accountId); return true; }
public function actionStatsMenusHits() { $openId = $this->getQuery('openId'); $channelId = $this->getQuery('channelId'); $count = 0; $lastTime = ''; $results = []; if (empty($openId) || empty($channelId)) { throw new BadRequestHttpException(Yii::t('common', 'parameters_missing')); } $resultItem = Yii::$app->weConnect->statsMenusHits($openId, $channelId); if (!empty($resultItem)) { if (!empty($resultItem['profiles']) && !empty($resultItem['profiles']['menus']) && count($resultItem['profiles']['menus']) > 0) { $raw = $resultItem['profiles']['menus']; $count = !isset($raw['hitCount']) ? 0 : $raw['hitCount']; $lastTime = empty($raw['lastHitTime']) ? '' : TimeUtil::msTime2String($raw['lastHitTime'], 'Y-m-d H:i:s'); } } $item = ['hitCount' => $count, 'lastHitTime' => $lastTime]; return $item; }
public function actionStatsCoupon() { $params = $this->getQuery(); if (empty($params['id']) || !isset($params['startTime']) || !isset($params['endTime'])) { throw new BadRequestHttpException(Yii::t('common', 'parameters_missing')); } $id = new MongoId($params['id']); $couponLog = Coupon::findOne(["_id" => $id]); if (empty($couponLog)) { throw new BadRequestHttpException(Yii::t('product', 'membershipDiscount_is_deleted')); } //turn unix timestamp to string $startTime = TimeUtil::msTime2String($params['startTime'], 'Y-m-d'); $endTime = TimeUtil::msTime2String($params['endTime'], 'Y-m-d'); $couponPeriodInfo = StatsCouponLogDaily::getCouponLogStats($id, $startTime, $endTime); ArrayHelper::multisort($couponPeriodInfo, 'date', SORT_ASC); $dateCouPonStats = ArrayHelper::index($couponPeriodInfo, 'date'); $item = $redeemedNum = $recievedNum = $date = []; $startDate = strtotime($startTime); $endDate = strtotime($endTime); if (!empty($couponPeriodInfo) && count($couponPeriodInfo) > 0) { while ($startDate <= $endDate) { $dateStr = date('Y-m-d', $startDate); if (!empty($dateCouPonStats[$dateStr])) { $date[] = $dateStr; $recievedNum[] = $dateCouPonStats[$dateStr]['recievedNum']; $redeemedNum[] = $dateCouPonStats[$dateStr]['redeemedNum']; } else { $date[] = $dateStr; $recievedNum[] = 0; $redeemedNum[] = 0; } $startDate = strtotime($dateStr . ' +1 day'); } } $item = ['date' => $date, 'count' => ['recievedNum' => $recievedNum, 'redeemedNum' => $redeemedNum]]; return $item; }
public function perform() { $args = $this->args; if (empty($args['accountId']) || empty($args['properties'][0])) { ResqueUtil::log('Missing required arguments accountId or properties!'); return false; } $accountId = new \MongoId($args['accountId']); $property = $args['properties'][0]; $memberProperty = MemberProperty::findOne(['propertyId' => $property, 'accountId' => $accountId]); if (empty($memberProperty)) { ResqueUtil::log('Can not find member property with propertyId:' . $property); return false; } $date = empty($args['date']) ? '' : $args['date']; $date = TimeUtil::getDatetime($date); $month = date('Y-m', $date); $startDate = strtotime($month); $endDate = strtotime(date('Y-m', strtotime('+1 month', $date))); $raw = Member::getCollection()->aggregate([['$unwind' => '$properties'], ['$match' => ['createdAt' => ['$gte' => new \MongoDate($startDate), '$lt' => new \MongoDate($endDate)], 'properties.id' => $memberProperty->_id, 'accountId' => $accountId]], ['$group' => ['_id' => '$properties.value', 'total' => ['$sum' => 1]]]]); foreach ($raw as $item) { $total = $item['total']; $propValue = $item['_id']; // save the stats member property monthly $statsMemberPropMonthly = ModelStatsMemberPropMonthly::findOne(['propId' => $property, 'propValue' => $propValue, 'month' => $month, 'accountId' => $accountId]); if (empty($statsMemberPropMonthly)) { $statsMemberPropMonthly = new ModelStatsMemberPropMonthly(); $statsMemberPropMonthly->propId = $property; $statsMemberPropMonthly->propValue = $propValue; $statsMemberPropMonthly->month = $month; $statsMemberPropMonthly->accountId = $accountId; } $statsMemberPropMonthly->total = $total; ResqueUtil::log($statsMemberPropMonthly->attributes); $statsMemberPropMonthly->save(); } return true; }
/** * Get question option answer's stats info * @throws BadRequestHttpException * @return array, [{"option": "Yes", "count": 12}] */ public function actionAnswers() { $params = $this->getQuery(); if (empty($params['questionId'])) { throw new BadRequestHttpException(Yii::t('common', 'parameters_missing')); } $question = Question::findByPk(new MongoId($params['questionId'])); if (empty($question) || $question->type === Question::TYPE_INPUT) { throw new InvalidParameterException(Yii::t('content', 'invalid_question')); } //turn unix timestamp to string $startDateStr = isset($params['startTime']) ? TimeUtil::msTime2String($params['startTime'], 'Y-m-d') : null; $endDateStr = isset($params['endTime']) ? TimeUtil::msTime2String($params['endTime'], 'Y-m-d') : null; $stats = StatsQuestionnaireAnswerDaily::getQuestionOptionStats(new MongoId($params['questionId']), $startDateStr, $endDateStr); $statsMap = ArrayHelper::map($stats, 'option', 'count'); $options = []; $count = []; foreach ($question->options as $option) { $options[] = $option['content']; $count[] = empty($statsMap[$option['content']]) ? 0 : $statsMap[$option['content']]; } return ['options' => $options, 'count' => $count]; }
public function actionUpdate($id) { $campaign = Campaign::findByPk($id); if (empty($campaign)) { throw new BadRequestHttpException(Yii::t('product', 'campaign_not_found')); } if (MongodbUtil::isExpired($campaign->endTime)) { throw new BadRequestHttpException(Yii::t('product', 'can_not_update')); } $params = $this->getParams(); $params['startTime'] = empty($params['startTime']) ? $campaign->startTime : new \MongoDate(TimeUtil::ms2sTime($params['startTime'])); $params['endTime'] = empty($params['endTime']) ? $campaign->endTime : new \MongoDate(TimeUtil::ms2sTime($params['endTime'])); $attributeNames = null; foreach ($params as $key => $value) { if (in_array($key, ['productIds', 'gift', 'products', 'tags', 'channels'])) { $attributeNames[] = 'promotion'; $promotion = $campaign->promotion; $promotion['type'] = Campaign::TYPE_PROMOTION_CODE; $key == 'productIds' ? $promotion['data'] = $params['productIds'] : ''; $key == 'gift' ? $promotion['gift'] = $params['gift'] : ''; $key == 'products' ? $promotion['products'] = $params['products'] : ''; $key == 'tags' ? $promotion['tags'] = $params['tags'] : ''; $key == 'channels' ? $promotion['channels'] = $params['channels'] : ''; $campaign->promotion = $promotion; } else { if (in_array($key, ['participantCount', 'limitTimes'])) { $attributeNames[] = $key; $campaign->{$key} = is_null($value) ? null : intval($value); } else { $attributeNames[] = $key; $campaign->{$key} = $value; } } } $campaign->save(true, $attributeNames); return $campaign; }
public function actionStatistics() { $startTime = $this->getQuery('startTime'); $endTime = $this->getQuery('endTime'); $accountId = $this->getAccountId(); $condition = ['accountId' => $accountId, 'isDeleted' => BaseModel::NOT_DELETED]; if (!empty($startTime) && !empty($endTime)) { $condition['createdAt'] = ['$gt' => new \MongoDate(TimeUtil::ms2sTime($startTime)), '$lt' => new \MongoDate(TimeUtil::ms2sTime($endTime))]; } //get the original statistics from db.(raw data) $clientCount = ChatConversation::getClientCount($condition); $conversationCount = ChatConversation::count($condition); $clientMessageCount = ChatMessage::countClientMessage($condition); $conversationDailyStatistics = ChatConversation::getDailyData($condition); $messageDailyStatistics = ChatMessage::getDailyData($condition); //format the statistics for chart $categories = []; $messageCountSeries = []; $clientCountSeries = []; $conversationCountSeries = []; foreach ($conversationDailyStatistics as $conversationDay) { foreach ($messageDailyStatistics as $messageDay) { if ($conversationDay['date'] == $messageDay['date']) { $conversationDay['messageCount'] = $messageDay['messageCount']; } } if (empty($conversationDay['messageCount'])) { $conversationDay['messageCount'] = 0; } $categories[] = $conversationDay['date']; $messageCountSeries[] = $conversationDay['messageCount']; $clientCountSeries[] = $conversationDay['clientCount']; $conversationCountSeries[] = $conversationDay['conversationCount']; } $statistics = ['categories' => $categories, 'series' => [['name' => 'helpdesk_users_count', 'data' => $clientCountSeries], ['name' => 'helpdesk_sessions_count', 'data' => $conversationCountSeries], ['name' => 'helpdesk_sent_message_count', 'data' => $messageCountSeries]]]; return ['clientCount' => $clientCount, 'conversationCount' => $conversationCount, 'clientMessageCount' => $clientMessageCount, 'statistics' => $statistics]; }
public function actionUpdate($id) { $params = $this->getParams(); if (empty($params['status']) || !isset($params['price'])) { throw new BadRequestHttpException(Yii::t('common', 'parameters_missing')); } $storeGoods = StoreGoods::findByPk(new \MongoId($id)); if (empty($storeGoods)) { throw new InvalidParameterException(Yii::t('store', 'invalid_goods_id')); } $storeGoods->pictures = empty($params['pictures']) ? $storeGoods->pictures : $params['pictures']; $price = floatval($params['price']); if ($price <= 0) { throw new InvalidParameterException(Yii::t('store', 'price_error')); } $storeGoods->price = $price; if ($params['status'] == StoreGoods::STATUS_ON) { $storeGoods->status = StoreGoods::STATUS_ON; $storeGoods->onSaleTime = new \MongoDate(); } else { if ($params['status'] == StoreGoods::STATUS_OFF && isset($params['onSaleTime']) && $params['onSaleTime'] !== '') { if (time() > TimeUtil::ms2sTime($params['onSaleTime'])) { throw new InvalidParameterException(['onSaleTime' => \Yii::t('product', 'not_less_than_current')]); } else { $storeGoods->status = StoreGoods::STATUS_OFF; $storeGoods->onSaleTime = new \MongoDate(TimeUtil::ms2sTime($params['onSaleTime'])); } } else { if ($params['status'] == StoreGoods::STATUS_OFF && (!isset($params['onSaleTime']) || $params['onSaleTime'] === '')) { $storeGoods->status = StoreGoods::STATUS_OFF; $storeGoods->onSaleTime = null; $storeGoods->offShelfTime = new \MongoDate(); } else { throw new BadRequestHttpException(Yii::t('common', 'data_error')); } } } if ($storeGoods->save(true)) { $storeGoods->_id = (string) $storeGoods->_id; return $storeGoods; } else { throw new ServerErrorHttpException(Yii::t('common', 'save_fail')); } }
public function conver2MongoDate($attribute) { if ($attribute == 'startTime' || $attribute == 'endTime') { $time = $this->{$attribute}; if (!empty($time) && is_numeric($time)) { $this->{$attribute} = new MongoDate(TimeUtil::ms2sTime($time)); } } else { return true; } }
/** * Send Mass message * * <b>Request Type</b>: POST<br/><br/> * <b>Request Endpoint</b>:http://{server-domain}/api/channel/mass-messages<br/><br/> * <b>Content-type</b>: application/json<br/><br/> * <b>Summary</b>: This api is used for sending mass message. * <br/><br/> * * <b>Request Params</b>:<br/> * channelId: string<br/> * scheduleTime: long, the scheduled time, or empty which means to send right now<br/> * userQuery.tags: array<br/> * userQuery.gender: male, female or empty<br/> * userQuery.country: string<br/> * userQuery.province: string<br/> * userQuery.city: string<br/> * msgType: TEXT or MPNEWS<br/> * content: string, if TEXT<br/> * content.articles, if MPNEWS<br/> * mixed: bool<br/> * <br/><br/> * * <b>Response Params:</b><br/> * msg: string, if query fail, it contains the error message<br/> * <br/><br/> * * <br/><br/> * * <b>Response Example</b>:<br/> * <pre> * { * "message": "OK" * } * </pre> */ public function actionCreate() { $massmessage = $this->getParams(); $channelId = $this->getChannelId(); if (!empty($massmessage['scheduleTime']) && $massmessage['scheduleTime'] < TimeUtil::msTime()) { throw new InvalidParameterException(['schedule-picker' => Yii::t('channel', 'schedule_time_error')]); } unset($massmessage['channelId']); $result = Yii::$app->weConnect->createMassMessage($channelId, $massmessage); if ($result) { return ['message' => 'OK']; } else { throw new ServerErrorHttpException('Create mass message fail.'); } }
public function validateTime($attribute) { $time = $this->{$attribute}; $time = TimeUtil::ms2sTime($time); $this->{$attribute} = new \MongoDate($time); if ($attribute == 'startTime') { $now = time(); if ($time < $now) { throw new InvalidParameterException(['beginDatePicker' => \Yii::t('product', 'invalid_start_time')]); } } else { if ($attribute == 'endTime') { if ($time <= MongodbUtil::MongoDate2TimeStamp($this->startTime)) { throw new InvalidParameterException(['endDatePicker' => \Yii::t('product', 'invalid_end_time')]); } } } }
/** * Check bind. * * <b>Request Type</b>: GET<br/><br/> * <b>Request Endpoint</b>:http://{server-domain}/api/mobile/check-bind<br/><br/> * <b>Response Content-type</b>: application/json<br/><br/> * <b>Summary</b>: This api is used for check bind. * <br/><br/> * * <b>Request Params</b>:<br/> * <br/><br/> * * <b>Response Params:</b><br/> * redirect<br/> * <br/><br/> * * <br/><br/> * * <b>Response Example</b>:<br/> * <pre> * redirect('http://dev.cp.augmarketing.cn/mobile/center?openId=3DoTAN2jmRmInqhC_CDLN7aSTzvfzo') or * redirect('http://dev.cp.augmarketing.cn/mobile/center?memberId=549a73c3e9c2fb8d7c8b4569') * </pre> */ public function actionCheckBind($type = '', $param = '') { $params = $this->getQuery(); if (empty($params['state'])) { throw new BadRequestHttpException('missing params state'); } $channelId = $params['state']; $channelInfo = Yii::$app->weConnect->getAccounts($channelId); if (empty($channelInfo[0]['channel'])) { throw new BadRequestHttpException('invalid channelId'); } $userChannel = $channelInfo[0]['channel']; $redirect = !empty($type) ? base64_decode($param) : ''; $mainDomain = Yii::$app->request->hostInfo; if ($userChannel == Account::WECONNECT_CHANNEL_ALIPAY) { if (empty($params['auth_code'])) { throw new BadRequestHttpException('missing param auth_code'); } LogUtil::info(['params' => $params, 'channelId' => $channelId, 'message' => 'alipay info'], 'channel'); if ($params['scope'] == 'auth_userinfo') { $alipayUserInfo = Yii::$app->weConnect->getAlipayUserInfo($channelId, $params['auth_code']); $openId = $alipayUserInfo['originId']; } else { //call weconnect to get openId $openId = Yii::$app->weConnect->getAlipayOpenId($channelId, $params['auth_code']); } } else { if (empty($params['openId'])) { $openIdInfo = $this->getOriginAndOpenId($params); $origin = $openIdInfo['origin']; $openId = $openIdInfo['openId']; } else { $origin = Member::WECHAT; $openId = $params['openId']; } } //get member unionId from weconnect try { if (empty($alipayUserInfo)) { //to suport alipay,because alipay did not get followers again $follower = Yii::$app->weConnect->getFollowerByOriginId($openId, $channelId); } else { $follower = $alipayUserInfo; } } catch (ApiDataException $e) { LogUtil::info(['WeConnect Exception' => 'Get follower info error', 'exception' => $e], 'channel'); $follower = null; } //if follower not subscribed and (follower must subscribe before redirect or origin is weibo), redirect if ((empty($follower) || isset($follower['subscribed']) && $follower['subscribed'] != true) && ($this->mustSubscribe($redirect) || $origin === Member::WEIBO)) { return $this->redirect($this->getSubscribePage($origin, $channelId, $type, $redirect)); } //if the channel is alipay,we need to judge the member info whether exists,if the info is empty,wo call the first url if ($userChannel == Account::WECONNECT_CHANNEL_ALIPAY) { if (isset($follower['authorized']) && $follower['authorized'] == false) { if ($params['scope'] == 'auth_userinfo') { LogUtil::info(['message' => 'weConnect authorized fail', 'follower' => $follower], 'channel'); } else { $redirectUrl = $mainDomain . '/api/mobile/check-bind'; if (!empty($type) && !empty($param)) { $redirectUrl .= "/{$type}/{$param}"; } $redirectUrl .= '?state=' . $channelId . '&appId=' . $params['appId']; $redirectUrl = urlencode($redirectUrl); $url = "https://openauth.alipay.com/oauth2/publicAppAuthorize.htm?" . "app_id=" . $params['appId'] . "&auth_skip=false&scope=auth_userinfo&redirect_uri={$redirectUrl}"; LogUtil::info(['message' => 'can not get detailed follower info', 'url' => $url, 'follower' => $follower], 'channel'); return $this->redirect($url); } } else { LogUtil::info(['message' => 'authorized', 'follower' => $follower], 'channel'); } } if (!empty($follower['unionId'])) { //unionId exists $unionId = $follower['unionId']; $member = Member::getByUnionid($unionId); if (empty($member)) { //no unionId but openId $member = Member::getByOpenId($openId); if (!empty($member)) { $member->unionId = $unionId; $member->save(true, ['unionId']); } } } else { if (!empty($follower['originId'])) { $unionId = ''; $member = Member::getByOpenId($openId); } else { if (empty($follower) && !empty($params['appid']) && $userChannel == Account::WECONNECT_CHANNEL_WEIXIN) { LogUtil::info(['message' => 'Failed to get follower info', 'follower' => $follower, 'params' => $params]); $appId = $params['appid']; // not a follower, oAuth2.0 to get user_info $member = Member::getByOpenId($openId); if (empty($member)) { $component = Yii::$app->weConnect->getComponentToken(); $componentAppId = $component['componentAppId']; $state = $channelId; $redirectUrl = Yii::$app->request->hostInfo . '/api/mobile/user-info'; if (!empty($redirect)) { $redirectUrl = $redirectUrl . '/' . $type . '/' . $param; } LogUtil::info(['message' => 'oauth2 user_info redirecturl', 'url' => $redirectUrl]); $redirectUrl = urlencode($redirectUrl); $url = "https://open.weixin.qq.com/connect/oauth2/authorize?appid={$appId}&redirect_uri={$redirectUrl}&response_type=code&scope=snsapi_userinfo&state={$state}&component_appid={$componentAppId}#wechat_redirect"; return $this->redirect($url); } else { //member exists, will redirect to member center or 403 } } else { LogUtil::error(['Mobile member' => 'Failed to get follower info']); return $this->redirect('/mobile/common/403'); } } } LogUtil::info(['message' => 'Bind with follower', 'follower' => $follower], 'channel'); if (empty($member)) { //if not exist redirect, get unionId to bind //urlencode to avoid lose $redirect query string when frontend get $redirect $redirect = urlencode($redirect); $redirectUrl = $mainDomain . '/mobile/member'; if ($type == self::TYPE_REDIRECT) { $redirectUrl .= '/activate'; } else { $redirectUrl .= '/center'; } $redirectUrl .= "?openId={$openId}&channelId={$channelId}&unionId={$unionId}&redirect={$redirect}&redirectType={$type}"; } else { //if member is disabled, redirect to 403 if ($member->isDisabled) { return $this->redirect('/mobile/common/403'); } //if exist redirect to member center $social = ['channel' => $channelId, 'openId' => $openId, 'origin' => $origin, 'originScene' => empty($follower['firstSubscribeSource']) ? '' : $follower['firstSubscribeSource']]; $this->addNewSocial($member, $social); $memberId = $member['_id'] . ''; if ($type == self::TYPE_REDIRECT) { $str = strpos($redirect, '?') !== false ? '&' : '?'; $redirectUrl = $redirect . $str . "quncrm_member={$memberId}"; } else { $accountId = new \MongoId($member['accountId']); $token = Token::createForMobile($accountId); if (empty($token['accessToken'])) { throw new ServerErrorHttpException('Failed to create token for unknown reason.'); } $accessToken = $token['accessToken']; $this->setAccessToken($accessToken); if ($type == self::TYPE_REDIRECT_INSIDE) { $str = strpos($redirect, '?') !== false ? '&' : '?'; $redirectUrl = $redirect . $str . "memberId={$memberId}&channelId={$channelId}"; } else { $redirectUrl = $mainDomain . "/mobile/member/center?memberId={$memberId}&channelId={$channelId}"; if (!empty($member->cardExpiredAt) && $member->cardExpiredAt < TimeUtil::msTime()) { $redirectUrl = $redirectUrl . '&cardExpired=1'; } else { $redirectUrl = $redirectUrl . '&cardExpired=0'; } } } } return $this->redirect($redirectUrl); }
public static function refund($accountId, $refundInfo) { $refund = new self(); $refundNumber = StringUtil::getUniqueCode('refund', 'T'); $refund->transactionId = empty($refundInfo['transactionId']) ? '' : $refundInfo['transactionId']; $refund->refundNumber = $refundNumber; $refund->accountId = $accountId; $refund->orderNumber = $refundInfo['orderNumber']; $refund->expectedAmount = $refundInfo['expectedAmount']; $refund->realAmount = $refundInfo['realAmount']; $refund->admin = $refundInfo['admin']; $refund->user = $refundInfo['user']; $refund->refundMode = $refundInfo['refundMode']; $refund->refundAt = empty($refundInfo['refundAt']) ? new MongoDate() : new MongoDate(TimeUtil::ms2sTime($refundInfo['refundAt'])); $comments = empty($refundInfo['comments']) ? '' : $refundInfo['comments']; $refund->comments = $comments; $refund->subject = $refundInfo['subject']; return $refund->Save(); }