115 lines
3.8 KiB
PHP
115 lines
3.8 KiB
PHP
<?php
|
|
|
|
namespace App\Service\Assignment;
|
|
|
|
use App\Entity\Assignment;
|
|
use App\Model\StaffingCandidate;
|
|
use App\Repository\AssignmentRepository;
|
|
use App\Repository\DestinationRepository;
|
|
use App\Repository\StaffingRuleRepository;
|
|
use Doctrine\ORM\EntityManagerInterface;
|
|
use Psr\Log\LoggerInterface;
|
|
|
|
/**
|
|
* Creates the draft assignments the staffing matrix calls for. Shared by app:assignment-generate
|
|
* and the admin preview, so what the stakeholders confirm is what gets generated.
|
|
*/
|
|
class AssignmentGenerator
|
|
{
|
|
public function __construct(
|
|
private readonly StaffingRuleRepository $staffingRuleRepository,
|
|
private readonly DestinationRepository $destinationRepository,
|
|
private readonly AssignmentRepository $assignmentRepository,
|
|
private readonly AssignmentPlanner $planner,
|
|
private readonly StaffingResolver $resolver,
|
|
private readonly EntityManagerInterface $entityManager,
|
|
private readonly LoggerInterface $logger,
|
|
) {
|
|
}
|
|
|
|
/**
|
|
* @param bool $enabledOnly false for the preview, which shows rows not yet switched on
|
|
*
|
|
* @return list<StaffingCandidate>
|
|
*/
|
|
public function getCandidates(bool $enabledOnly, ?\DateTimeImmutable $today = null): array
|
|
{
|
|
$rules = [];
|
|
|
|
foreach ($this->staffingRuleRepository->getList() as $rule) {
|
|
if (false === $enabledOnly || true === $rule->isEnabled()) {
|
|
$rules[$rule->getProductCode()] = $rule;
|
|
}
|
|
}
|
|
|
|
$destinations = $this->destinationRepository->getStaffingCandidates(
|
|
array_map('strval', array_keys($rules)),
|
|
$today ?? new \DateTimeImmutable('today'),
|
|
);
|
|
$skipped = array_flip($this->assignmentRepository->getDestinationIdsWithAnyAssignment($destinations));
|
|
|
|
$candidates = [];
|
|
|
|
foreach ($destinations as $destination) {
|
|
$rule = $rules[$destination->getProductCode()];
|
|
|
|
$candidates[] = new StaffingCandidate(
|
|
$destination,
|
|
$rule,
|
|
$this->planner->plan($rule, $destination),
|
|
isset($skipped[$destination->getId()]),
|
|
);
|
|
}
|
|
|
|
return $candidates;
|
|
}
|
|
|
|
/**
|
|
* Persists and flushes the candidate's drafts.
|
|
*
|
|
* @return list<Assignment>
|
|
*
|
|
* @throws StaffingConfigurationException when a configured job profile or fee is missing
|
|
*/
|
|
public function generate(StaffingCandidate $candidate): array
|
|
{
|
|
if (true === $candidate->skipped) {
|
|
return [];
|
|
}
|
|
|
|
$assignments = [];
|
|
|
|
foreach ($candidate->planned as $planned) {
|
|
$assignment = (new Assignment())
|
|
->setDestination($candidate->destination)
|
|
->setJobProfile($this->resolver->jobProfile($planned->role))
|
|
->setAvailableDispositions($planned->places)
|
|
->setPickup($planned->pickup)
|
|
;
|
|
|
|
foreach ($planned->fees as $fee) {
|
|
$assignment->addFee($this->resolver->fee($fee));
|
|
}
|
|
|
|
$this->entityManager->persist($assignment);
|
|
$assignments[] = $assignment;
|
|
}
|
|
|
|
$this->entityManager->flush();
|
|
|
|
foreach ($assignments as $assignment) {
|
|
$this->logger->info('Generate assignment', [
|
|
'assignment_id' => $assignment->getId(),
|
|
'destination_id' => $candidate->destination->getId(),
|
|
'destination_code' => $candidate->destination->getCode(),
|
|
'product_code' => $candidate->rule->getProductCode(),
|
|
'job_profile' => $assignment->getJobProfile()->getName(),
|
|
'places' => $assignment->getAvailableDispositions(),
|
|
'pickup' => $assignment->getPickup(),
|
|
]);
|
|
}
|
|
|
|
return $assignments;
|
|
}
|
|
}
|