예제 #1
0
 protected function run1($stage)
 {
     $this->console->out('Initializing quarterly_budget data...');
     $quarters = new Quarters(SettingEntity::getQuarters());
     $currentYearPeriod = $quarters->getPeriodForDate();
     $currentFiscalYear = $currentYearPeriod->year;
     $prevFiscalYear = $currentFiscalYear - 1;
     $this->db->Execute("\n            UPDATE quarterly_budget b\n            SET b.`cumulativespend` = 0.000000\n            WHERE b.`year` = ? OR b.`year` = ?\n        ", [$currentFiscalYear, $prevFiscalYear]);
     foreach ([$prevFiscalYear, $currentFiscalYear] as $year) {
         for ($quarter = 1; $quarter <= 4; $quarter++) {
             $quarterPeriod = $quarters->getPeriodForQuarter($quarter, $year);
             $this->db->Execute("\n                    INSERT INTO quarterly_budget (`year`, `quarter`, `subject_type`, `subject_id`, `cumulativespend`)\n                    SELECT ?, u.`quarter`, u.`subject_type`, u.`subject_id`, u.`cumulativespend`\n                    FROM (\n                        SELECT ? AS `quarter`, ? AS `subject_type`, `cc_id` AS `subject_id`, SUM(`cost`) AS `cumulativespend`\n                        FROM usage_d\n                        WHERE `date` BETWEEN ? AND ?\n                        GROUP BY `cc_id`\n                        UNION ALL\n                        SELECT ? AS `quarter`, ? AS `subject_type`, `project_id` AS `subject_id`, SUM(`cost`) AS `cumulativespend`\n                        FROM usage_d\n                        WHERE `date` BETWEEN ? AND ?\n                        GROUP BY `project_id`\n                    ) AS u\n                    ON DUPLICATE KEY UPDATE\n                        `cumulativespend` = u.`cumulativespend`\n                ", [$year, $quarter, QuarterlyBudgetEntity::SUBJECT_TYPE_CC, $quarterPeriod->start->format('Y-m-d'), $quarterPeriod->end->format('Y-m-d'), $quarter, QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT, $quarterPeriod->start->format('Y-m-d'), $quarterPeriod->end->format('Y-m-d')]);
             $this->db->Execute("\n                    UPDATE quarterly_budget b\n                    JOIN (\n                        (SELECT SUM(`cost`) AS `cost`, `date`, `cc_id` AS `subject_id`\n                        FROM usage_d\n                        WHERE `date` BETWEEN ? AND ?\n                        GROUP BY `cc_id`, `date`)\n                        UNION ALL\n                        (SELECT SUM(`cost`) AS `cost`, `date`, `project_id` AS `subject_id`\n                        FROM usage_d\n                        WHERE `date` BETWEEN ? AND ?\n                        GROUP BY `project_id`, `date`)\n                        ORDER BY `date`\n                    ) AS ud ON b.subject_id = ud.`subject_id` AND b.`year` = ?\n                    SET b.`spentondate` = IF (\n                        b.`budget` > 0 AND b.`spentondate` IS NULL AND ud.`cost` >= b.`budget`,\n                        ud.`date`,\n                        b.`spentondate`\n                    )\n                    WHERE b.`quarter` = ?\n                ", [$quarterPeriod->start->format('Y-m-d'), $quarterPeriod->end->format('Y-m-d'), $quarterPeriod->start->format('Y-m-d'), $quarterPeriod->end->format('Y-m-d'), $year, $quarter]);
         }
     }
 }
예제 #2
0
 /**
  * @test
  * @dataProvider providerConstructor
  */
 public function testConstructor($days, $fixtures)
 {
     $quarters = new Quarters($days);
     foreach ($fixtures as $i => $v) {
         $this->assertEquals($v['quarter'], $quarters->getQuarterForDate($v['date']), sprintf('The number of the quarter for the date "%s" is expected to be %d.', $v['date'], $v['quarter']));
         $period = $quarters->getPeriodForQuarter($v['quarter'], $v['year']);
         $this->assertInternalType('object', $period);
         $this->assertEquals($v['start'], $period->start->format('Y-m-d'), sprintf('Start date is expected to be "%s".', $v['start']));
         $this->assertEquals($v['end'], $period->end->format('Y-m-d'), sprintf('End date is expected to be "%s".', $v['end']));
         $this->assertEquals($v['year'], $period->year);
         $this->assertEquals($v['quarter'], $period->quarter);
         $periodForDate = $quarters->getPeriodForDate(new DateTime($v['date'], new DateTimeZone('UTC')));
         $this->assertEquals($v['start'], $periodForDate->start->format('Y-m-d'), sprintf('getPeriodForDate for fixture#%d failed. Start date is expected to be "%s".', $i, $v['start']));
         $this->assertEquals($v['end'], $periodForDate->end->format('Y-m-d'), sprintf('getPeriodForDate for fixture#%d failed. End date is expected to be "%s".', $i, $v['end']));
         $this->assertEquals($v['year'], $periodForDate->year, sprintf('getPeriodForDate for fixture#%d failed. Year is expected to be "%s".', $i, $v['year']));
         $this->assertEquals($v['quarter'], $periodForDate->quarter, sprintf('getPeriodForDate for fixture#%d failed. Quarter is expected to be "%s".', $i, $v['quarter']));
     }
 }
예제 #3
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');
 }
 /**
  * {@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());
                 $currentQuarter = $quarters->getQuarterForDate(new \DateTime('yesterday', new \DateTimeZone('UTC')));
                 $currentYear = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->format('Y');
                 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;
                 $startForecast = $currentYear . '-01-01';
                 $endForecast = $currentYear . '-12-31';
                 $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());
             $currentQuarter = $quarters->getQuarterForDate(new \DateTime($start, new \DateTimeZone('UTC')));
             $currentYear = (new \DateTime($start, new \DateTimeZone('UTC')))->format('Y');
             $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 . '#/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();
 }
예제 #5
0
파일: Forecast.php 프로젝트: rickb838/scalr
 /**
  * Gets budget used percentage
  *
  * @param   array    $request  Request array should look like
  *                             ['projectId' => id, 'ccId' => id, 'period' => period, 'getRelationDependentBudget' => true]
  * @return  array
  * @throws  \InvalidArgumentException
  */
 public function getBudgetUsedPercentage($request)
 {
     $ret = [];
     if (!empty($request['projectId'])) {
         $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT;
         $subjectId = $request['projectId'];
     } else {
         if (!empty($request['ccId'])) {
             $subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_CC;
             $subjectId = $request['ccId'];
         }
     }
     $ret['budget'] = 0;
     $ret['budgetSpentPct'] = null;
     $ret['budgetSpent'] = 0;
     $ret['budgetRemain'] = null;
     $ret['budgetRemainPct'] = null;
     $ret['budgetOverspend'] = 0;
     $ret['budgetOverspendPct'] = 0;
     $ret['budgetSpentOnDate'] = null;
     $ret['budgetSpentThisPeriodPct'] = 0;
     $ret['quarter'] = null;
     $ret['year'] = null;
     $ret['quarterStartDate'] = null;
     $ret['quarterEndDate'] = null;
     //This is a rudiment as we use cumulativespend column everywhere
     $ret['budgetFinalSpent'] = 0;
     if (isset($subjectId)) {
         $period = isset($request['period']) ? $request['period'] : $this->_getCurrentPeriod();
         if (!$period instanceof QuarterPeriod) {
             throw new InvalidArgumentException(sprintf("Period must be instance of the Scalr\\Stats\\CostAnalytics\\QuarterPeriod class. %s given", gettype($period)));
         }
         $quarter = $period->quarter;
         $year = $period->year;
         $ret['quarter'] = $quarter;
         $ret['year'] = $year;
         $ret['quarterStartDate'] = $period->start->format('Y-m-d');
         $ret['quarterEndDate'] = $period->end->format('Y-m-d');
         $ret['closed'] = $ret['quarterEndDate'] < gmdate('Y-m-d');
         //Retrieves budget from database
         if ($quarter == 'year') {
             $quarters = new Quarters(SettingEntity::getQuarters());
             //Calculates total budgeted cost for the specified year
             $quarterlyBudget = new QuarterlyBudgetEntity();
             $quarterlyBudget->year = $year;
             $quarterlyBudget->subjectId = $subjectId;
             $quarterlyBudget->subjectType = $subjectType;
             $collection = QuarterlyBudgetEntity::find([['year' => $year], ['subjectType' => $subjectType], ['subjectId' => $subjectId]]);
             //List of the quarters which budget has not been set for
             $arrNotSet = [1, 2, 3, 4];
             foreach ($collection as $entity) {
                 $period = $quarters->getPeriodForQuarter($entity->quarter, $year);
                 //It shoud take into account only ongoing or future quarters without budget set
                 if ($entity->budget > 0 || $period->end->format('Y-m-d') < gmdate('Y-m-d')) {
                     if (isset($arrNotSet[$entity->quarter - 1])) {
                         unset($arrNotSet[$entity->quarter - 1]);
                     }
                 }
                 $quarterlyBudget->budget += $entity->budget;
                 $quarterlyBudget->cumulativespend += $entity->cumulativespend;
             }
             if (!empty($arrNotSet)) {
                 $ret['budgetAlert'] = "Budget has not been allocated for Q" . join(", Q", $arrNotSet);
             }
         } else {
             $quarterlyBudget = QuarterlyBudgetEntity::findPk($year, $subjectType, $subjectId, $quarter);
         }
         if ($quarterlyBudget instanceof QuarterlyBudgetEntity) {
             $ret['budget'] = round($quarterlyBudget->budget);
             $ret['budgetSpent'] = round($quarterlyBudget->cumulativespend);
             if ($ret['budget']) {
                 $ret['budgetOverspend'] = max(round($quarterlyBudget->cumulativespend - $quarterlyBudget->budget), 0);
                 $ret['budgetOverspendPct'] = round($ret['budgetOverspend'] / $ret['budget'] * 100);
             }
             $ret['budgetSpentPct'] = $ret['budget'] == 0 ? null : min(100, round($ret['budgetSpent'] / $ret['budget'] * 100));
             if (isset($request['usage'])) {
                 $ret['budgetSpentThisPeriodPct'] = $ret['budget'] == 0 ? null : min(100, round($request['usage'] / $ret['budget'] * 100));
             }
             $ret['budgetRemain'] = max(0, round($ret['budget'] - $ret['budgetSpent']));
             $ret['budgetRemainPct'] = $ret['budgetSpentPct'] !== null ? 100 - $ret['budgetSpentPct'] : null;
             if ($ret['closed']) {
                 $ret['costVariance'] = $ret['budgetSpent'] - $ret['budget'];
                 $ret['costVariancePct'] = $ret['budget'] == 0 ? null : round(abs($ret['costVariance']) / $ret['budget'] * 100);
             }
             $ret['budgetFinalSpent'] = round($quarterlyBudget->final);
             $ret['budgetSpentOnDate'] = $quarterlyBudget->spentondate instanceof DateTime ? $quarterlyBudget->spentondate->format('Y-m-d') : null;
             if (!empty($request['getRelationDependentBudget'])) {
                 if ($quarterlyBudget->subjectType != QuarterlyBudgetEntity::SUBJECT_TYPE_CC && isset($request['ccId'])) {
                     $ccQuarterlyBudget = clone $quarterlyBudget;
                     $ccQuarterlyBudget->subjectType = QuarterlyBudgetEntity::SUBJECT_TYPE_CC;
                     $ccQuarterlyBudget->subjectId = $request['ccId'];
                     $ret['relationDependentBudget'] = round($ccQuarterlyBudget->getRelationDependentBudget());
                     unset($ccQuarterlyBudget);
                 } else {
                     $ret['relationDependentBudget'] = round($quarterlyBudget->getRelationDependentBudget());
                 }
             }
         }
     }
     return $ret;
 }
예제 #6
0
파일: Forecast.php 프로젝트: mheydt/scalr
 /**
  * Returns iterator for current quarter
  *
  * @return Iterator\ChartQuarterlyIterator
  */
 public function getCurrentQuarterIterator()
 {
     $quarters = new Quarters(SettingEntity::getQuarters());
     $currentQuarter = $quarters->getQuarterForDate(new \DateTime('now', new \DateTimeZone('UTC')));
     $currentYear = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y');
     if ($currentQuarter === 1) {
         $quarter = 4;
         $year = $currentYear - 1;
     } else {
         $quarter = $currentQuarter - 1;
         $year = $currentYear;
     }
     $date = $quarters->getPeriodForQuarter($quarter, $year);
     $iterator = ChartPeriodIterator::create('quarter', $date->start, $date->end, 'UTC');
     return $iterator;
 }
 /**
  * {@inheritdoc}
  * @see \Scalr\System\Pcntl\ProcessInterface::OnStartForking()
  */
 public function OnStartForking()
 {
     if (!\Scalr::getContainer()->analytics->enabled) {
         die("Terminating the process as Cost analytics is disabled in the config.\n");
     }
     $this->console->out("%s (UTC) Start Analytics Notifications process", gmdate('Y-m-d'));
     if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_CCS_ENABLED) || SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_PROJECTS_ENABLED)) {
         $this->console->out('Calculating data for projects notifications');
         $quarters = new Quarters(SettingEntity::getQuarters());
         $date = $quarters->getPeriodForDate('yesterday');
         $formatedTitle = 'Q' . $quarters->getQuarterForDate('now') . ' budget (' . (new \DateTime('now', new \DateTimeZone('UTC')))->format('M j, Y') . ')';
         $projects = ProjectEntity::find();
         foreach ($projects as $project) {
             $periodProjectData = \Scalr::getContainer()->analytics->usage->getProjectPeriodData($project->projectId, 'quarter', $date->start->format('Y-m-d'), $date->end->format('Y-m-d'));
             $projectAnalytics[$project->projectId] = ['budget' => $periodProjectData['totals']['budget'], 'name' => $project->name, 'trends' => $periodProjectData['totals']['trends'], 'forecastCost' => $periodProjectData['totals']['forecastCost'], 'interval' => $periodProjectData['interval'], 'jsonVersion' => '1.0.0', 'farms' => []];
             if (!empty($periodProjectData['totals']['farms'])) {
                 foreach ($periodProjectData['totals']['farms'] as $farm) {
                     $projectAnalytics[$project->projectId]['farms'][] = ['id' => $farm['id'], 'name' => $farm['name'], 'median' => $farm['median'] / 7, 'cost' => $farm['cost'], 'costPct' => $farm['costPct']];
                 }
                 if (count($projectAnalytics[$project->projectId]['farms'] > 1)) {
                     usort($projectAnalytics[$project->projectId]['farms'], array($this, 'sortItems'));
                     if (count($projectAnalytics[$project->projectId]['farms'] > 6)) {
                         array_splice($projectAnalytics[$project->projectId]['farms'], 6, count($projectAnalytics[$project->projectId]['farms']));
                     }
                 }
             }
             $projectAnalytics[$project->projectId]['date'] = $formatedTitle;
             if ($project->archived) {
                 continue;
             }
             if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_PROJECTS_ENABLED)) {
                 $projectNotifications = NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_PROJECT);
                 foreach ($projectNotifications as $notification) {
                     $this->saveNotificationData('project', $notification, $project->projectId, $projectAnalytics);
                 }
             }
         }
     }
     if (SettingEntity::getValue(SettingEntity::ID_NOTIFICATIONS_CCS_ENABLED)) {
         $this->console->out('Calculating data for cost center notifications');
         $ccs = CostCentreEntity::find();
         foreach ($ccs as $cc) {
             if ($cc->archived) {
                 continue;
             }
             $periodCostCenterData = \Scalr::getContainer()->analytics->usage->getCostCenterPeriodData($cc->ccId, 'quarter', $date->start->format('Y-m-d'), $date->end->format('Y-m-d'));
             $ccAnalytics[$cc->ccId] = ['budget' => $periodCostCenterData['totals']['budget'], 'name' => $cc->name, 'trends' => $periodCostCenterData['totals']['trends'], 'forecastCost' => $periodCostCenterData['totals']['forecastCost'], 'interval' => $periodCostCenterData['interval'], 'jsonVersion' => '1.0.0', 'projects' => []];
             if (!empty($periodCostCenterData['totals']['projects'])) {
                 foreach ($periodCostCenterData['totals']['projects'] as $key => $project) {
                     if (!empty($project['id'])) {
                         $projectBudget = $projectAnalytics[$project['id']]['budget'];
                         $projectBudget['name'] = $project['name'];
                         $projectBudget['id'] = $project['id'];
                         $projectBudget['median'] = $project['median'] / 7;
                         $ccAnalytics[$cc->ccId]['projects'][] = $projectBudget;
                     } else {
                         $otherProjectsKey = $key;
                     }
                 }
                 if (isset($otherProjectsKey)) {
                     $ccAnalytics[$cc->ccId]['projects'][] = ['id' => '', 'budgetSpent' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['cost'], 'median' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['median'] / 7, 'name' => $periodCostCenterData['totals']['projects'][$otherProjectsKey]['name'], 'estimateOverspend' => null];
                     unset($otherProjectsKey);
                 }
                 if (count($ccAnalytics[$cc->ccId]['projects'] > 1)) {
                     usort($ccAnalytics[$cc->ccId]['projects'], array($this, 'sortItems'));
                     if (count($ccAnalytics[$cc->ccId]['projects'] > 6)) {
                         array_splice($ccAnalytics[$cc->ccId]['projects'], 6, count($ccAnalytics[$cc->ccId]['projects']));
                     }
                 }
             }
             $ccAnalytics[$cc->ccId]['date'] = $formatedTitle;
             $ccsNotifications = NotificationEntity::findBySubjectType(NotificationEntity::SUBJECT_TYPE_CC);
             foreach ($ccsNotifications as $notification) {
                 $this->saveNotificationData('cc', $notification, $cc->ccId, $ccAnalytics);
             }
         }
     }
     if (SettingEntity::getValue(SettingEntity::ID_REPORTS_ENABLED)) {
         $this->console->out('Calculating data for reports');
         $reports = ReportEntity::find();
         foreach ($reports as $report) {
             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');
                     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');
                     $quarters = new Quarters(SettingEntity::getQuarters());
                     $currentQuarter = $quarters->getQuarterForDate(new \DateTime($start, new \DateTimeZone('UTC')));
                     $currentYear = (new \DateTime($start, new \DateTimeZone('UTC')))->format('Y');
                     $date = $quarters->getPeriodForQuarter($currentQuarter, $currentYear);
                     $formatedTitle = (new \DateTime($start, new \DateTimeZone('UTC')))->format('M Y');
                     $startForecast = $date->start->format('Y-m-d');
                     $endForecast = $date->end->format('Y-m-d');
                     $periodForecast = 'quarter';
                     break;
                 case ReportEntity::PERIOD_QUARTELY:
                     $period = 'quarter';
                     $quarters = new Quarters(SettingEntity::getQuarters());
                     $currentQuarter = $quarters->getQuarterForDate(new \DateTime('yesterday', new \DateTimeZone('UTC')));
                     $currentYear = (new \DateTime('yesterday', new \DateTimeZone('UTC')))->format('Y');
                     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;
                     $startForecast = $currentYear . '-01-01';
                     $endForecast = $currentYear . '-12-31';
                     $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');
                     $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';
                     break;
             }
             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 {
                     $periodData = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($period, $start, $end);
                     $periodDataForecast = \Scalr::getContainer()->analytics->usage->getDashboardPeriodData($periodForecast, $startForecast, $endForecast);
                     $periodData['period'] = $period;
                     $periodData['forecastPeriod'] = $periodForecast;
                     $periodData['totals']['forecastCost'] = $periodDataForecast['totals']['forecastCost'];
                     $periodData['totals']['trends'] = $periodDataForecast['totals']['trends'];
                     $periodData['name'] = 'Cloud Cost Report';
                     $periodData['jsonVersion'] = '1.0.0';
                     $periodData['totals']['clouds'] = $this->changeCloudNames($periodData['totals']['clouds']);
                     $periodData['date'] = $formatedTitle;
                     $periodData['totals']['budget']['budget'] = null;
                     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->console->out('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);
             } 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);
                     }
                 }
             }
         }
     }
     $this->console->out('Done');
     exit;
 }