Refactor goals_criteria and goals_progress_alert_renderer for improved department filtering and summary rendering
- Add cloning logic in `withDepartmentFilter` to avoid mutating original `goals_criteria` objects. - Rename method parameter in `render` and refactor `renderDanishPeriodSummary` for enhanced readability and flexibility. - Introduce helper methods for date range and criteria window adjustments to streamline department progress calculations.
This commit is contained in:
@@ -637,7 +637,9 @@ class goals_criteria implements goals_criteria_i
|
||||
|
||||
public function withDepartmentFilter(int $department_id): goals_criteria
|
||||
{
|
||||
// Clone the criteria and create a fresh departments collection to avoid mutating the original
|
||||
$new_criteria = clone $this;
|
||||
$new_criteria->departments = new goals_criteria_departments();
|
||||
$new_criteria->departments->set([(new \objects\departments_o())->select($department_id)]);
|
||||
return $new_criteria;
|
||||
}
|
||||
|
||||
@@ -13,7 +13,7 @@ use objects\departments_o;
|
||||
|
||||
class goals_progress_alert_renderer
|
||||
{
|
||||
public static function render(goals_criteria $criteria, ?departments_o $department = null): string
|
||||
public static function render(goals_criteria $criteria, ?departments_o $department_to_highlight = null): string
|
||||
{
|
||||
$label = (string)($criteria->label ?? 'Goal');
|
||||
$count = (int)self::getProgress($criteria);
|
||||
@@ -28,7 +28,7 @@ class goals_progress_alert_renderer
|
||||
// Prepare readable names for fields
|
||||
$departmentsList = $criteria->departments?->list() ?? [];
|
||||
$usersList = $criteria->users?->list() ?? [];
|
||||
$productsList = $criteria->products?->list() ?? [];
|
||||
$productsList = $criteria->products?->list() ?? [];
|
||||
|
||||
$deptNames = self::commaNamesFromObjects($departmentsList, 'department');
|
||||
$customerNames = self::commaNamesFromObjects($usersList, 'user');
|
||||
@@ -53,13 +53,13 @@ class goals_progress_alert_renderer
|
||||
$deptNames !== '' ? "$deptLabel: $deptNames" : null,
|
||||
$customerNames !== '' ? "$customerLabel: $customerNames" : null,
|
||||
$productNames !== '' ? "$productLabel: $productNames" : null,
|
||||
], department: $department),
|
||||
], department: $department_to_highlight),
|
||||
PType::ALL => self::renderDanishPeriodSummary($criteria, includeTargets: $target > 0,
|
||||
header: [
|
||||
$deptNames !== '' ? "$deptLabel: $deptNames" : null,
|
||||
$customerNames !== '' ? "$customerLabel: $customerNames" : null,
|
||||
$productNames !== '' ? "$productLabel: $productNames" : null,
|
||||
], department: $department),
|
||||
], department: $department_to_highlight),
|
||||
// Legacy single-line fallbacks
|
||||
PType::PERCENTAGE_ONLY => sprintf('Progress: %s%%', number_format($percent, 2)),
|
||||
PType::COUNT_AND_TARGET => sprintf('Progress: %d / %d', $count, $target),
|
||||
@@ -124,69 +124,175 @@ class goals_progress_alert_renderer
|
||||
return 0;
|
||||
}
|
||||
|
||||
private static function renderDanishPeriodSummary(goals_criteria $criteria, bool $includeTargets, array $header = [], ?departments_o $department = null): string
|
||||
private static function renderDanishPeriodSummary(
|
||||
goals_criteria $criteria,
|
||||
bool $includeTargets,
|
||||
?array $header = null,
|
||||
?departments_o $department = null
|
||||
): string
|
||||
{
|
||||
/**
|
||||
* > Afdelinger: Taulov, Taastrup
|
||||
* > Kunder: DHL FREIGHT (DENMARK ONLY) A/S, DHL FREIGHT (Trailer Danmark NTP), DHL FREIGHT (Trailere Finland NTP), DHL FREIGHT (Trailere Sverige NTP)
|
||||
* > Produkt: Trailer
|
||||
* > Igår: 4
|
||||
* > Heraf:
|
||||
* > - Taastrup: 2
|
||||
* > - Taulov: 2
|
||||
* > Ugen total: 9
|
||||
* > Heraf:
|
||||
* > - Taastrup: 7
|
||||
* > - Taulov: 2
|
||||
* > Måneden total: 15
|
||||
* > Heraf:
|
||||
* > - Taastrup: 10
|
||||
* > - Taulov: 5
|
||||
* Renders a Danish multi-line progress summary for yesterday, week-to-date, and month-to-date.
|
||||
* If $includeTargets is true and a target is set, shows progress as "X ud af Y (Z%)".
|
||||
* Otherwise, shows just the raw counts.
|
||||
* It should display like this:
|
||||
* {$departmentName}:
|
||||
* Igår: 5 ud af 10 (50%)
|
||||
* Ugen total: 20 ud af 50 (40%)
|
||||
* Måneden total: 75 ud af 100 (75%)
|
||||
*/
|
||||
// Build period windows
|
||||
$now = new \DateTimeImmutable('now');
|
||||
$yesterdayStart = $now->modify('-1 day')->setTime(0, 0, 0);
|
||||
$yesterdayEnd = $now->modify('-1 day')->setTime(23, 59, 59);
|
||||
|
||||
// Week start (Monday) to now
|
||||
$weekStart = (new \DateTimeImmutable('monday this week'))->setTime(0, 0, 0);
|
||||
if ($now->format('N') === '1') { // if Monday, "monday this week" is today, ok
|
||||
$weekStart = $now->setTime(0, 0, 0);
|
||||
// Collect departments to summarize (id, label, highlight) using stable ID list
|
||||
$departments = [];
|
||||
$deptIds = $criteria->departments?->listIDs() ?? [];
|
||||
foreach ($deptIds as $deptId) {
|
||||
$deptId = (int)$deptId;
|
||||
$deptName = '';
|
||||
try {
|
||||
$deptObj = (new \objects\departments_o())->select($deptId);
|
||||
if (isset($deptObj->name)) {
|
||||
$deptName = (string)$deptObj->name->value();
|
||||
}
|
||||
if ($deptName === '') {
|
||||
$deptName = 'Afdeling ' . (string)$deptId;
|
||||
}
|
||||
} catch (\Throwable) {
|
||||
$deptName = 'Afdeling (ukendt)';
|
||||
}
|
||||
$departments[] = [
|
||||
'id' => $deptId,
|
||||
'label' => $deptName,
|
||||
'highlight' => ($department && isset($department->id) && (int)$department->id === $deptId)
|
||||
];
|
||||
}
|
||||
|
||||
// Month start to now
|
||||
$monthStart = $now->setDate((int)$now->format('Y'), (int)$now->format('m'), 1)->setTime(0, 0, 0);
|
||||
|
||||
$yCount = self::progressForWindow($criteria, $yesterdayStart, $yesterdayEnd);
|
||||
$wCount = self::progressForWindow($criteria, $weekStart, $now);
|
||||
$mCount = self::progressForWindow($criteria, $monthStart, $now);
|
||||
|
||||
$target = (int)($criteria->target ?? 0);
|
||||
|
||||
$lines = array_values(array_filter($header));
|
||||
if ($includeTargets && $target > 0) {
|
||||
$yPct = number_format($yCount > 0 ? ($yCount / max(1, $target)) * 100 : 0, 0);
|
||||
$wPct = number_format($wCount > 0 ? ($wCount / max(1, $target)) * 100 : 0, 0);
|
||||
$mPct = number_format($mCount > 0 ? ($mCount / max(1, $target)) * 100 : 0, 0);
|
||||
$lines[] = sprintf('Igår: %d ud af %d (%s%%)', $yCount, $target, $yPct);
|
||||
$lines[] = sprintf('Ugen total: %d ud af %d (%s%%)', $wCount, $target, $wPct);
|
||||
$lines[] = sprintf('Måneden total: %d ud af %d (%s%%)', $mCount, $target, $mPct);
|
||||
} else {
|
||||
$lines[] = sprintf('Igår: %d', $yCount);
|
||||
$lines[] = sprintf('Ugen total: %d', $wCount);
|
||||
$lines[] = sprintf('Måneden total: %d', $mCount);
|
||||
// Build the output lines
|
||||
$outLines = [];
|
||||
// Prepend header lines if provided
|
||||
if (is_array($header)) {
|
||||
foreach (array_filter($header, fn($v) => $v !== null && $v !== '') as $hLine) {
|
||||
$outLines[] = (string)$hLine;
|
||||
}
|
||||
}
|
||||
foreach ($departments as $deptData) {
|
||||
$lines = [];
|
||||
$lines[] = $deptData['label'] . ':';
|
||||
// Calculate counts on the fly for each period using the criteria with department filter
|
||||
$deptId = $deptData['id'];
|
||||
$yesterdayCount = 0;
|
||||
$weekTotalCount = 0;
|
||||
$monthTotalCount = 0;
|
||||
|
||||
return implode("\n", $lines);
|
||||
if ($deptId !== null) {
|
||||
// Base dept-filtered criteria
|
||||
$base = $criteria->withDepartmentFilter((int)$deptId);
|
||||
|
||||
// Yesterday
|
||||
[$ys, $ye] = self::getYesterdayRange();
|
||||
$yr = self::clampToCriteriaWindow($criteria, $ys, $ye);
|
||||
if ($yr !== null) {
|
||||
[$ys2, $ye2] = $yr;
|
||||
$c = clone $base;
|
||||
// goals_criteria timeframe expects \DateTime (mutable), convert from Immutable
|
||||
$c->start = \DateTime::createFromImmutable($ys2);
|
||||
$c->end = \DateTime::createFromImmutable($ye2);
|
||||
$yesterdayCount = (int)self::getProgress($c);
|
||||
}
|
||||
|
||||
// Week-to-date (Mon..today)
|
||||
[$ws, $we] = self::getWeekToDateRange();
|
||||
$wr = self::clampToCriteriaWindow($criteria, $ws, $we);
|
||||
if ($wr !== null) {
|
||||
[$ws2, $we2] = $wr;
|
||||
$c = clone $base;
|
||||
$c->start = \DateTime::createFromImmutable($ws2);
|
||||
$c->end = \DateTime::createFromImmutable($we2);
|
||||
$weekTotalCount = (int)self::getProgress($c);
|
||||
}
|
||||
|
||||
// Month-to-date (1st..today)
|
||||
[$ms, $me] = self::getMonthToDateRange();
|
||||
$mr = self::clampToCriteriaWindow($criteria, $ms, $me);
|
||||
if ($mr !== null) {
|
||||
[$ms2, $me2] = $mr;
|
||||
$c = clone $base;
|
||||
$c->start = \DateTime::createFromImmutable($ms2);
|
||||
$c->end = \DateTime::createFromImmutable($me2);
|
||||
$monthTotalCount = (int)self::getProgress($c);
|
||||
}
|
||||
}
|
||||
// Yesterday
|
||||
if ($includeTargets && isset($criteria->target)) {
|
||||
$target = (int)$criteria->target;
|
||||
$percentYest = $target > 0 ? round(($yesterdayCount / max(1, $target)) * 100, 2) : 0.0;
|
||||
$lines[] = sprintf('Igår: %d ud af %d (%.2f%%)', $yesterdayCount, $target, $percentYest);
|
||||
} else {
|
||||
$lines[] = sprintf('Igår: %d', $yesterdayCount);
|
||||
}
|
||||
// Week total
|
||||
if ($includeTargets && isset($criteria->target)) {
|
||||
$target = (int)$criteria->target;
|
||||
$percentWeek = $target > 0 ? round(($weekTotalCount / max(1, $target)) * 100, 2) : 0.0;
|
||||
$lines[] = sprintf('Ugen total: %d ud af %d (%.2f%%)', $weekTotalCount, $target, $percentWeek);
|
||||
} else {
|
||||
$lines[] = sprintf('Ugen total: %d', $weekTotalCount);
|
||||
}
|
||||
// Month total
|
||||
if ($includeTargets && isset($criteria->target)) {
|
||||
$target = (int)$criteria->target;
|
||||
$percentMonth = $target > 0 ? round(($monthTotalCount / max(1, $target)) * 100, 2) : 0.0;
|
||||
$lines[] = sprintf('Måneden total: %d ud af %d (%.2f%%)', $monthTotalCount, $target, $percentMonth);
|
||||
} else {
|
||||
$lines[] = sprintf('Måneden total: %d', $monthTotalCount);
|
||||
}
|
||||
// Highlight if needed
|
||||
if ($deptData['highlight']) {
|
||||
$outLines[] = ">>> " . implode("\n", $lines);
|
||||
} else {
|
||||
$outLines[] = implode("\n", $lines);
|
||||
}
|
||||
}
|
||||
return implode("\n\n", $outLines);
|
||||
}
|
||||
|
||||
private static function progressForWindow(goals_criteria $criteria, \DateTimeInterface $start, \DateTimeInterface $end): int
|
||||
// --- Date range helpers for summary periods ---
|
||||
private static function getYesterdayRange(): array
|
||||
{
|
||||
// Clone criteria and adjust timeframe
|
||||
$clone = clone $criteria;
|
||||
$clone->start = (clone \DateTime::createFromInterface($start));
|
||||
$clone->end = (clone \DateTime::createFromInterface($end));
|
||||
return self::getProgress($clone);
|
||||
$now = new \DateTimeImmutable('now');
|
||||
$y = $now->modify('-1 day');
|
||||
return [$y->setTime(0, 0, 0), $y->setTime(23, 59, 59)];
|
||||
}
|
||||
|
||||
private static function getWeekToDateRange(): array
|
||||
{
|
||||
$now = new \DateTimeImmutable('now');
|
||||
$monday = $now->modify('monday this week');
|
||||
return [$monday->setTime(0, 0, 0), $now->setTime(23, 59, 59)];
|
||||
}
|
||||
|
||||
private static function getMonthToDateRange(): array
|
||||
{
|
||||
$now = new \DateTimeImmutable('now');
|
||||
$first = $now->modify('first day of this month');
|
||||
return [$first->setTime(0, 0, 0), $now->setTime(23, 59, 59)];
|
||||
}
|
||||
|
||||
private static function clampToCriteriaWindow(goals_criteria $criteria, \DateTimeImmutable $start, \DateTimeImmutable $end): ?array
|
||||
{
|
||||
$sTs = $start->getTimestamp();
|
||||
$eTs = $end->getTimestamp();
|
||||
if ($criteria->start instanceof \DateTimeInterface) {
|
||||
$cs = $criteria->start->getTimestamp();
|
||||
if ($sTs < $cs) { $sTs = $cs; }
|
||||
}
|
||||
if ($criteria->end instanceof \DateTimeInterface) {
|
||||
$ce = $criteria->end->getTimestamp();
|
||||
if ($eTs > $ce) { $eTs = $ce; }
|
||||
}
|
||||
if ($sTs > $eTs) { return null; }
|
||||
// Preserve the timezone of provided start/end
|
||||
$tz = $start->getTimezone();
|
||||
$s = (new \DateTimeImmutable('@' . $sTs))->setTimezone($tz);
|
||||
$e = (new \DateTimeImmutable('@' . $eTs))->setTimezone($tz);
|
||||
return [$s, $e];
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
Reference in New Issue
Block a user