Budget graph in project details (#3406)
* do not copy description if restarting via calendar * added support to display negative durations * fix charts for larger numbers
This commit is contained in:
@@ -392,15 +392,16 @@ class ProjectStatisticService
|
||||
$model = new ProjectDetailsModel($project);
|
||||
$model->setBudgetStatisticModel($this->getBudgetStatisticModel($project, $query->getToday()));
|
||||
|
||||
$years = [];
|
||||
$qb = $this->timesheetRepository->createQueryBuilder('t');
|
||||
$qb
|
||||
->select('COALESCE(SUM(t.duration), 0) as duration')
|
||||
->addSelect('COALESCE(SUM(t.rate), 0) as rate')
|
||||
->addSelect('COALESCE(SUM(t.internalRate), 0) as internalRate')
|
||||
->addSelect('COUNT(t.id) as count')
|
||||
->addSelect('t.billable as billable')
|
||||
->andWhere('t.project = :project')
|
||||
->setParameter('project', $query->getProject())
|
||||
->addGroupBy('billable')
|
||||
;
|
||||
|
||||
// fetch stats grouped by ACTIVITY for all time
|
||||
@@ -410,13 +411,31 @@ class ProjectStatisticService
|
||||
->addSelect('a as activity')
|
||||
->addGroupBy('a')
|
||||
;
|
||||
|
||||
/** @var array<ActivityStatistic> $activities */
|
||||
$activities = [];
|
||||
foreach ($qb1->getQuery()->getResult() as $tmp) {
|
||||
$activity = new ActivityStatistic();
|
||||
$activity->setActivity($tmp['activity']);
|
||||
$activity->setRecordRate($tmp['rate']);
|
||||
$activity->setRecordDuration($tmp['duration']);
|
||||
$activity->setRecordInternalRate($tmp['internalRate']);
|
||||
$activity->setCounter($tmp['count']);
|
||||
$activityId = $tmp['activity']->getId();
|
||||
if (!\array_key_exists($activityId, $activities)) {
|
||||
$activity = new ActivityStatistic();
|
||||
$activity->setActivity($tmp['activity']);
|
||||
$activities[$activityId] = $activity;
|
||||
} else {
|
||||
$activity = $activities[$activityId];
|
||||
}
|
||||
|
||||
$activity->setRecordRate($activity->getRecordRate() + $tmp['rate']);
|
||||
$activity->setRecordDuration($activity->getRecordDuration() + $tmp['duration']);
|
||||
$activity->setInternalRate($activity->getInternalRate() + $tmp['internalRate']);
|
||||
$activity->setCounter($activity->getCounter() + $tmp['count']);
|
||||
|
||||
if ($tmp['billable']) {
|
||||
$activity->setDurationBillable($activity->getDurationBillable() + $tmp['duration']);
|
||||
$activity->setRateBillable($activity->getRateBillable() + $tmp['rate']);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($activities as $activity) {
|
||||
$model->addActivity($activity);
|
||||
}
|
||||
// ---------------------------------------------------
|
||||
@@ -438,6 +457,7 @@ class ProjectStatisticService
|
||||
if (!empty($userIds)) {
|
||||
$qb2 = $this->userRepository->createQueryBuilder('u');
|
||||
$qb2->select('u')->where($qb2->expr()->in('u.id', $userIds));
|
||||
/** @var array<int, UserStatistic> $users */
|
||||
$users = [];
|
||||
foreach ($qb2->getQuery()->getResult() as $user) {
|
||||
$users[$user->getId()] = new UserStatistic($user);
|
||||
@@ -448,31 +468,95 @@ class ProjectStatisticService
|
||||
$year = $model->getUserYear($tmp['year'], $user);
|
||||
if ($year === null) {
|
||||
$year = new Year($tmp['year']);
|
||||
for ($i = 1; $i < 13; $i++) {
|
||||
$year->setMonth(new Month($i));
|
||||
}
|
||||
$model->setUserYear($year, $user);
|
||||
}
|
||||
$month = new Month($tmp['month']);
|
||||
$month->setTotalRate($tmp['rate']);
|
||||
$month->setTotalDuration($tmp['duration']);
|
||||
$month->setTotalInternalRate($tmp['internalRate']);
|
||||
$year->setMonth($month);
|
||||
$users[$tmp['user']]->addValuesFromMonth($month);
|
||||
$month = $year->getMonth($tmp['month']);
|
||||
if ($month === null) {
|
||||
$month = new Month($tmp['month']);
|
||||
$year->setMonth($month);
|
||||
}
|
||||
$month->setTotalRate($month->getTotalRate() + $tmp['rate']);
|
||||
$month->setTotalDuration($month->getTotalDuration() + $tmp['duration']);
|
||||
$month->setTotalInternalRate($month->getTotalInternalRate() + $tmp['internalRate']);
|
||||
|
||||
if ($tmp['billable']) {
|
||||
$month->setBillableDuration($month->getBillableDuration() + $tmp['duration']);
|
||||
$month->setBillableRate($month->getBillableRate() + $tmp['rate']);
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($users as $userId => $statistic) {
|
||||
foreach ($model->getYears() as $year) {
|
||||
$statYear = $model->getUserYear($year->getYear(), $statistic->getUser());
|
||||
if ($statYear === null) {
|
||||
continue;
|
||||
}
|
||||
foreach ($statYear->getMonths() as $month) {
|
||||
$statistic->addValuesFromMonth($month);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------
|
||||
|
||||
$years = [];
|
||||
|
||||
// make sure that we have all month between project start and end
|
||||
if ($project->getStart() !== null) {
|
||||
if ($project->getEnd() !== null) {
|
||||
$end = clone $project->getEnd();
|
||||
} else {
|
||||
$end = clone $query->getToday();
|
||||
$end->setDate((int) $end->format('Y'), 12, 31);
|
||||
}
|
||||
|
||||
$start = clone $project->getStart();
|
||||
$start->setDate((int) $start->format('Y'), (int) $start->format('m'), 1);
|
||||
$start->setTime(0, 0, 0);
|
||||
|
||||
while ($start !== false && $start < $end) {
|
||||
$year = $start->format('Y');
|
||||
if (!\array_key_exists($year, $years)) {
|
||||
$years[$year] = new Year($year);
|
||||
}
|
||||
$tmp = $years[$year];
|
||||
$tmp->setMonth(new Month($start->format('m')));
|
||||
$start = $start->modify('+1 month');
|
||||
}
|
||||
}
|
||||
|
||||
// fetch stats grouped by YEARS
|
||||
$qb1 = clone $qb;
|
||||
$qb1
|
||||
->addSelect('YEAR(t.date) as year')
|
||||
->addGroupBy('year')
|
||||
;
|
||||
foreach ($qb1->getQuery()->getResult() as $year) {
|
||||
$tmp = new Year($year['year']);
|
||||
$tmp->setTotalRate($year['rate']);
|
||||
$tmp->setTotalInternalRate($year['internalRate']);
|
||||
$tmp->setTotalDuration($year['duration']);
|
||||
$years[$year['year']] = $tmp;
|
||||
|
||||
foreach ($qb1->getQuery()->getResult() as $year) {
|
||||
if (!\array_key_exists($year['year'], $years)) {
|
||||
$tmp = new Year($year['year']);
|
||||
for ($i = 1; $i < 13; $i++) {
|
||||
$tmp->setMonth(new Month($i));
|
||||
}
|
||||
$years[$year['year']] = $tmp;
|
||||
} else {
|
||||
$tmp = $years[$year['year']];
|
||||
}
|
||||
$tmp->setTotalRate($tmp->getTotalRate() + $year['rate']);
|
||||
$tmp->setTotalInternalRate($tmp->getTotalInternalRate() + $year['internalRate']);
|
||||
$tmp->setTotalDuration($tmp->getTotalDuration() + $year['duration']);
|
||||
|
||||
if ($year['billable']) {
|
||||
$tmp->setBillableDuration($tmp->getBillableDuration() + $year['duration']);
|
||||
$tmp->setBillableRate($tmp->getBillableRate() + $year['rate']);
|
||||
}
|
||||
}
|
||||
|
||||
$yearActivities = [];
|
||||
foreach ($years as $yearName => $yearStat) {
|
||||
// fetch yearly stats grouped by ACTIVITY and YEAR
|
||||
$qb2 = clone $qb;
|
||||
$qb2
|
||||
@@ -480,20 +564,41 @@ class ProjectStatisticService
|
||||
->addSelect('a as activity')
|
||||
->addSelect('YEAR(t.date) as year')
|
||||
->andWhere('YEAR(t.date) = :year')
|
||||
->setParameter('year', $year['year'])
|
||||
->setParameter('year', $yearName)
|
||||
->addGroupBy('year')
|
||||
->addGroupBy('a')
|
||||
;
|
||||
|
||||
foreach ($qb2->getQuery()->getResult() as $tmp) {
|
||||
$activity = new ActivityStatistic();
|
||||
$activity->setActivity($tmp['activity']);
|
||||
$activity->setRecordRate($tmp['rate']);
|
||||
$activity->setRecordDuration($tmp['duration']);
|
||||
$activity->setRecordInternalRate($tmp['internalRate']);
|
||||
$activity->setCounter($tmp['count']);
|
||||
$model->addYearActivity($tmp['year'], $activity);
|
||||
$activityId = $tmp['activity']->getId();
|
||||
if (!\array_key_exists($yearName, $yearActivities)) {
|
||||
$yearActivities[$yearName] = [];
|
||||
}
|
||||
if (!\array_key_exists($activityId, $yearActivities[$yearName])) {
|
||||
$activity = new ActivityStatistic();
|
||||
$activity->setActivity($tmp['activity']);
|
||||
$yearActivities[$yearName][$activityId] = $activity;
|
||||
} else {
|
||||
$activity = $yearActivities[$yearName][$activityId];
|
||||
}
|
||||
$activity->setRecordRate($activity->getRecordRate() + $tmp['rate']);
|
||||
$activity->setRecordDuration($activity->getRecordDuration() + $tmp['duration']);
|
||||
$activity->setInternalRate($activity->getInternalRate() + $tmp['internalRate']);
|
||||
$activity->setCounter($activity->getCounter() + $tmp['count']);
|
||||
|
||||
if ($tmp['billable']) {
|
||||
$activity->setDurationBillable($activity->getDurationBillable() + $tmp['duration']);
|
||||
$activity->setRateBillable($activity->getRateBillable() + $tmp['rate']);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($yearActivities as $year => $activities) {
|
||||
foreach ($activities as $activity) {
|
||||
$model->addYearActivity($year, $activity);
|
||||
}
|
||||
}
|
||||
|
||||
$model->setYears(array_values($years));
|
||||
// ---------------------------------------------------
|
||||
|
||||
@@ -506,11 +611,19 @@ class ProjectStatisticService
|
||||
->addGroupBy('month')
|
||||
;
|
||||
foreach ($qb1->getQuery()->getResult() as $month) {
|
||||
$tmp = new Month($month['month']);
|
||||
$tmp->setTotalRate($month['rate']);
|
||||
$tmp->setTotalInternalRate($month['internalRate']);
|
||||
$tmp->setTotalDuration($month['duration']);
|
||||
$model->getYear($month['year'])->setMonth($tmp);
|
||||
$tmp = $model->getYear($month['year'])->getMonth($month['month']);
|
||||
if ($tmp === null) {
|
||||
$tmp = new Month($month['month']);
|
||||
$model->getYear($month['year'])->setMonth($tmp);
|
||||
}
|
||||
$tmp->setTotalRate($tmp->getTotalRate() + $month['rate']);
|
||||
$tmp->setTotalInternalRate($tmp->getTotalInternalRate() + $month['internalRate']);
|
||||
$tmp->setTotalDuration($tmp->getTotalDuration() + $month['duration']);
|
||||
|
||||
if ($month['billable']) {
|
||||
$tmp->setBillableDuration($tmp->getBillableDuration() + $month['duration']);
|
||||
$tmp->setBillableRate($tmp->getBillableRate() + $month['rate']);
|
||||
}
|
||||
}
|
||||
// ---------------------------------------------------
|
||||
|
||||
|
||||
Reference in New Issue
Block a user