예제 #1
0
 /**
  * {@inheritdoc}
  * @see \Scalr\System\Zmq\Cron\TaskInterface::enqueue()
  */
 public function enqueue()
 {
     if (!\Scalr::getContainer()->analytics->enabled) {
         $this->getLogger()->info("Terminating the process as Cost analytics is disabled in the config.\n");
         return new ArrayObject();
     }
     $this->getLogger()->info("%s (UTC) Start Analytics Notifications process", gmdate('Y-m-d'));
     $notifications = NotificationEntity::find();
     $this->getLogger()->info('Calculating data for projects and cost centers notifications');
     foreach ($notifications as $notification) {
         /* @var $notification NotificationEntity */
         if ($notification->status === NotificationEntity::STATUS_DISABLED) {
             continue;
         }
         if ($notification->subjectType === NotificationEntity::SUBJECT_TYPE_CC) {
             $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\CostCentre';
         } else {
             if ($notification->subjectType === NotificationEntity::SUBJECT_TYPE_PROJECT) {
                 $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\Project';
             }
         }
         if (!empty($notification->subjectId)) {
             $subject = call_user_func($subjectEntityName . 'Entity::findPk', $notification->subjectId);
             $this->saveNotificationData($subject, $notification);
         } else {
             $subjects = call_user_func($subjectEntityName . 'Entity::find');
             foreach ($subjects as $subject) {
                 if ($subject->archived) {
                     continue;
                 }
                 $this->saveNotificationData($subject, $notification);
             }
         }
     }
     $this->getLogger()->info('Calculating data for reports');
     $reports = ReportEntity::find();
     foreach ($reports as $report) {
         /* @var $report ReportEntity */
         if ($report->status === ReportEntity::STATUS_DISABLED) {
             continue;
         }
         switch ($report->period) {
             case ReportEntity::PERIOD_DAILY:
                 $period = 'custom';
                 $start = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->format('Y-m-d');
                 $end = $start;
                 $startForecast = (new \DateTime('first day of this month', new \DateTimeZone('UTC')))->format('Y-m-d');
                 $endForecast = (new \DateTime('last day of this month', new \DateTimeZone('UTC')))->format('Y-m-d');
                 if ($startForecast == (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y-m-d')) {
                     $startForecast = (new \DateTime('first day of last month', new \DateTimeZone('UTC')))->format('Y-m-d');
                     $endForecast = (new \DateTime('last day of last month', new \DateTimeZone('UTC')))->format('Y-m-d');
                 }
                 $periodForecast = 'month';
                 $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M j');
                 $formatedForecastDate = (new \DateTime($start, new \DateTimeZone('UTC')))->format('F');
                 break;
             case ReportEntity::PERIOD_MONTHLY:
                 $period = 'month';
                 $start = (new \DateTime('first day of last month', new \DateTimeZone('UTC')))->format('Y-m-d');
                 $end = (new \DateTime('last day of last month', new \DateTimeZone('UTC')))->format('Y-m-d');
                 $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M Y');
                 break;
             case ReportEntity::PERIOD_QUARTELY:
                 $period = 'quarter';
                 $quarters = new Quarters(SettingEntity::getQuarters());
                 $currentPeriod = $quarters->getPeriodForDate(new \DateTime('yesterday', new \DateTimeZone('UTC')));
                 $currentQuarter = $currentPeriod->quarter;
                 $currentYear = $currentPeriod->year;
                 if ($currentQuarter === 1) {
                     $quarter = 4;
                     $year = $currentYear - 1;
                 } else {
                     $quarter = $currentQuarter - 1;
                     $year = $currentYear;
                 }
                 $date = $quarters->getPeriodForQuarter($quarter, $year);
                 $start = $date->start->format('Y-m-d');
                 $end = $date->end->format('Y-m-d');
                 $formatedTitle = 'Q' . $quarter . ' ' . $year;
                 $formatedForecastDate = 'End of ' . $currentYear;
                 $forecastPeriod = $quarters->getPeriodForYear($year);
                 $startForecast = $forecastPeriod->start->format('Y-m-d');
                 $endForecast = $forecastPeriod->end->format('Y-m-d');
                 $periodForecast = 'year';
                 break;
             case ReportEntity::PERIOD_WEEKLY:
                 $period = 'week';
                 $end = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->modify('last saturday')->format('Y-m-d');
                 $start = (new \DateTime($end, new \DateTimeZone('UTC')))->modify('last sunday')->format('Y-m-d');
                 $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M j') . ' - ' . (new \DateTime($end, new \DateTimeZone('UTC')))->format('M j');
                 break;
         }
         if ($report->period !== ReportEntity::PERIOD_DAILY && $report->period !== ReportEntity::PERIOD_QUARTELY) {
             $quarters = new Quarters(SettingEntity::getQuarters());
             $currentPeriod = $quarters->getPeriodForDate(new \DateTime($start, new \DateTimeZone('UTC')));
             $currentQuarter = $currentPeriod->quarter;
             $currentYear = $currentPeriod->year;
             $date = $quarters->getPeriodForQuarter($currentQuarter, $currentYear);
             $formatedForecastDate = 'End of Q' . $currentQuarter;
             $startForecast = $date->start->format('Y-m-d');
             $endForecast = $date->end->format('Y-m-d');
             $periodForecast = 'quarter';
         }
         if ($report->subjectType === ReportEntity::SUBJECT_TYPE_CC) {
             $getPeriodicSubjectData = 'getCostCenterPeriodData';
             $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\CostCentre';
             $subjectId = 'ccId';
         } else {
             if ($report->subjectType === ReportEntity::SUBJECT_TYPE_PROJECT) {
                 $getPeriodicSubjectData = 'getProjectPeriodData';
                 $subjectEntityName = 'Scalr\\Stats\\CostAnalytics\\Entity\\Project';
                 $subjectId = 'projectId';
             } else {
                 $baseUrl = rtrim(\Scalr::getContainer()->config('scalr.endpoint.scheme') . "://" . \Scalr::getContainer()->config('scalr.endpoint.host'), '/');
                 $periodData = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($period, $start, $end);
                 $periodDataForecast = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($periodForecast, $startForecast, $endForecast);
                 $periodData['period'] = $period;
                 $periodData['forecastPeriod'] = $formatedForecastDate;
                 $periodData['totals']['forecastCost'] = $periodDataForecast['totals']['forecastCost'];
                 $periodData['name'] = 'Cloud Cost Report';
                 $periodData['jsonVersion'] = '1.0.0';
                 $periodData['detailsUrl'] = $baseUrl . '#/admin/analytics/dashboard';
                 $periodData['totals']['clouds'] = $this->changeCloudNames($periodData['totals']['clouds']);
                 $periodData['date'] = $formatedTitle;
                 $periodData['totals']['budget']['budget'] = null;
                 if ($period !== 'custom') {
                     $periodData['totals']['prevPeriodDate'] = (new \DateTime($periodData['previousStartDate'], new \DateTimeZone('UTC')))->format('M d') . " - " . (new \DateTime($periodData['previousEndDate'], new \DateTimeZone('UTC')))->format('M d');
                 } else {
                     $periodData['totals']['prevPeriodDate'] = (new \DateTime($periodData['previousEndDate'], new \DateTimeZone('UTC')))->format('M d');
                 }
                 if ($period == 'quarter') {
                     $periodData['totals']['budget'] = ['quarter' => $quarter, 'year' => $year, 'quarterStartDate' => $start, 'quarterEndDate' => $end];
                 } else {
                     if ($period == 'month') {
                         $periodData['totals']['budget'] = ['quarter' => $currentQuarter];
                     }
                 }
                 unset($periodData['projects'], $periodData['budget']['projects']);
                 if (count($periodData['costcenters'] > 1)) {
                     uasort($periodData['costcenters'], array($this, 'sortItems'));
                     if (count($periodData['costcenters'] > 6)) {
                         array_splice($periodData['costcenters'], 6, count($periodData['costcenters']));
                     }
                 }
                 if (count($periodData['totals']['clouds'] > 1)) {
                     usort($periodData['totals']['clouds'], array($this, 'sortItems'));
                 }
                 $entity = ReportPayloadEntity::init([$report->subjectType, $report->subjectId, $period], $periodData, $start);
                 if (!ReportPayloadEntity::findPk($entity->uuid)) {
                     $payload = json_decode($entity->payload, true);
                     \Scalr::getContainer()->mailer->setSubject('Summary report.')->setContentType('text/html')->sendTemplate(SCALR_TEMPLATES_PATH . '/emails/report_summary.html.php', $payload, $report->emails);
                     $this->getLogger()->info('Summary report email has been sent');
                     $payload['date'] = $entity->created->format('Y-m-d');
                     $entity->payload = json_encode($payload);
                     $entity->save();
                 }
             }
         }
         unset($currentQuarter, $currentYear);
         if (!empty($report->subjectType) && !empty($report->subjectId)) {
             $subject = call_user_func($subjectEntityName . 'Entity::findPk', $report->subjectId);
             if ($subject->archived) {
                 continue;
             }
             $this->saveReportData($getPeriodicSubjectData, $subjectEntityName, ['period' => $period, 'start' => $start, 'end' => $end], ['period' => $periodForecast, 'start' => $startForecast, 'end' => $endForecast], $report->subjectId, $report->subjectType, $report->emails, $formatedTitle, $formatedForecastDate);
         } else {
             if (!empty($report->subjectType)) {
                 $subjects = call_user_func($subjectEntityName . 'Entity::find');
                 foreach ($subjects as $subject) {
                     if ($subject->archived) {
                         continue;
                     }
                     $this->saveReportData($getPeriodicSubjectData, $subjectEntityName, ['period' => $period, 'start' => $start, 'end' => $end], ['period' => $periodForecast, 'start' => $startForecast, 'end' => $endForecast], $subject->{$subjectId}, $report->subjectType, $report->emails, $formatedTitle, $formatedForecastDate);
                 }
             }
         }
     }
     $this->getLogger()->info('Done');
     return new ArrayObject();
 }
예제 #2
0
파일: Budgets.php 프로젝트: scalr/scalr
 public function xSaveAction()
 {
     $this->request->defineParams(array('projectId' => ['type' => 'string'], 'year' => ['type' => 'int'], 'quarters' => ['type' => 'json'], 'selectedQuarter' => ['type' => 'string']));
     $year = $this->getParam('year');
     $selectedQuarter = $this->getParam('selectedQuarter');
     if ($selectedQuarter !== 'year' && ($selectedQuarter < 1 || $selectedQuarter > 4)) {
         throw new OutOfBoundsException(sprintf("Invalid selectedQuarter number."));
     }
     $quarterReq = [];
     foreach ($this->getParam('quarters') as $q) {
         if (!isset($q['quarter'])) {
             throw new InvalidArgumentException(sprintf("Missing quarter property for quarters data set in the request."));
         }
         if ($q['quarter'] < 1 || $q['quarter'] > 4) {
             throw new OutOfRangeException(sprintf("Quarter value should be between 1 and 4."));
         }
         if (!isset($q['budget'])) {
             throw new InvalidArgumentException(sprintf("Missing budget property for quarters data set in the request."));
         }
         $quarterReq[$q['quarter']] = $q;
     }
     if ($this->getParam('projectId')) {
         $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT;
         $subjectId = $this->getParam('projectId');
         $subjectEntity = ProjectEntity::findPk($subjectId);
         /* @var $subjectEntity ProjectEntity */
         if ($subjectEntity->accountId != $this->user->getAccountId() || $subjectEntity->shared != ProjectEntity::SHARED_WITHIN_ACCOUNT) {
             throw new Scalr_Exception_InsufficientPermissions();
         }
     } else {
         throw new InvalidArgumentException(sprintf('ProjectId must be provided with the request.'));
     }
     if (!preg_match("/^[[:xdigit:]-]{36}\$/", $subjectId)) {
         throw new InvalidArgumentException(sprintf("Invalid UUID has been passed."));
     }
     if (!preg_match('/^\\d{4}$/', $year)) {
         throw new InvalidArgumentException(sprintf("Invalid year has been passed."));
     }
     //Fetches the previous state of the entities from database
     $collection = QuarterlyBudgetEntity::getProjectBudget($year, $subjectId);
     $quarters = new Quarters(SettingEntity::getQuarters(true));
     //Updates|creates entities
     for ($quarter = 1; $quarter <= 4; ++$quarter) {
         if (!isset($quarterReq[$quarter])) {
             continue;
         }
         $period = $quarters->getPeriodForQuarter($quarter, $year);
         //Checks if period has already been closed and forbids update
         if ($period->end->format('Y-m-d') < gmdate('Y-m-d')) {
             continue;
         }
         $entity = current($collection->filterByQuarter($quarter));
         if ($entity instanceof QuarterlyBudgetEntity) {
             //We should update an entity
             $entity->budget = abs((double) $quarterReq[$quarter]['budget']);
         } else {
             //We should create a new one.
             $entity = new QuarterlyBudgetEntity($year, $quarter);
             $entity->subjectType = $subjectType;
             $entity->subjectId = $subjectId;
             $entity->budget = abs((double) $quarterReq[$quarter]['budget']);
         }
         $entity->save();
     }
     if ($selectedQuarter == 'year') {
         $selectedPeriod = $quarters->getPeriodForYear($year);
     } else {
         $selectedPeriod = $quarters->getPeriodForQuarter($selectedQuarter, $year);
     }
     $data = $this->getProjectData(ProjectEntity::findPk($subjectId), $selectedPeriod, true);
     $budgetInfo = $this->getBudgetInfo($year, $data['ccId'], $data['projectId']);
     $this->response->data(['data' => $data, 'budgetInfo' => $budgetInfo]);
     $this->response->success('Budget changes have been saved');
 }
예제 #3
0
 /**
  * Gets QuarterPeriod object which has the most days of this interval.
  *
  * @return  QuarterPeriod
  */
 public function getQuarterPeriod()
 {
     $quarters = new Quarters(SettingEntity::getQuarters());
     if ($this->mode == 'year') {
         //Takes the first day of the period interval to obtain yearly period object
         $p = $quarters->getPeriodForDate($this->getStart());
         $ret = $quarters->getPeriodForYear($p->year);
         return $ret;
     }
     $stat = [];
     $periods = [];
     $start = $this->getStart();
     $end = $this->getEnd();
     $fnstat = function ($p) use(&$stat, &$periods) {
         $key = $p->quarter . ',' . $p->year;
         if (!isset($stat[$key])) {
             $stat[$key] = 1;
             $periods[$key] = $p;
         } else {
             $stat[$key]++;
         }
     };
     $fnstat($quarters->getPeriodForDate($start));
     $fnstat($quarters->getPeriodForDate($end));
     $days = $start->diff($end, true)->days;
     //Divides inteval into four parts and examine the most relevant period for this interval.
     $interval = max(floor($days / 4), 1);
     while ($start <= $end) {
         $fnstat($quarters->getPeriodForDate($start));
         $start->modify('+1 day');
     }
     arsort($stat);
     return $periods[key($stat)];
 }