feat: collect assignment and disposition events for statistics

This commit is contained in:
2026-08-26 15:17:17 +02:00
parent e210021fe3
commit 2662d56ac1
26 changed files with 2557 additions and 96 deletions
+19
View File
@@ -0,0 +1,19 @@
<?php
namespace App\Enum;
/**
* How far a call-off reached.
*
* Distinct from Disposition::$calledOffBy, which records whose decision it was. The office
* can cancel a single placement just as a whole trip can fall away, so who decided says
* nothing about how many teamers it cost.
*/
enum CallOffScope: string
{
/** The whole trip was cancelled and every teamer on it lost their placement. */
case ASSIGNMENT = 'assignment';
/** This placement alone ended; the assignment and everyone else carried on. */
case DISPOSITION = 'disposition';
}
+17
View File
@@ -0,0 +1,17 @@
<?php
namespace App\Enum;
/**
* The coarse role of whoever triggered a statistic event.
*
* This is who *acted*, derived from the security token. It is deliberately not the
* same as Disposition::$calledOffBy, which is what an admin declares on the call-off
* form about whose decision it was.
*/
enum StatisticsActorRole: string
{
case ADMIN = 'admin';
case TEAMER = 'teamer';
case SYSTEM = 'system';
}
+25
View File
@@ -0,0 +1,25 @@
<?php
namespace App\Enum;
/**
* Which date a statistics query means when it is given a period.
*
* The two answer different questions and routinely disagree: an application for the
* coming winter arrives months before the season it belongs to.
*/
enum StatisticsDateBasis: string
{
/**
* The season the assignment runs in - assignment dates, falling back to the
* destination's. This is what every other statistics screen in the app filters by,
* so it is the default here too.
*/
case SEASON = 'season';
/**
* When the event was actually recorded. Wanted for genuine time series, such as
* call-offs per month.
*/
case OCCURRENCE = 'occurrence';
}
+31
View File
@@ -0,0 +1,31 @@
<?php
namespace App\Enum;
/**
* The metrics collected into the statistics_event table.
*
* Adding a metric means adding a case here plus one StatisticsCollectorInterface that
* records it. The table itself does not change, and neither does
* StatisticsChangeSetListener.
*
* A case's value is what ends up in statistics_event.name, so renaming one orphans every
* row already recorded under the old value.
*/
enum StatisticsEventName: string
{
case ASSIGNMENT_JOB_PROFILE_CHANGED = 'assignment.job_profile_changed';
case ASSIGNMENT_CALLED_OFF = 'assignment.called_off';
case DISPOSITION_CALLED_OFF = 'disposition.called_off';
case APPLICATION_CREATED = 'application.created';
public function label(): string
{
return match ($this) {
self::ASSIGNMENT_JOB_PROFILE_CHANGED => 'Tätigkeitsprofil geändert',
self::ASSIGNMENT_CALLED_OFF => 'Reise abgesagt',
self::DISPOSITION_CALLED_OFF => 'Einsatz abgesagt',
self::APPLICATION_CREATED => 'Bewerbung eingegangen',
};
}
}