feat(rtt) : autoriser le paiement RTT rétroactif sur l'exercice précédent
La RH peut désormais saisir un paiement RTT sur l'exercice immédiatement précédent (ex. RTT de mai réglés après la bascule du 1er juin), sans casser le report. - gate back (assertYearAllowedForPayment) : accepte courant, N-1, ou dernier exercice d'une phase clôturée - après saisie sur N-1, recalcul automatique du report d'ouverture de l'exercice courant (computeClosingBalance) dans une transaction → pas de double comptage - refus si le report de l'exercice courant est verrouillé (assertReportNotLocked) - fallback EmployeeRttSummaryProvider::resolveCarry passe sur computeClosingBalance : disponible correct même sans ligne stockée - front : bouton + Payer les RTT actif sur l'exercice précédent - docs : CLAUDE.md, doc/rtt-tab.md, documentation-content.ts Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -7,6 +7,7 @@ namespace App\Tests\State;
|
||||
use App\Entity\Contract;
|
||||
use App\Entity\Employee;
|
||||
use App\Entity\EmployeeContractPeriod;
|
||||
use App\Entity\EmployeeRttBalance;
|
||||
use App\Enum\ContractNature;
|
||||
use App\Enum\TrackingMode;
|
||||
use App\Service\Contracts\EmployeeContractPhaseResolver;
|
||||
@@ -74,6 +75,54 @@ final class EmployeeRttPaymentProcessorTest extends TestCase
|
||||
$this->invokePrivate($processor, 'assertYearAllowedForPayment', $employee, 2030);
|
||||
}
|
||||
|
||||
public function testPaymentAllowedOnPreviousExercise(): void
|
||||
{
|
||||
// Today = 2026-05-19 → current exercise = 2026. Retroactive payment on the
|
||||
// immediately previous exercise (2025) is now allowed (Option B).
|
||||
$employee = $this->buildEmployeeWithTransition('2020-06-01', '2026-04-30', '2026-05-01');
|
||||
$processor = $this->buildProcessorWithClock(new DateTimeImmutable('2026-05-19'));
|
||||
|
||||
$this->invokePrivate($processor, 'assertYearAllowedForPayment', $employee, 2025);
|
||||
|
||||
// No exception → previous exercise accepted.
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
public function testPaymentStillRejectedTwoExercisesBack(): void
|
||||
{
|
||||
// 2024 is two exercises before current (2026) and not a closed-phase end → still rejected.
|
||||
$employee = $this->buildEmployeeWithTransition('2020-06-01', '2026-04-30', '2026-05-01');
|
||||
$processor = $this->buildProcessorWithClock(new DateTimeImmutable('2026-05-19'));
|
||||
|
||||
$this->expectException(UnprocessableEntityHttpException::class);
|
||||
$this->invokePrivate($processor, 'assertYearAllowedForPayment', $employee, 2024);
|
||||
}
|
||||
|
||||
public function testRetroactivePaymentRefusedWhenDownstreamReportLocked(): void
|
||||
{
|
||||
$processor = $this->buildProcessorWithClock(new DateTimeImmutable('2026-05-19'));
|
||||
|
||||
$locked = new EmployeeRttBalance();
|
||||
$locked->setIsLocked(true);
|
||||
|
||||
$this->expectException(UnprocessableEntityHttpException::class);
|
||||
$this->invokePrivate($processor, 'assertReportNotLocked', $locked);
|
||||
}
|
||||
|
||||
public function testRetroactivePaymentAllowedWhenDownstreamReportMissingOrUnlocked(): void
|
||||
{
|
||||
$processor = $this->buildProcessorWithClock(new DateTimeImmutable('2026-05-19'));
|
||||
|
||||
$unlocked = new EmployeeRttBalance();
|
||||
$unlocked->setIsLocked(false);
|
||||
|
||||
// Neither a missing (null) nor an unlocked downstream report must block payment.
|
||||
$this->invokePrivate($processor, 'assertReportNotLocked', null);
|
||||
$this->invokePrivate($processor, 'assertReportNotLocked', $unlocked);
|
||||
|
||||
self::assertTrue(true);
|
||||
}
|
||||
|
||||
// -----------------------------------------------------------------------
|
||||
// Test harness helpers.
|
||||
// -----------------------------------------------------------------------
|
||||
|
||||
Reference in New Issue
Block a user