[#SIRH-14] Ajouter un onglet Observation sur la fiche employé (#8)
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
Some checks failed
Auto Tag Develop / tag (push) Has been cancelled
| Numéro du ticket | Titre du ticket | |------------------|-----------------| | | | ## Description de la PR ## Modification du .env ## Check list - [ ] Pas de régression - [ ] TU/TI/TF rédigée - [ ] TU/TI/TF OK - [ ] CHANGELOG modifié Reviewed-on: #8 Co-authored-by: tristan <tristan@yuno.malio.fr> Co-committed-by: tristan <tristan@yuno.malio.fr>
This commit was merged in pull request #8.
This commit is contained in:
130
src/Entity/Observation.php
Normal file
130
src/Entity/Observation.php
Normal file
@@ -0,0 +1,130 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Entity;
|
||||
|
||||
use ApiPlatform\Doctrine\Orm\Filter\DateFilter;
|
||||
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
|
||||
use ApiPlatform\Metadata\ApiFilter;
|
||||
use ApiPlatform\Metadata\ApiResource;
|
||||
use ApiPlatform\Metadata\Delete;
|
||||
use ApiPlatform\Metadata\Get;
|
||||
use ApiPlatform\Metadata\GetCollection;
|
||||
use ApiPlatform\Metadata\Patch;
|
||||
use ApiPlatform\Metadata\Post;
|
||||
use App\Repository\ObservationRepository;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\ORM\Mapping as ORM;
|
||||
use Symfony\Component\Serializer\Attribute\Groups;
|
||||
|
||||
#[ApiResource(
|
||||
operations: [
|
||||
new Get(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new GetCollection(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Post(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Patch(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
new Delete(
|
||||
security: "is_granted('ROLE_ADMIN')"
|
||||
),
|
||||
],
|
||||
normalizationContext: [
|
||||
'groups' => ['observation:read', 'employee:read'],
|
||||
'datetime_format' => 'Y-m-d',
|
||||
],
|
||||
denormalizationContext: [
|
||||
'groups' => ['observation:write'],
|
||||
'datetime_format' => 'Y-m-d',
|
||||
],
|
||||
order: ['month' => 'DESC'],
|
||||
paginationEnabled: false,
|
||||
)]
|
||||
#[ApiFilter(DateFilter::class, properties: ['month'])]
|
||||
#[ApiFilter(SearchFilter::class, properties: ['employee' => 'exact'])]
|
||||
#[ORM\Entity(repositoryClass: ObservationRepository::class)]
|
||||
#[ORM\Table(name: 'observations')]
|
||||
#[ORM\UniqueConstraint(name: 'uniq_observation_employee_month', columns: ['employee_id', 'month'])]
|
||||
class Observation
|
||||
{
|
||||
#[ORM\Id]
|
||||
#[ORM\GeneratedValue]
|
||||
#[ORM\Column(type: 'integer')]
|
||||
#[Groups(['observation:read'])]
|
||||
private ?int $id = null;
|
||||
|
||||
#[ORM\ManyToOne(targetEntity: Employee::class)]
|
||||
#[ORM\JoinColumn(nullable: false)]
|
||||
#[Groups(['observation:read', 'observation:write'])]
|
||||
private ?Employee $employee = null;
|
||||
|
||||
#[ORM\Column(type: 'date_immutable')]
|
||||
#[Groups(['observation:read', 'observation:write'])]
|
||||
private ?DateTimeImmutable $month = null;
|
||||
|
||||
#[ORM\Column(type: 'text')]
|
||||
#[Groups(['observation:read', 'observation:write'])]
|
||||
private string $content = '';
|
||||
|
||||
#[ORM\Column(type: 'datetime_immutable')]
|
||||
#[Groups(['observation:read'])]
|
||||
private DateTimeImmutable $createdAt;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->createdAt = new DateTimeImmutable();
|
||||
}
|
||||
|
||||
public function getId(): ?int
|
||||
{
|
||||
return $this->id;
|
||||
}
|
||||
|
||||
public function getEmployee(): ?Employee
|
||||
{
|
||||
return $this->employee;
|
||||
}
|
||||
|
||||
public function setEmployee(?Employee $employee): self
|
||||
{
|
||||
$this->employee = $employee;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getMonth(): ?DateTimeImmutable
|
||||
{
|
||||
return $this->month;
|
||||
}
|
||||
|
||||
public function setMonth(?DateTimeImmutable $month): self
|
||||
{
|
||||
$this->month = $month;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getContent(): string
|
||||
{
|
||||
return $this->content;
|
||||
}
|
||||
|
||||
public function setContent(string $content): self
|
||||
{
|
||||
$this->content = $content;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getCreatedAt(): DateTimeImmutable
|
||||
{
|
||||
return $this->createdAt;
|
||||
}
|
||||
}
|
||||
@@ -84,6 +84,10 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
#[Groups(['user:read', 'user:write'])]
|
||||
private ?Employee $employee = null;
|
||||
|
||||
#[ORM\Column(type: 'boolean', options: ['default' => false])]
|
||||
#[Groups(['user:read', 'user:write'])]
|
||||
private bool $isLocked = false;
|
||||
|
||||
/**
|
||||
* @var Collection<int, UserSiteRole>
|
||||
*/
|
||||
@@ -204,5 +208,17 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function isLocked(): bool
|
||||
{
|
||||
return $this->isLocked;
|
||||
}
|
||||
|
||||
public function setIsLocked(bool $isLocked): self
|
||||
{
|
||||
$this->isLocked = $isLocked;
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function eraseCredentials(): void {}
|
||||
}
|
||||
|
||||
38
src/Repository/ObservationRepository.php
Normal file
38
src/Repository/ObservationRepository.php
Normal file
@@ -0,0 +1,38 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Repository;
|
||||
|
||||
use App\Entity\Observation;
|
||||
use DateTimeImmutable;
|
||||
use Doctrine\Bundle\DoctrineBundle\Repository\ServiceEntityRepository;
|
||||
use Doctrine\Persistence\ManagerRegistry;
|
||||
|
||||
/**
|
||||
* @extends ServiceEntityRepository<Observation>
|
||||
*/
|
||||
final class ObservationRepository extends ServiceEntityRepository
|
||||
{
|
||||
public function __construct(ManagerRegistry $registry)
|
||||
{
|
||||
parent::__construct($registry, Observation::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return Observation[]
|
||||
*/
|
||||
public function findByMonth(DateTimeImmutable $from, DateTimeImmutable $to): array
|
||||
{
|
||||
return $this->createQueryBuilder('o')
|
||||
->andWhere('o.month >= :from')
|
||||
->andWhere('o.month <= :to')
|
||||
->setParameter('from', $from)
|
||||
->setParameter('to', $to)
|
||||
->innerJoin('o.employee', 'e')
|
||||
->addSelect('e')
|
||||
->getQuery()
|
||||
->getResult()
|
||||
;
|
||||
}
|
||||
}
|
||||
27
src/Security/UserChecker.php
Normal file
27
src/Security/UserChecker.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Security;
|
||||
|
||||
use App\Entity\User;
|
||||
use Symfony\Component\Security\Core\Authentication\Token\TokenInterface;
|
||||
use Symfony\Component\Security\Core\Exception\CustomUserMessageAccountStatusException;
|
||||
use Symfony\Component\Security\Core\User\UserCheckerInterface;
|
||||
use Symfony\Component\Security\Core\User\UserInterface;
|
||||
|
||||
final class UserChecker implements UserCheckerInterface
|
||||
{
|
||||
public function checkPreAuth(UserInterface $user): void
|
||||
{
|
||||
if (!$user instanceof User) {
|
||||
return;
|
||||
}
|
||||
|
||||
if ($user->isLocked()) {
|
||||
throw new CustomUserMessageAccountStatusException('Ce compte est verrouillé.');
|
||||
}
|
||||
}
|
||||
|
||||
public function checkPostAuth(UserInterface $user, ?TokenInterface $token = null): void {}
|
||||
}
|
||||
@@ -15,6 +15,7 @@ use App\Repository\BonusRepository;
|
||||
use App\Repository\EmployeeRepository;
|
||||
use App\Repository\EmployeeRttPaymentRepository;
|
||||
use App\Repository\MileageAllowanceRepository;
|
||||
use App\Repository\ObservationRepository;
|
||||
use App\Repository\WorkHourRepository;
|
||||
use App\Service\Contracts\EmployeeContractResolver;
|
||||
use DateInterval;
|
||||
@@ -36,6 +37,7 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
private EmployeeRttPaymentRepository $rttPaymentRepository,
|
||||
private BonusRepository $bonusRepository,
|
||||
private MileageAllowanceRepository $mileageAllowanceRepository,
|
||||
private ObservationRepository $observationRepository,
|
||||
private EmployeeContractResolver $contractResolver,
|
||||
) {}
|
||||
|
||||
@@ -62,20 +64,22 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
$monthNumber = (int) $from->format('n');
|
||||
$rttPayments = $this->rttPaymentRepository->findByYearAndMonth($year, $monthNumber);
|
||||
|
||||
$bonuses = $this->bonusRepository->findByMonth($from, $to);
|
||||
$mileages = $this->mileageAllowanceRepository->findByMonth($from, $to);
|
||||
$bonuses = $this->bonusRepository->findByMonth($from, $to);
|
||||
$mileages = $this->mileageAllowanceRepository->findByMonth($from, $to);
|
||||
$observations = $this->observationRepository->findByMonth($from, $to);
|
||||
|
||||
$days = $this->buildDays($from, $to);
|
||||
$contractMap = $this->contractResolver->resolveForEmployeesAndDays($employees, $days);
|
||||
$driverMap = $this->contractResolver->resolveIsDriverForEmployeesAndDays($employees, $days);
|
||||
|
||||
$workHourMap = $this->buildWorkHourMap($workHours);
|
||||
$absenceMap = $this->buildAbsenceMap($absences);
|
||||
$rttPaymentMap = $this->buildRttPaymentMap($rttPayments);
|
||||
$bonusMap = $this->buildBonusMap($bonuses);
|
||||
$mileageMap = $this->buildMileageMap($mileages);
|
||||
$workHourMap = $this->buildWorkHourMap($workHours);
|
||||
$absenceMap = $this->buildAbsenceMap($absences);
|
||||
$rttPaymentMap = $this->buildRttPaymentMap($rttPayments);
|
||||
$bonusMap = $this->buildBonusMap($bonuses);
|
||||
$mileageMap = $this->buildMileageMap($mileages);
|
||||
$observationMap = $this->buildObservationMap($observations);
|
||||
|
||||
$siteGroups = $this->aggregateBySite($employees, $days, $contractMap, $driverMap, $workHourMap, $absenceMap, $rttPaymentMap, $bonusMap, $mileageMap);
|
||||
$siteGroups = $this->aggregateBySite($employees, $days, $contractMap, $driverMap, $workHourMap, $absenceMap, $rttPaymentMap, $bonusMap, $mileageMap, $observationMap);
|
||||
|
||||
$options = new Options();
|
||||
$options->set('isRemoteEnabled', true);
|
||||
@@ -204,6 +208,23 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
return $map;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return array<int, string>
|
||||
*/
|
||||
private function buildObservationMap(array $observations): array
|
||||
{
|
||||
$map = [];
|
||||
foreach ($observations as $observation) {
|
||||
$employeeId = $observation->getEmployee()?->getId();
|
||||
if (!$employeeId) {
|
||||
continue;
|
||||
}
|
||||
$map[$employeeId] = $observation->getContent();
|
||||
}
|
||||
|
||||
return $map;
|
||||
}
|
||||
|
||||
private function aggregateBySite(
|
||||
array $employees,
|
||||
array $days,
|
||||
@@ -214,6 +235,7 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
array $rttPaymentMap,
|
||||
array $bonusMap,
|
||||
array $mileageMap,
|
||||
array $observationMap,
|
||||
): array {
|
||||
$siteGroups = [];
|
||||
|
||||
@@ -234,6 +256,7 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
$rttPaymentMap[$employeeId] ?? 0,
|
||||
$bonusMap[$employeeId] ?? 0.0,
|
||||
$mileageMap[$employeeId] ?? 0.0,
|
||||
$observationMap[$employeeId] ?? '',
|
||||
);
|
||||
|
||||
if (!isset($siteGroups[$siteId])) {
|
||||
@@ -261,6 +284,7 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
int $rttPaidMinutes,
|
||||
float $bonusAmount,
|
||||
float $mileageKm,
|
||||
string $observation,
|
||||
): array {
|
||||
$contractName = null;
|
||||
$presenceDays = 0.0;
|
||||
@@ -373,6 +397,7 @@ class SalaryRecapPrintProvider implements ProviderInterface
|
||||
'driverMeals' => $driverMeals,
|
||||
'driverOvernight' => $driverOvernight,
|
||||
'driverSaturdays' => $driverSaturdays,
|
||||
'observation' => $observation,
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user