Esempio n. 1
0
 public function getContent($params = array())
 {
     $this->request->restrictAccess(Acl::RESOURCE_OWN_FARMS, Acl::PERM_FARMS_CREATE);
     $projects = [];
     if ($this->getContainer()->analytics->enabled && $this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID)) {
         $costCenter = $this->getContainer()->analytics->ccs->get($this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID));
         $currentYear = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y');
         $quarters = new Quarters(SettingEntity::getQuarters());
         $currentQuarter = $quarters->getQuarterForDate(new \DateTime('now', new \DateTimeZone('UTC')));
         if ($costCenter instanceof CostCentreEntity) {
             $projectsIterator = new SharedProjectsFilterIterator($costCenter->getProjects(), $costCenter->ccId, $this->user, $this->getEnvironment());
             foreach ($projectsIterator as $item) {
                 $quarterBudget = QuarterlyBudgetEntity::findOne([['year' => $currentYear], ['subjectType' => QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT], ['subjectId' => $item->projectId], ['quarter' => $currentQuarter]]);
                 $projects[] = array('projectId' => $item->projectId, 'name' => $item->name, 'budgetRemain' => !is_null($quarterBudget) && $quarterBudget->budget > 0 ? max(0, round($quarterBudget->budget - $quarterBudget->cumulativespend)) : null);
             }
             //$costCentreName = $costCenter->name;
             $isLocked = $costCenter->getProperty(CostCentrePropertyEntity::NAME_LOCKED);
             $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $this->environment->clientId], ['ccId' => $costCenter->ccId]]);
             if ($isLocked || !$accountCcs instanceof AccountCostCenterEntity) {
                 $costCentreLocked = 1;
             } else {
                 $costCentreLocked = 0;
             }
         } else {
             $costCentreName = '';
             $costCentreLocked = 0;
         }
     }
     return ['costCenterLocked' => $costCentreLocked, 'projects' => $projects];
 }
Esempio n. 2
0
 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');
 }
Esempio n. 3
0
 /**
  * Gets quarterly budget of specified year for the CC
  *
  * @param   int    $year   The year
  * @throws  \RuntimeException
  * @return  \Scalr\Model\Collections\ArrayCollection Returns collection of the QuarterlyBudgetEntity objects
  */
 public function getQuarterlyBudget($year)
 {
     if ($this->projectId === null) {
         throw new \RuntimeException(sprintf("Identifier of the cost center has not been initialized yet for %s", get_class($this)));
     }
     return QuarterlyBudgetEntity::getCcBudget($year, $this->ccId);
 }
Esempio n. 4
0
 /**
  * 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;
 }
Esempio n. 5
0
 /**
  * Gets project moving average to date
  *
  * @param   string|null $projectId    The identifier of the project
  * @param   string      $mode         The mode
  * @param   string      $date         The UTC date within period ('Y-m-d H:00')
  * @param   string      $startDate    The start date of the period in UTC ('Y-m-d')
  * @param   string      $endDate      The end date of the period in UTC ('Y-m-d')
  * @param   string      $ccId         optional The identifier of the cost center (It is used only when project is null)
  * @return  array       Returns project moving average to date
  * @throws  InvalidArgumentException
  * @throws  AnalyticsException
  */
 public function getProjectMovingAverageToDate($projectId, $mode, $date, $startDate, $endDate, $ccId = null)
 {
     $projectId = empty($projectId) ? null : $projectId;
     if (!preg_match('/^[\\d]{4}-[\\d]{2}-[\\d]{2} [\\d]{2}:00$/', $date)) {
         throw new InvalidArgumentException(sprintf("Invalid date:%s. 'YYYY-MM-DD HH:00' is expected.", strip_tags($date)));
     }
     if (!preg_match('/^[[:xdigit:]-]{36}$/', $projectId)) {
         throw new InvalidArgumentException(sprintf("Invalid identifier of the Project:%s. UUID is expected.", strip_tags($projectId)));
     }
     $iterator = ChartPeriodIterator::create($mode, $startDate, $endDate ?: null, 'UTC');
     //Interval which is used in the database query for grouping
     $queryInterval = preg_replace('/^1 /', '', $iterator->getInterval());
     if ($projectId !== null) {
         $project = ProjectEntity::findPk($projectId);
         if ($project === null) {
             if (empty($ccId)) {
                 throw new AnalyticsException(sprintf("Project %s does not exist. Please provide ccId.", $projectId));
             }
         } else {
             $ccId = $project->ccId;
         }
     }
     $data = $this->getRollingAvg(['projectId' => $projectId], $queryInterval, $date);
     $data['budgetUseToDate'] = null;
     $data['budgetUseToDatePct'] = null;
     //Does not calculate budget use to date for those cases
     if ($mode != 'custom' && $mode != 'year') {
         $pointPosition = $iterator->searchPoint($date);
         if ($pointPosition !== false) {
             $chartPoint = $iterator->current();
             //Gets the end date of the selected interval
             $end = clone $chartPoint->dt;
             if ($chartPoint->interval != '1 day') {
                 $end->modify("+" . $chartPoint->interval . " -1 day");
             }
             //Gets quarters config
             $quarters = new Quarters(SettingEntity::getQuarters());
             //Gets start and end of the quarter for the end date of the current interval
             $period = $quarters->getPeriodForDate($end);
             $data['year'] = $period->year;
             $data['quarter'] = $period->quarter;
             $data['quarterStartDate'] = $period->start->format('Y-m-d');
             $data['quarterEndDate'] = $period->end->format('Y-m-d');
             //Gets budgeted cost
             $budget = current(QuarterlyBudgetEntity::getProjectBudget($period->year, $projectId)->filterByQuarter($period->quarter));
             //If budget has not been set we should not calculate anything
             if ($budget instanceof QuarterlyBudgetEntity && round($budget->budget) > 0) {
                 $data['budget'] = round($budget->budget);
                 //Calculates usage from the start date of the quarter to date
                 $usage = $this->get(['projectId' => $projectId], $period->start, $end);
                 $data['budgetUseToDate'] = $usage['cost'];
                 $data['budgetUseToDatePct'] = $data['budget'] == 0 ? null : min(100, round($usage['cost'] / $data['budget'] * 100));
             }
         }
     }
     return ['data' => $data];
 }
Esempio n. 6
0
 private function getFarmCostData($farmId)
 {
     $result = [];
     $costCenter = $this->getContainer()->analytics->ccs->get($this->getEnvironment()->getPlatformConfigValue(Scalr_Environment::SETTING_CC_ID));
     $currentYear = (new \DateTime('now', new \DateTimeZone('UTC')))->format('Y');
     $quarters = new Quarters(SettingEntity::getQuarters());
     $currentQuarter = $quarters->getQuarterForDate(new \DateTime('now', new \DateTimeZone('UTC')));
     $projects = [];
     if ($farmId) {
         $farm = DBFarm::LoadByID($farmId);
         $currentProjectId = $farm->GetSetting(Entity\FarmSetting::PROJECT_ID);
         $currentProject = ProjectEntity::findPk($currentProjectId);
         /* @var $currentProject ProjectEntity */
         if (!empty($currentProject)) {
             $quarterBudget = QuarterlyBudgetEntity::findOne([['year' => $currentYear], ['subjectType' => QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT], ['subjectId' => $currentProject->projectId], ['quarter' => $currentQuarter]]);
             $projects[] = ['projectId' => $currentProject->projectId, 'name' => "{$currentProject->name} / {$currentProject->getCostCenter()->name}", 'budgetRemain' => !is_null($quarterBudget) && $quarterBudget->budget > 0 ? max(0, round($quarterBudget->budget - $quarterBudget->cumulativespend)) : null];
         }
         $result['projectId'] = $farm->GetSetting(Entity\FarmSetting::PROJECT_ID);
         $result['farmCostMetering'] = $result['projectId'] ? $this->getContainer()->analytics->usage->getFarmCostMetering($this->user->getAccountId(), $farmId) : null;
     }
     if ($costCenter instanceof CostCentreEntity) {
         $projectsIterator = new SharedProjectsFilterIterator($costCenter->getProjects(), $costCenter->ccId, $this->user, $this->getEnvironment());
         foreach ($projectsIterator as $item) {
             /* @var $item Scalr\Stats\CostAnalytics\Entity\ProjectEntity */
             if (!empty($currentProjectId) && $item->projectId == $currentProjectId) {
                 continue;
             }
             $quarterBudget = QuarterlyBudgetEntity::findOne([['year' => $currentYear], ['subjectType' => QuarterlyBudgetEntity::SUBJECT_TYPE_PROJECT], ['subjectId' => $item->projectId], ['quarter' => $currentQuarter]]);
             $projects[] = array('projectId' => $item->projectId, 'name' => "{$item->name} / {$costCenter->name}", 'budgetRemain' => !is_null($quarterBudget) && $quarterBudget->budget > 0 ? max(0, round($quarterBudget->budget - $quarterBudget->cumulativespend)) : null);
         }
         $costCentreName = $costCenter->name;
         $isLocked = $costCenter->getProperty(CostCentrePropertyEntity::NAME_LOCKED);
         $accountCcs = AccountCostCenterEntity::findOne([['accountId' => $this->environment->clientId], ['ccId' => $costCenter->ccId]]);
         if ($isLocked || !$accountCcs instanceof AccountCostCenterEntity) {
             $costCentreLocked = 1;
         } else {
             $costCentreLocked = 0;
         }
     } else {
         $costCentreName = '';
         $costCentreLocked = 0;
     }
     $supportedClouds = $this->getContainer()->analytics->prices->getSupportedClouds();
     $result['analytics'] = array('costCenterName' => $costCentreName, 'costCenterLocked' => $costCentreLocked, 'projects' => $projects, 'unsupportedClouds' => array_values(array_diff($this->environment->getEnabledPlatforms(), $supportedClouds)));
     return $result;
 }