Files
SIRH/docs/superpowers/plans/2026-03-12-employee-entry-date.md
2026-03-12 12:30:13 +01:00

8.2 KiB

Employee Entry Date Implementation Plan

For agentic workers: REQUIRED: Use superpowers:subagent-driven-development (if subagents available) or superpowers:executing-plans to implement this plan. Steps use checkbox (- [ ]) syntax for tracking.

Goal: Add an entryDate field to Employee, automatically populated from contractStartDate at creation.

Architecture: New nullable DATE column on employees table. The EmployeeWriteProcessor sets entryDate from the first contract period's start date during employee creation. Exposed read-only in the API. No fallback needed — existing employees will be updated manually in prod DB.

Tech Stack: Symfony/Doctrine (backend), Nuxt/Vue/TypeScript (frontend)


File Structure

File Action Responsibility
src/Entity/Employee.php Modify Add entryDate column + getter/setter, expose in employee:read
src/State/EmployeeWriteProcessor.php Modify Set entryDate from contractStartDate on creation
migrations/Version20260312120000.php Create Add entry_date column to employees table
tests/State/EmployeeWriteProcessorTest.php Modify Assert entryDate is set on new employee
frontend/services/dto/employee.ts Modify Add entryDate field to Employee type
frontend/pages/employees/index.vue Modify Display entry date in employee list

Chunk 1: Backend

Task 1: Migration

Files:

  • Create: migrations/Version20260312120000.php

  • Step 1: Create the migration file

<?php

declare(strict_types=1);

namespace DoctrineMigrations;

use Doctrine\DBAL\Schema\Schema;
use Doctrine\Migrations\AbstractMigration;

final class Version20260312120000 extends AbstractMigration
{
    public function getDescription(): string
    {
        return 'Add entry_date column to employees table';
    }

    public function up(Schema $schema): void
    {
        $this->addSql('ALTER TABLE employees ADD entry_date DATE DEFAULT NULL COMMENT \'(DC2Type:date_immutable)\'');
    }

    public function down(Schema $schema): void
    {
        $this->addSql('ALTER TABLE employees DROP entry_date');
    }
}
  • Step 2: Run migration

Run: php bin/console doctrine:migrations:migrate --no-interaction Expected: Migration applied successfully

  • Step 3: Commit
git add migrations/Version20260312120000.php
git commit -m "feat : ajout colonne entry_date sur employees"

Task 2: Entity — add entryDate property

Files:

  • Modify: src/Entity/Employee.php:56-61 (insert after displayOrder)

  • Step 1: Add the column, getter, and setter to Employee entity

Add after the displayOrder property (line 58):

#[ORM\Column(type: 'date_immutable', nullable: true)]
#[Groups(['employee:read'])]
private ?\DateTimeImmutable $entryDate = null;

Add getter and setter after setDisplayOrder() (after line 167):

public function getEntryDate(): ?\DateTimeImmutable
{
    return $this->entryDate;
}

public function setEntryDate(?\DateTimeImmutable $entryDate): self
{
    $this->entryDate = $entryDate;

    return $this;
}
  • Step 2: Verify schema is in sync

Run: php bin/console doctrine:schema:validate Expected: OK (or only existing unrelated warnings)

  • Step 3: Commit
git add src/Entity/Employee.php
git commit -m "feat : ajout propriete entryDate sur Employee"

Task 3: Set entryDate on employee creation

Files:

  • Modify: src/State/EmployeeWriteProcessor.php:60-71

  • Modify: tests/State/EmployeeWriteProcessorTest.php

  • Step 1: Write the failing test

Add use ApiPlatform\Metadata\Post; to the imports at the top of the test file (alongside the existing Delete and Patch imports).

Then add this test method to EmployeeWriteProcessorTest:

public function testSetsEntryDateOnNewEmployee(): void
{
    $employee = new Employee();
    $employee->setFirstName('Jane');
    $employee->setLastName('Doe');
    $employee->setContractStartDate('2026-04-01');
    $employee->setContractNature('CDI');

    $contract = new Contract()
        ->setName('35h')
        ->setTrackingMode(Contract::TRACKING_TIME)
        ->setWeeklyHours(35);
    $employee->setContract($contract);

    $persistProcessor     = $this->createMock(ProcessorInterface::class);
    $removeProcessor      = $this->createStub(ProcessorInterface::class);
    $entityManager        = $this->createStub(EntityManagerInterface::class);
    $periodRepository     = $this->createStub(EmployeeContractPeriodReadRepositoryInterface::class);
    $changeRequestFactory = new EmployeeContractChangeRequestFactory();
    $periodManager        = $this->createMock(EmployeeContractPeriodManagerInterface::class);

    $persistProcessor
        ->expects(self::once())
        ->method('process')
        ->willReturn($employee);

    $periodManager
        ->expects(self::once())
        ->method('ensureContractPeriodExists');

    $processor = new EmployeeWriteProcessor(
        $persistProcessor,
        $removeProcessor,
        $entityManager,
        $periodRepository,
        $changeRequestFactory,
        $periodManager
    );

    $processor->process($employee, new Post());

    self::assertNotNull($employee->getEntryDate());
    self::assertSame('2026-04-01', $employee->getEntryDate()->format('Y-m-d'));
}
  • Step 2: Run test to verify it fails

Run: php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee Expected: FAIL — entryDate is null

  • Step 3: Implement — set entryDate in EmployeeWriteProcessor

In src/State/EmployeeWriteProcessor.php, inside the if ($isNew) block (line 60-71), add before return $result; (line 71):

$data->setEntryDate($startDate);

The full block becomes:

if ($isNew) {
    $startDate = $changeRequest->contractStartDate ?? new DateTimeImmutable('1970-01-01');
    $nature    = $changeRequest->contractNature ?? ContractNature::CDI;
    $this->periodManager->ensureContractPeriodExists(
        employee: $data,
        contract: $currentContract,
        startDate: $startDate,
        endDate: $changeRequest->contractEndDate,
        nature: $nature
    );

    $data->setEntryDate($startDate);

    return $result;
}
  • Step 4: Run test to verify it passes

Run: php bin/phpunit tests/State/EmployeeWriteProcessorTest.php --filter=testSetsEntryDateOnNewEmployee Expected: PASS

  • Step 5: Run all EmployeeWriteProcessor tests

Run: php bin/phpunit tests/State/EmployeeWriteProcessorTest.php Expected: All tests pass (no regression)

  • Step 6: Commit
git add src/State/EmployeeWriteProcessor.php tests/State/EmployeeWriteProcessorTest.php
git commit -m "feat : remplissage automatique entryDate a la creation employe"

Chunk 2: Frontend

Task 4: Update frontend DTO and display entry date

Files:

  • Modify: frontend/services/dto/employee.ts:14-25

  • Modify: frontend/pages/employees/index.vue

  • Step 1: Add entryDate to the Employee DTO

In frontend/services/dto/employee.ts:24, add entryDate after displayOrder:

  displayOrder?: number
  entryDate?: string | null
  • Step 2: Display entry date in the employee card hover overlay

In frontend/pages/employees/index.vue, inside the hover overlay <div> (line 49-54), add a new line after the "Site" line (after line 53):

<p><strong>Entree :</strong> {{ employee.entryDate ? employee.entryDate.split('-').reverse().join('/') : '-' }}</p>

This uses string splitting instead of new Date() to avoid timezone parsing issues with date-only strings.

  • Step 3: Verify in browser
  1. Check the API response for an employee: GET /api/employees should include entryDate field (confirms backend employee:read group works)
  2. Open the employee list page, hover over a card — entry date should appear in the overlay
  3. Create a new employee, verify the entry date shows the contract start date
  4. Existing employees without entry date should show "-"
  • Step 4: Commit
git add frontend/services/dto/employee.ts frontend/pages/employees/index.vue
git commit -m "feat : affichage date d'entree dans la liste employes"