feat: financial data check for teamers, improved enforced checks logic
addresses #869at5rtp
This commit is contained in:
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace App\RequiredTeamerCheck;
|
||||
|
||||
use Carbon\CarbonImmutable;
|
||||
|
||||
/**
|
||||
* A set of yearly recurring dates after which something must be confirmed again.
|
||||
*
|
||||
* Belongs to the individual check that composes it, never to the application as a
|
||||
* whole: a deadline expresses "this particular confirmation has expired", not
|
||||
* "portal access has expired".
|
||||
*/
|
||||
final class RecurringDeadlines
|
||||
{
|
||||
/**
|
||||
* @param string[] $deadlines dates as MM-DD, e.g. ['04-01', '10-01']; an empty
|
||||
* list is never due
|
||||
*/
|
||||
public function __construct(private readonly array $deadlines)
|
||||
{
|
||||
}
|
||||
|
||||
/**
|
||||
* Whether a confirmation is outstanding: never confirmed, or last confirmed
|
||||
* before the most recent deadline that has passed.
|
||||
*/
|
||||
public function isDue(?\DateTimeInterface $confirmedAt, ?\DateTimeInterface $registeredAt, CarbonImmutable $now): bool
|
||||
{
|
||||
$deadline = $this->getCurrentDeadline($now);
|
||||
|
||||
if (null === $deadline) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (true === $this->isRegisteredAfterAnyDeadline($registeredAt, $now)) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (null === $confirmedAt) {
|
||||
return true;
|
||||
}
|
||||
|
||||
return CarbonImmutable::instance($confirmedAt) < $deadline;
|
||||
}
|
||||
|
||||
/**
|
||||
* The most recent deadline that has already passed, or null when none has.
|
||||
*/
|
||||
public function getCurrentDeadline(CarbonImmutable $now): ?CarbonImmutable
|
||||
{
|
||||
$deadlines = $this->getDeadlinesForYear($now);
|
||||
rsort($deadlines);
|
||||
|
||||
foreach ($deadlines as $deadline) {
|
||||
if ($deadline <= $now) {
|
||||
return $deadline;
|
||||
}
|
||||
}
|
||||
|
||||
return null;
|
||||
}
|
||||
|
||||
/**
|
||||
* Someone who registered after a deadline has effectively confirmed their data
|
||||
* by registering, so they are exempt until the next one.
|
||||
*/
|
||||
private function isRegisteredAfterAnyDeadline(?\DateTimeInterface $registeredAt, CarbonImmutable $now): bool
|
||||
{
|
||||
if (null === $registeredAt) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$registeredAt = CarbonImmutable::instance($registeredAt)->startOfDay();
|
||||
|
||||
foreach ($this->getDeadlinesForYear($now) as $deadline) {
|
||||
if ($registeredAt > $deadline) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return CarbonImmutable[]
|
||||
*/
|
||||
private function getDeadlinesForYear(CarbonImmutable $now): array
|
||||
{
|
||||
$deadlines = [];
|
||||
|
||||
foreach (array_filter(array_map('trim', $this->deadlines)) as $date) {
|
||||
$deadline = CarbonImmutable::createFromFormat('Y-m-d', sprintf('%s-%s', $now->format('Y'), $date));
|
||||
|
||||
if (false === $deadline instanceof CarbonImmutable) {
|
||||
continue;
|
||||
}
|
||||
|
||||
$deadlines[] = $deadline->startOfDay();
|
||||
}
|
||||
|
||||
return $deadlines;
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user