feat: remove obsolete date range override
This commit is contained in:
@@ -163,12 +163,10 @@ class ApplicationRepository extends ServiceEntityRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* Finds all applications of a teamer whose effective assignment period overlaps the given period.
|
||||
* Finds all applications of a teamer whose assignment period overlaps the given period.
|
||||
*
|
||||
* The effective period of an assignment is its own date range, falling back to the date range of
|
||||
* its destination whenever the assignment does not override it - the query mirrors
|
||||
* {@see Assignment::getEffectivePeriod()}. Boundaries count as an overlap: a teamer cannot end one
|
||||
* assignment on the same day another one begins.
|
||||
* The assignment period is the date range of its destination. Boundaries count as an
|
||||
* overlap: a teamer cannot end one assignment on the same day another one begins.
|
||||
*
|
||||
* @return array<Application>
|
||||
*/
|
||||
@@ -193,26 +191,8 @@ class ApplicationRepository extends ServiceEntityRepository
|
||||
$qb->expr()->neq('assignment.status', ':assignment_called_off'),
|
||||
$qb->expr()->isNull('assignment.deletedAt'),
|
||||
$qb->expr()->isNull('destination.deletedAt'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateFrom'),
|
||||
$qb->expr()->lte('destination.dateFrom', ':dateTo')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateFrom'),
|
||||
$qb->expr()->lte('assignment.dateFrom', ':dateTo')
|
||||
)
|
||||
),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateTo'),
|
||||
$qb->expr()->gte('destination.dateTo', ':dateFrom')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->gte('assignment.dateTo', ':dateFrom')
|
||||
)
|
||||
)
|
||||
$qb->expr()->lte('destination.dateFrom', ':dateTo'),
|
||||
$qb->expr()->gte('destination.dateTo', ':dateFrom')
|
||||
))
|
||||
->setParameter('teamer', $teamer)
|
||||
->setParameter('application_rejected', Application::STATUS_REJECTED)
|
||||
|
||||
@@ -73,13 +73,7 @@ class AssignmentRepository extends ServiceEntityRepository
|
||||
->innerJoin('assignment.destination', 'destination')
|
||||
->innerJoin('assignment.jobProfile', 'job_profile')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->gt('destination.dateFrom', ':now'),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateFrom'),
|
||||
$qb->expr()->gt('assignment.dateFrom', ':now')
|
||||
)
|
||||
),
|
||||
$qb->expr()->gt('destination.dateFrom', ':now'),
|
||||
$qb->expr()->isNull('assignment.deletedAt'),
|
||||
$qb->expr()->notIn('assignment.status', ':status'),
|
||||
$qb->expr()->in('assignment.id', $availableAssignmentsIds)
|
||||
@@ -399,13 +393,7 @@ class AssignmentRepository extends ServiceEntityRepository
|
||||
)
|
||||
->innerJoin('assignment.destination', 'destination')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->gt('destination.dateFrom', ':now'),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateFrom'),
|
||||
$qb->expr()->gt('assignment.dateFrom', ':now')
|
||||
)
|
||||
),
|
||||
$qb->expr()->gt('destination.dateFrom', ':now'),
|
||||
$qb->expr()->notIn('assignment.status', ':status'),
|
||||
$qb->expr()->isNull('assignment.deletedAt')
|
||||
))
|
||||
|
||||
@@ -11,7 +11,6 @@ use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\ORM\Query;
|
||||
use Doctrine\ORM\Query\Expr\Comparison;
|
||||
use Doctrine\ORM\Query\Expr\Join;
|
||||
use Doctrine\ORM\Query\Expr\Orx;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
@@ -43,16 +42,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
$qb->expr()->eq('disposition.teamer', ':teamer'),
|
||||
$qb->expr()->neq('assignment.status', ':assignmentStatus'),
|
||||
$qb->expr()->neq('disposition.status', ':dispositionStatus'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateTo'),
|
||||
$qb->expr()->gte('destination.dateTo', ':date')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->gte('assignment.dateTo', ':date')
|
||||
)
|
||||
)
|
||||
$qb->expr()->gte('destination.dateTo', ':date')
|
||||
))
|
||||
->setParameter('teamer', $teamer)
|
||||
->setParameter('assignmentStatus', Assignment::STATUS_CALLED_OFF)
|
||||
@@ -85,16 +75,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
$qb->expr()->eq('disposition.teamer', ':teamer'),
|
||||
$qb->expr()->neq('assignment.status', ':assignmentStatus'),
|
||||
$qb->expr()->neq('disposition.status', ':dispositionStatus'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateTo'),
|
||||
$qb->expr()->lte('destination.dateTo', ':date')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->lte('assignment.dateTo', ':date')
|
||||
)
|
||||
)
|
||||
$qb->expr()->lte('destination.dateTo', ':date')
|
||||
))
|
||||
->setParameter('teamer', $teamer)
|
||||
->setParameter('assignmentStatus', Assignment::STATUS_CALLED_OFF)
|
||||
@@ -145,12 +126,12 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
}
|
||||
|
||||
/**
|
||||
* The effective start date of every non-called-off disposition of a teamer, one row
|
||||
* each, for the per-season tally in the info modal.
|
||||
* The start date of every non-called-off disposition of a teamer, one row each, for the
|
||||
* per-season tally in the info modal.
|
||||
*
|
||||
* Same teamer/called-off filtering as findRecentDispositionsByTeamer(), but unbounded
|
||||
* and stripped to the one date it needs: assignment.dateFrom falling back to the
|
||||
* destination's, the season convention shared with SeasonPeriodFilter.
|
||||
* and stripped to the one date it needs: the destination's start, the season convention
|
||||
* shared with SeasonPeriodFilter.
|
||||
*
|
||||
* @return array<int, array{seasonDate: string}>
|
||||
*/
|
||||
@@ -159,7 +140,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
$qb = $this->createQueryBuilder('disposition');
|
||||
|
||||
return $qb
|
||||
->select('COALESCE(assignment.dateFrom, destination.dateFrom) AS seasonDate')
|
||||
->select('destination.dateFrom AS seasonDate')
|
||||
->innerJoin('disposition.assignment', 'assignment')
|
||||
->innerJoin('assignment.destination', 'destination')
|
||||
->where($qb->expr()->andX(
|
||||
@@ -242,13 +223,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
->leftJoin('disposition.feedback', 'feedback')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->notIn('assignment.status', ':status'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->lte('assignment.dateTo', ':dateTo')
|
||||
),
|
||||
$qb->expr()->lte('destination.dateTo', ':dateTo')
|
||||
),
|
||||
$qb->expr()->lte('destination.dateTo', ':dateTo'),
|
||||
$qb->expr()->isNull('feedback'),
|
||||
$this->excludesSkipFormalities($qb)
|
||||
))
|
||||
@@ -302,13 +277,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
->innerJoin('assignment.destination', 'destination')
|
||||
->where($qb->expr()->andX(
|
||||
$qb->expr()->in('disposition.status', ':status'),
|
||||
$qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->lte('assignment.dateTo', ':dateTo')
|
||||
),
|
||||
$qb->expr()->lte('destination.dateTo', ':dateTo')
|
||||
)
|
||||
$qb->expr()->lte('destination.dateTo', ':dateTo')
|
||||
))
|
||||
->setParameter('status', [
|
||||
Disposition::STATUS_NEW,
|
||||
@@ -529,10 +498,10 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
$normalDay = $qb->expr()->andX(
|
||||
$qb->expr()->gte('disposition.createdAt', ':dayStart'),
|
||||
$qb->expr()->lt('disposition.createdAt', ':dayEnd'),
|
||||
$this->effectiveDateToGreaterThan($qb, ':tomorrow'),
|
||||
$qb->expr()->gt('destination.dateTo', ':tomorrow'),
|
||||
);
|
||||
$shortNoticeDay = $qb->expr()->andX(
|
||||
$this->effectiveDateToEquals($qb, ':tomorrow'),
|
||||
$qb->expr()->eq('destination.dateTo', ':tomorrow'),
|
||||
$qb->expr()->gte('disposition.createdAt', ':dayStart'),
|
||||
);
|
||||
|
||||
@@ -599,7 +568,7 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
// in CronCommand, so a skip-formalities placement is still `confirmed` here and
|
||||
// would slip past the status filter on the day after the assignment ends.
|
||||
$this->excludesSkipFormalities($qb),
|
||||
$this->effectiveDateToEquals($qb, ':endDate'),
|
||||
$qb->expr()->eq('destination.dateTo', ':endDate'),
|
||||
))
|
||||
->setParameter('documentType', Upload::TYPE_INVOICE)
|
||||
->setParameter('dispositionStatus', [Disposition::STATUS_CALLED_OFF, Disposition::STATUS_COMPLETED])
|
||||
@@ -611,30 +580,6 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
;
|
||||
}
|
||||
|
||||
/**
|
||||
* Compares the assignment's end date against $parameter, falling back to the destination's
|
||||
* when the assignment does not override it.
|
||||
*
|
||||
* The fallback is guarded on both sides - without the isNull() on the second branch an
|
||||
* assignment that moves the end date into the future would still match on the
|
||||
* destination's date. Kept in one place because the per-assignment date override is due to
|
||||
* be removed (docs/remove-assignment-date-override.md), and this then collapses to a plain
|
||||
* comparison on destination.dateTo.
|
||||
*/
|
||||
private function effectiveDateToEquals(QueryBuilder $qb, string $parameter): Orx
|
||||
{
|
||||
return $qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->eq('assignment.dateTo', $parameter)
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateTo'),
|
||||
$qb->expr()->eq('destination.dateTo', $parameter)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Restricts a query to assignments that still run the contract, invoice and feedback process.
|
||||
*
|
||||
@@ -653,23 +598,6 @@ class DispositionRepository extends ServiceEntityRepository
|
||||
return $qb->expr()->eq('assignment.skipFormalities', ':skipFormalities');
|
||||
}
|
||||
|
||||
/**
|
||||
* Same fallback as effectiveDateToEquals(), but for "later than $parameter".
|
||||
*/
|
||||
private function effectiveDateToGreaterThan(QueryBuilder $qb, string $parameter): Orx
|
||||
{
|
||||
return $qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull('assignment.dateTo'),
|
||||
$qb->expr()->gt('assignment.dateTo', $parameter)
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull('assignment.dateTo'),
|
||||
$qb->expr()->gt('destination.dateTo', $parameter)
|
||||
),
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Dispositions whose contract upload period has run out, for the admin dashboard.
|
||||
*
|
||||
|
||||
@@ -5,15 +5,14 @@ namespace App\Repository\Filter;
|
||||
use Doctrine\ORM\QueryBuilder;
|
||||
|
||||
/**
|
||||
* Narrows a query to the season an assignment runs in.
|
||||
* Narrows a query to the season an assignment runs in, which is the date range of its
|
||||
* destination.
|
||||
*
|
||||
* The season is assignment.dateFrom/dateTo falling back to the destination's, mirroring
|
||||
* Assignment::getEffectivePeriod(), which DQL cannot call. Every statistics screen means
|
||||
* this by a date range, so it lives in one place: three repositories carrying the same
|
||||
* expression by hand is three chances for "a season" to come to mean something slightly
|
||||
* different on one screen than on the one beside it.
|
||||
* Kept in one place because every statistics screen means the same thing by "a season":
|
||||
* the expression carried by hand in each repository is one more chance for it to come to
|
||||
* mean something slightly different on one screen than on the one beside it.
|
||||
*
|
||||
* Both aliases must already be joined by the caller - this only adds the conditions.
|
||||
* The destination alias must already be joined by the caller - this only adds the conditions.
|
||||
*/
|
||||
final class SeasonPeriodFilter
|
||||
{
|
||||
@@ -21,37 +20,18 @@ final class SeasonPeriodFilter
|
||||
QueryBuilder $qb,
|
||||
?\DateTimeImmutable $dateFrom,
|
||||
?\DateTimeImmutable $dateTo,
|
||||
string $assignmentAlias = 'assignment',
|
||||
string $destinationAlias = 'destination',
|
||||
): void {
|
||||
if (null !== $dateFrom) {
|
||||
$qb
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull($assignmentAlias.'.dateFrom'),
|
||||
$qb->expr()->gte($assignmentAlias.'.dateFrom', ':dateFrom')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull($assignmentAlias.'.dateFrom'),
|
||||
$qb->expr()->gte($destinationAlias.'.dateFrom', ':dateFrom')
|
||||
)
|
||||
))
|
||||
->andWhere($qb->expr()->gte($destinationAlias.'.dateFrom', ':dateFrom'))
|
||||
->setParameter('dateFrom', $dateFrom)
|
||||
;
|
||||
}
|
||||
|
||||
if (null !== $dateTo) {
|
||||
$qb
|
||||
->andWhere($qb->expr()->orX(
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNotNull($assignmentAlias.'.dateTo'),
|
||||
$qb->expr()->lte($assignmentAlias.'.dateTo', ':dateTo')
|
||||
),
|
||||
$qb->expr()->andX(
|
||||
$qb->expr()->isNull($assignmentAlias.'.dateTo'),
|
||||
$qb->expr()->lte($destinationAlias.'.dateTo', ':dateTo')
|
||||
)
|
||||
))
|
||||
->andWhere($qb->expr()->lte($destinationAlias.'.dateTo', ':dateTo'))
|
||||
->setParameter('dateTo', $dateTo)
|
||||
;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user