Add addressee history to ticket serialization

This update extends the tickets serialization and normalisation process to include addressee history. With the changes, AddresseeHistory class now also keeps track of who removed an addressee. Additional types, tests and interfaces have been introduced to support this change.
This commit is contained in:
Julien Fastré 2024-04-23 23:39:01 +02:00
parent ed45f14a45
commit 45828174d1
Signed by: julienfastre
GPG Key ID: BDE2190974723FCB
5 changed files with 89 additions and 9 deletions

View File

@ -51,6 +51,8 @@ export interface UserGroup {
excludeKey: string, excludeKey: string,
} }
export type UserGroupOrUser = User | UserGroup;
export interface UserAssociatedInterface { export interface UserAssociatedInterface {
type: "user"; type: "user";
id: number; id: number;

View File

@ -18,9 +18,11 @@ use Chill\MainBundle\Doctrine\Model\TrackUpdateTrait;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup; use Chill\MainBundle\Entity\UserGroup;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Annotation as Serializer;
#[ORM\Entity()] #[ORM\Entity()]
#[ORM\Table(name: 'addressee_history', schema: 'chill_ticket')] #[ORM\Table(name: 'addressee_history', schema: 'chill_ticket')]
#[Serializer\DiscriminatorMap(typeProperty: 'type', mapping: ['ticket_addressee_history' => AddresseeHistory::class])]
class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface
{ {
use TrackCreationTrait; use TrackCreationTrait;
@ -29,6 +31,7 @@ class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface
#[ORM\Id] #[ORM\Id]
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: false)] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::INTEGER, nullable: false)]
#[ORM\GeneratedValue(strategy: 'AUTO')] #[ORM\GeneratedValue(strategy: 'AUTO')]
#[Serializer\Groups(['read'])]
private ?int $id = null; private ?int $id = null;
#[ORM\ManyToOne(targetEntity: User::class)] #[ORM\ManyToOne(targetEntity: User::class)]
@ -39,11 +42,19 @@ class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface
#[ORM\JoinColumn(nullable: true)] #[ORM\JoinColumn(nullable: true)]
private ?UserGroup $addresseeGroup = null; private ?UserGroup $addresseeGroup = null;
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: true, options: ['default' => 'null'])]
#[Serializer\Groups(['read'])]
private ?\DateTimeImmutable $endDate = null; private ?\DateTimeImmutable $endDate = null;
#[ORM\ManyToOne(targetEntity: User::class)]
#[ORM\JoinColumn(nullable: true)]
#[Serializer\Groups(['read'])]
private ?User $removedBy = null;
public function __construct( public function __construct(
User|UserGroup $addressee, User|UserGroup $addressee,
#[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: false)] #[ORM\Column(type: \Doctrine\DBAL\Types\Types::DATETIME_IMMUTABLE, nullable: false)]
#[Serializer\Groups(['read'])]
private \DateTimeImmutable $startDate, private \DateTimeImmutable $startDate,
#[ORM\ManyToOne(targetEntity: Ticket::class)] #[ORM\ManyToOne(targetEntity: Ticket::class)]
#[ORM\JoinColumn(nullable: false)] #[ORM\JoinColumn(nullable: false)]
@ -58,6 +69,7 @@ class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface
$this->ticket->addAddresseeHistory($this); $this->ticket->addAddresseeHistory($this);
} }
#[Serializer\Groups(['read'])]
public function getAddressee(): UserGroup|User public function getAddressee(): UserGroup|User
{ {
if (null !== $this->addresseeGroup) { if (null !== $this->addresseeGroup) {
@ -97,6 +109,18 @@ class AddresseeHistory implements TrackUpdateInterface, TrackCreationInterface
return $this->ticket; return $this->ticket;
} }
public function getRemovedBy(): ?User
{
return $this->removedBy;
}
public function setRemovedBy(?User $removedBy): self
{
$this->removedBy = $removedBy;
return $this;
}
public function setEndDate(?\DateTimeImmutable $endDate): self public function setEndDate(?\DateTimeImmutable $endDate): self
{ {
$this->endDate = $endDate; $this->endDate = $endDate;

View File

@ -1,4 +1,10 @@
import {DateTime, TranslatableString, User} from "../../../../ChillMainBundle/Resources/public/types"; import {
DateTime,
TranslatableString,
User,
UserGroup,
UserGroupOrUser
} from "../../../../ChillMainBundle/Resources/public/types";
import {Person} from "../../../../ChillPersonBundle/Resources/public/types"; import {Person} from "../../../../ChillPersonBundle/Resources/public/types";
export interface Motive { export interface Motive {
@ -46,18 +52,33 @@ interface Comment {
updatedAt: DateTime|null, updatedAt: DateTime|null,
} }
interface AddresseeHistory {
type: "ticket_addressee_history",
id: number,
startDate: DateTime|null,
addressee: UserGroupOrUser,
endDate: DateTime|null,
removedBy: User|null,
createdBy: User|null,
createdAt: DateTime|null,
updatedBy: User|null,
updatedAt: DateTime|null,
}
interface AddPersonEvent extends TicketHistory<"add_person", PersonHistory> {}; interface AddPersonEvent extends TicketHistory<"add_person", PersonHistory> {};
interface AddCommentEvent extends TicketHistory<"add_comment", Comment> {}; interface AddCommentEvent extends TicketHistory<"add_comment", Comment> {};
interface SetMotiveEvent extends TicketHistory<"set_motive", MotiveHistory> {}; interface SetMotiveEvent extends TicketHistory<"set_motive", MotiveHistory> {};
interface AddAddressee extends TicketHistory<"add_addressee", AddresseeHistory> {};
type TicketHistoryLine = AddPersonEvent | AddCommentEvent | SetMotiveEvent; type TicketHistoryLine = AddPersonEvent | AddCommentEvent | SetMotiveEvent | AddAddressee;
export interface Ticket { export interface Ticket {
type: "ticket_ticket" type: "ticket_ticket",
id: number id: number,
externalRef: string externalRef: string,
currentPersons: Person[] currentAddressees: UserGroupOrUser[],
currentMotive: null|Motive currentPersons: Person[],
currentMotive: null|Motive,
history: TicketHistoryLine[], history: TicketHistoryLine[],
} }

View File

@ -11,6 +11,7 @@ declare(strict_types=1);
namespace Chill\TicketBundle\Serializer\Normalizer; namespace Chill\TicketBundle\Serializer\Normalizer;
use Chill\TicketBundle\Entity\AddresseeHistory;
use Chill\TicketBundle\Entity\Comment; use Chill\TicketBundle\Entity\Comment;
use Chill\TicketBundle\Entity\MotiveHistory; use Chill\TicketBundle\Entity\MotiveHistory;
use Chill\TicketBundle\Entity\PersonHistory; use Chill\TicketBundle\Entity\PersonHistory;
@ -79,6 +80,24 @@ final class TicketNormalizer implements NormalizerInterface, NormalizerAwareInte
], ],
$ticket->getComments()->toArray(), $ticket->getComments()->toArray(),
), ),
...array_map(
fn (AddresseeHistory $history) => [
'event_type' => 'add_addressee',
'at' => $history->getStartDate(),
'by' => $history->getCreatedBy(),
'data' => $history,
],
$ticket->getAddresseeHistories()->toArray(),
),
...array_map(
fn (AddresseeHistory $history) => [
'event_type' => 'remove_addressee',
'at' => $history->getStartDate(),
'by' => $history->getRemovedBy(),
'data' => $history,
],
$ticket->getAddresseeHistories()->filter(fn (AddresseeHistory $history) => null !== $history->getEndDate())->toArray()
),
]; ];
usort( usort(

View File

@ -12,7 +12,9 @@ declare(strict_types=1);
namespace Chill\TicketBundle\Tests\Serializer\Normalizer; namespace Chill\TicketBundle\Tests\Serializer\Normalizer;
use Chill\MainBundle\Entity\User; use Chill\MainBundle\Entity\User;
use Chill\MainBundle\Entity\UserGroup;
use Chill\PersonBundle\Entity\Person; use Chill\PersonBundle\Entity\Person;
use Chill\TicketBundle\Entity\AddresseeHistory;
use Chill\TicketBundle\Entity\Comment; use Chill\TicketBundle\Entity\Comment;
use Chill\TicketBundle\Entity\Motive; use Chill\TicketBundle\Entity\Motive;
use Chill\TicketBundle\Entity\MotiveHistory; use Chill\TicketBundle\Entity\MotiveHistory;
@ -108,6 +110,8 @@ class TicketNormalizerTest extends KernelTestCase
->willReturn(['motiveHistory']); ->willReturn(['motiveHistory']);
$normalizer->normalize(Argument::type(Comment::class), 'json', Argument::type('array')) $normalizer->normalize(Argument::type(Comment::class), 'json', Argument::type('array'))
->willReturn(['comment']); ->willReturn(['comment']);
$normalizer->normalize(Argument::type(AddresseeHistory::class), 'json', Argument::type('array'))
->willReturn(['addresseeHistory']);
// null values // null values
$normalizer->normalize(null, 'json', Argument::type('array'))->willReturn(null); $normalizer->normalize(null, 'json', Argument::type('array'))->willReturn(null);
@ -142,6 +146,9 @@ class TicketNormalizerTest extends KernelTestCase
$comment = new Comment('blabla test', $ticket); $comment = new Comment('blabla test', $ticket);
$comment->setCreatedAt(new \DateTimeImmutable('2024-04-01T12:04:00')); $comment->setCreatedAt(new \DateTimeImmutable('2024-04-01T12:04:00'));
$comment->setCreatedBy(new User()); $comment->setCreatedBy(new User());
$addresseeHistory = new AddresseeHistory(new User(), new \DateTimeImmutable('2024-04-01T12:05:00'), $ticket);
$addresseeHistory->setEndDate(new \DateTimeImmutable('2024-04-01T12:06:00'));
new AddresseeHistory(new UserGroup(), new \DateTimeImmutable('2024-04-01T12:07:00'), $ticket);
yield [ yield [
$ticket, $ticket,
@ -150,10 +157,17 @@ class TicketNormalizerTest extends KernelTestCase
'id' => null, 'id' => null,
'externalRef' => '2134', 'externalRef' => '2134',
'currentPersons' => ['embedded'], 'currentPersons' => ['embedded'],
'currentAddressees' => [], 'currentAddressees' => ['embedded'],
'currentInputs' => [], 'currentInputs' => [],
'currentMotive' => ['type' => 'motive', 'id' => 0], 'currentMotive' => ['type' => 'motive', 'id' => 0],
'history' => [['event_type' => 'add_person'], ['event_type' => 'set_motive'], ['event_type' => 'add_comment']], 'history' => [
['event_type' => 'add_person'],
['event_type' => 'set_motive'],
['event_type' => 'add_comment'],
['event_type' => 'add_addressee'],
['event_type' => 'remove_addressee'],
['event_type' => 'add_addressee'],
],
], ],
]; ];
} }