Feature: [acp] record the step history of each accompanying period

Each time a step is changed on an history, a record is stored in a
dedicated table.

When the acp's opening date is moved, the first row is adapted to match the new opening's date. This
mechanisme does not work if the opening date is move beyon the first end
date (if any), nor on the closing date.
This commit is contained in:
2022-10-14 14:36:40 +02:00
parent 66f282e221
commit 59e21b6819
5 changed files with 293 additions and 27 deletions

View File

@@ -22,6 +22,7 @@ use Chill\MainBundle\Entity\Scope;
use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserJob;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodLocationHistory;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodStepHistory;
use Chill\PersonBundle\Entity\AccompanyingPeriod\AccompanyingPeriodWork;
use Chill\PersonBundle\Entity\AccompanyingPeriod\ClosingMotive;
use Chill\PersonBundle\Entity\AccompanyingPeriod\Comment;
@@ -336,6 +337,12 @@ class AccompanyingPeriod implements
*/
private string $step = self::STEP_DRAFT;
/**
* @ORM\OneToMany(targetEntity=AccompanyingPeriodStepHistory::class,
* mappedBy="period", cascade={"persist", "remove"}, orphanRemoval=true)
*/
private Collection $stepHistories;
/**
* @ORM\Column(type="datetime", nullable=true, options={"default": NULL})
*/
@@ -390,7 +397,6 @@ class AccompanyingPeriod implements
*/
public function __construct(?DateTime $dateOpening = null)
{
$this->setOpeningDate($dateOpening ?? new DateTime('now'));
$this->participations = new ArrayCollection();
$this->scopes = new ArrayCollection();
$this->socialIssues = new ArrayCollection();
@@ -399,6 +405,8 @@ class AccompanyingPeriod implements
$this->resources = new ArrayCollection();
$this->userHistories = new ArrayCollection();
$this->locationHistories = new ArrayCollection();
$this->stepHistories = new ArrayCollection();
$this->setOpeningDate($dateOpening ?? new DateTime('now'));
}
/**
@@ -966,6 +974,11 @@ class AccompanyingPeriod implements
return $this->step;
}
public function getStepHistories(): Collection
{
return $this->stepHistories;
}
public function getUser(): ?User
{
return $this->user;
@@ -1234,7 +1247,11 @@ class AccompanyingPeriod implements
*/
public function setOpeningDate($openingDate)
{
$this->openingDate = $openingDate;
if ($this->openingDate !== $openingDate) {
$this->openingDate = $openingDate;
$this->ensureStepContinuity();
}
return $this;
}
@@ -1333,6 +1350,14 @@ class AccompanyingPeriod implements
$this->bootPeriod();
}
if (self::STEP_DRAFT !== $this->step && $previous !== $step) {
// we create a new history
$history = new AccompanyingPeriodStepHistory();
$history->setStep($this->step)->setStartDate(new DateTimeImmutable('now'));
$this->addStepHistory($history);
}
return $this;
}
@@ -1373,6 +1398,17 @@ class AccompanyingPeriod implements
return $this;
}
private function addStepHistory(AccompanyingPeriodStepHistory $stepHistory): self
{
if (!$this->stepHistories->contains($stepHistory)) {
$this->stepHistories[] = $stepHistory;
$stepHistory->setPeriod($this);
$this->ensureStepContinuity();
}
return $this;
}
private function bootPeriod(): void
{
// first location history
@@ -1384,6 +1420,43 @@ class AccompanyingPeriod implements
$this->addLocationHistory($locationHistory);
}
private function ensureStepContinuity(): void
{
// ensure continuity of histories
$criteria = new Criteria();
$criteria->orderBy(['startDate' => Criteria::ASC, 'id' => Criteria::ASC]);
/** @var Iterator $steps */
$steps = $this->getStepHistories()->matching($criteria)->getIterator();
$steps->rewind();
// we set the start date of the first step as the opening date, only if it is
// not greater than the end date
/** @var AccompanyingPeriodStepHistory $current */
$current = $steps->current();
if (null === $current) {
return;
}
if ($this->getOpeningDate()->format('Y-m-d') !== $current->getStartDate()->format('Y-m-d')
&& ($this->getOpeningDate() <= $current->getEndDate() || null === $current->getEndDate())) {
$current->setStartDate(DateTimeImmutable::createFromMutable($this->getOpeningDate()));
}
// then we set all the end date to the start date of the next one
do {
/** @var AccompanyingPeriodStepHistory $current */
$current = $steps->current();
$steps->next();
if ($steps->valid()) {
$next = $steps->current();
$current->setEndDate($next->getStartDate());
}
} while ($steps->valid());
}
private function setRequestorPerson(?Person $requestorPerson = null): self
{
$this->requestorPerson = $requestorPerson;

View File

@@ -0,0 +1,115 @@
<?php
declare(strict_types=1);
/*
* Chill is a software for social workers
*
* For the full copyright and license information, please view
* the LICENSE file that was distributed with this source code.
*/
namespace Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\MainBundle\Doctrine\Model\TrackCreationInterface;
use Chill\MainBundle\Doctrine\Model\TrackCreationTrait;
use Chill\MainBundle\Doctrine\Model\TrackUpdateInterface;
use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\PersonBundle\Entity\AccompanyingPeriod;
use Chill\PersonBundle\Entity\Person;
use DateTimeImmutable;
use Doctrine\ORM\Mapping as ORM;
/**
* @ORM\Entity
* @ORM\Table("chill_person_accompanying_period_step_history")
*/
class AccompanyingPeriodStepHistory implements TrackCreationInterface, TrackUpdateInterface
{
use TrackCreationTrait;
use TrackUpdateTrait;
/**
* @ORM\Column(type="date_immutable", nullable=true, options={"default": null})
*/
private ?DateTimeImmutable $endDate = null;
/**
* @ORM\Id
* @ORM\GeneratedValue
* @ORM\Column(type="integer")
*/
private ?int $id = null;
/**
* @ORM\ManyToOne(targetEntity=AccompanyingPeriod::class)
*/
private AccompanyingPeriod $period;
/**
* @ORM\Column(type="date_immutable")
*/
private ?DateTimeImmutable $startDate = null;
/**
* @ORM\Column(type="text", nullable=false)
*/
private string $step;
public function getEndDate(): ?DateTimeImmutable
{
return $this->endDate;
}
public function getId(): ?int
{
return $this->id;
}
public function getPeriod(): AccompanyingPeriod
{
return $this->period;
}
public function getStartDate(): ?DateTimeImmutable
{
return $this->startDate;
}
public function getStep(): string
{
return $this->step;
}
public function setEndDate(?DateTimeImmutable $endDate): self
{
$this->endDate = $endDate;
return $this;
}
/**
* @internal use AccompanyingPeriod::addLocationHistory
*/
public function setPeriod(AccompanyingPeriod $period): self
{
$this->period = $period;
return $this;
}
public function setStartDate(?DateTimeImmutable $startDate): self
{
$this->startDate = $startDate;
return $this;
}
public function setStep(string $step): AccompanyingPeriodStepHistory
{
$this->step = $step;
return $this;
}
}