| @@ -4571,7 +4571,6 @@ components: | |||||
| format: iri-reference | format: iri-reference | ||||
| example: 'https://example.com/' | example: 'https://example.com/' | ||||
| pilotageReference: | pilotageReference: | ||||
| readOnly: true | |||||
| type: | type: | ||||
| - string | - string | ||||
| - 'null' | - 'null' | ||||
| @@ -4664,7 +4663,6 @@ components: | |||||
| format: iri-reference | format: iri-reference | ||||
| example: 'https://example.com/' | example: 'https://example.com/' | ||||
| pilotageReference: | pilotageReference: | ||||
| readOnly: true | |||||
| type: | type: | ||||
| - string | - string | ||||
| - 'null' | - 'null' | ||||
| @@ -28,7 +28,7 @@ export class ErrorInterceptor implements HttpInterceptor { | |||||
| this.accountService.logout(); | this.accountService.logout(); | ||||
| } | } | ||||
| console.log(err); | console.log(err); | ||||
| this.alertService.error(err.message + ' - ' + err.error); | |||||
| this.alertService.error(err.error.detail); | |||||
| const error = err.error?.message || err.statusText; | const error = err.error?.message || err.statusText; | ||||
| return throwError(() => error); | return throwError(() => error); | ||||
| @@ -11,6 +11,10 @@ | |||||
| <div class="spt-form"> | <div class="spt-form"> | ||||
| <form [formGroup]="tripForm" (ngSubmit)="onSubmit()"> | <form [formGroup]="tripForm" (ngSubmit)="onSubmit()"> | ||||
| <div class="row"> | <div class="row"> | ||||
| <div class="col-12 col-lg-6 mb-3"> | |||||
| <label for="pilotageReference" class="form-label">{{ 'trip.pilot_reference' | translate }}:</label> | |||||
| <input type="text" class="form-control" id="pilotageReference" formControlName="pilotageReference"/> | |||||
| </div> | |||||
| <div class="col-12 mb-3"> | <div class="col-12 mb-3"> | ||||
| <label for="vesselIri" class="form-label">{{ 'trip.vessel' | translate }}*:</label> | <label for="vesselIri" class="form-label">{{ 'trip.vessel' | translate }}*:</label> | ||||
| <app-search-select #vesselSearchSelect | <app-search-select #vesselSearchSelect | ||||
| @@ -18,7 +18,7 @@ export interface Trip { | |||||
| readonly dbId?: number | null; | readonly dbId?: number | null; | ||||
| readonly vessel?: string; | readonly vessel?: string; | ||||
| vesselIri: string | null; | vesselIri: string | null; | ||||
| readonly pilotageReference?: string | null; | |||||
| pilotageReference?: string | null; | |||||
| readonly startLocation?: string; | readonly startLocation?: string; | ||||
| startLocationIri: string | null; | startLocationIri: string | null; | ||||
| readonly endLocation?: string; | readonly endLocation?: string; | ||||
| @@ -23,7 +23,7 @@ export interface TripJsonld { | |||||
| readonly dbId?: number | null; | readonly dbId?: number | null; | ||||
| readonly vessel?: VesselJsonld; | readonly vessel?: VesselJsonld; | ||||
| vesselIri: string | null; | vesselIri: string | null; | ||||
| readonly pilotageReference?: string | null; | |||||
| pilotageReference?: string | null; | |||||
| readonly startLocation?: LocationJsonld; | readonly startLocation?: LocationJsonld; | ||||
| startLocationIri: string | null; | startLocationIri: string | null; | ||||
| readonly endLocation?: LocationJsonld; | readonly endLocation?: LocationJsonld; | ||||
| @@ -2,4 +2,4 @@ lexik_jwt_authentication: | |||||
| secret_key: '%env(resolve:JWT_SECRET_KEY)%' | secret_key: '%env(resolve:JWT_SECRET_KEY)%' | ||||
| public_key: '%env(resolve:JWT_PUBLIC_KEY)%' | public_key: '%env(resolve:JWT_PUBLIC_KEY)%' | ||||
| pass_phrase: '%env(JWT_PASSPHRASE)%' | pass_phrase: '%env(JWT_PASSPHRASE)%' | ||||
| token_ttl: 1209600 | |||||
| token_ttl: 7776000 | |||||
| @@ -0,0 +1,31 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace DoctrineMigrations; | |||||
| use Doctrine\DBAL\Schema\Schema; | |||||
| use Doctrine\Migrations\AbstractMigration; | |||||
| /** | |||||
| * Auto-generated Migration: Please modify to your needs! | |||||
| */ | |||||
| final class Version20250730143720 extends AbstractMigration | |||||
| { | |||||
| public function getDescription(): string | |||||
| { | |||||
| return ''; | |||||
| } | |||||
| public function up(Schema $schema): void | |||||
| { | |||||
| // this up() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE trip ADD pilotage_reference VARCHAR(255) NOT NULL'); | |||||
| } | |||||
| public function down(Schema $schema): void | |||||
| { | |||||
| // this down() migration is auto-generated, please modify it to your needs | |||||
| $this->addSql('ALTER TABLE trip DROP pilotage_reference'); | |||||
| } | |||||
| } | |||||
| @@ -78,7 +78,7 @@ class TripApi | |||||
| #[ApiProperty(writable: true)] | #[ApiProperty(writable: true)] | ||||
| public ?VesselApi $vesselIri = null; | public ?VesselApi $vesselIri = null; | ||||
| #[ApiProperty(writable: false)] | |||||
| #[ApiProperty(writable: true)] | |||||
| public ?string $pilotageReference = null; | public ?string $pilotageReference = null; | ||||
| /** | /** | ||||
| @@ -0,0 +1,39 @@ | |||||
| <?php | |||||
| declare(strict_types=1); | |||||
| namespace App\Command\Patch; | |||||
| use App\Entity\Event; | |||||
| use App\Entity\Trip; | |||||
| use Doctrine\ORM\EntityManagerInterface; | |||||
| use Symfony\Component\Console\Attribute\AsCommand; | |||||
| use Symfony\Component\Console\Command\Command; | |||||
| use Symfony\Component\Console\Input\InputInterface; | |||||
| use Symfony\Component\Console\Output\OutputInterface; | |||||
| #[AsCommand( | |||||
| name: 'app:patch-001', | |||||
| description: 'Creates pilotage references' | |||||
| )] | |||||
| class Patch001Command extends Command | |||||
| { | |||||
| public function __construct( | |||||
| private readonly EntityManagerInterface $entityManager | |||||
| ) { | |||||
| parent::__construct(); | |||||
| } | |||||
| protected function execute(InputInterface $input, OutputInterface $output): int | |||||
| { | |||||
| $trips = $this->entityManager->getRepository(Trip::class)->findAll(); | |||||
| foreach ($trips as $trip) { | |||||
| $trip->setPilotageReference("P-" . $trip->getId() . "-" . $trip->getStartDate()->format('Y')); | |||||
| } | |||||
| $this->entityManager->flush(); | |||||
| return Command::SUCCESS; | |||||
| } | |||||
| } | |||||
| @@ -18,6 +18,9 @@ class Trip | |||||
| #[ORM\Column] | #[ORM\Column] | ||||
| private ?int $id = null; | private ?int $id = null; | ||||
| #[ORM\Column(length: 255, unique: true)] | |||||
| private ?string $pilotageReference = null; | |||||
| #[ORM\ManyToOne(targetEntity: Vessel::class, inversedBy: 'trips')] | #[ORM\ManyToOne(targetEntity: Vessel::class, inversedBy: 'trips')] | ||||
| #[ORM\JoinColumn(nullable: false)] | #[ORM\JoinColumn(nullable: false)] | ||||
| private Vessel $vessel; | private Vessel $vessel; | ||||
| @@ -74,25 +77,25 @@ class Trip | |||||
| return $this->id; | return $this->id; | ||||
| } | } | ||||
| public function getVessel(): Vessel | |||||
| public function getPilotageReference(): ?string | |||||
| { | { | ||||
| return $this->vessel; | |||||
| return $this->pilotageReference; | |||||
| } | } | ||||
| public function setVessel(Vessel $vessel): self | |||||
| public function setPilotageReference(string $pilotageReference): void | |||||
| { | { | ||||
| $this->vessel = $vessel; | |||||
| return $this; | |||||
| $this->pilotageReference = $pilotageReference; | |||||
| } | } | ||||
| public function getCustomerReference(): ?string | |||||
| public function getVessel(): Vessel | |||||
| { | { | ||||
| return $this->customerReference; | |||||
| return $this->vessel; | |||||
| } | } | ||||
| public function setCustomerReference(?string $customerReference): void | |||||
| public function setVessel(Vessel $vessel): self | |||||
| { | { | ||||
| $this->customerReference = $customerReference; | |||||
| $this->vessel = $vessel; | |||||
| return $this; | |||||
| } | } | ||||
| public function getStartLocation(): Location | public function getStartLocation(): Location | ||||
| @@ -7,6 +7,7 @@ use App\Entity\Trip; | |||||
| use App\Repository\TripRepository; | use App\Repository\TripRepository; | ||||
| use App\Repository\VesselRepository; | use App\Repository\VesselRepository; | ||||
| use App\Repository\LocationRepository; | use App\Repository\LocationRepository; | ||||
| use Symfony\Component\Validator\Exception\ValidatorException; | |||||
| use Symfonycasts\MicroMapper\AsMapper; | use Symfonycasts\MicroMapper\AsMapper; | ||||
| use Symfonycasts\MicroMapper\MapperInterface; | use Symfonycasts\MicroMapper\MapperInterface; | ||||
| use Symfonycasts\MicroMapper\MicroMapperInterface; | use Symfonycasts\MicroMapper\MicroMapperInterface; | ||||
| @@ -77,6 +78,19 @@ class TripApiToEntityMapper implements MapperInterface | |||||
| $entity->setEndDate($dto->endDate); | $entity->setEndDate($dto->endDate); | ||||
| $entity->setNote($dto->note); | $entity->setNote($dto->note); | ||||
| if ($dto->pilotageReference !== $entity->getPilotageReference()) { | |||||
| $existingTrip = $this->repository->findOneBy(['pilotageReference' => $dto->pilotageReference]); | |||||
| if ($existingTrip !== null) { | |||||
| throw new ValidatorException(sprintf( | |||||
| 'A trip with the pilotage reference "%s" already exists.', | |||||
| $dto->pilotageReference | |||||
| )); | |||||
| } | |||||
| $entity->setPilotageReference($dto->pilotageReference); | |||||
| } | |||||
| if ($dto->vesselIri->id) { | if ($dto->vesselIri->id) { | ||||
| $vessel = $this->vesselRepository->find($dto->vesselIri->id); | $vessel = $this->vesselRepository->find($dto->vesselIri->id); | ||||
| if (!$vessel) { | if (!$vessel) { | ||||
| @@ -37,7 +37,7 @@ class TripEntityToApiMapper implements MapperInterface | |||||
| assert($dto instanceof TripApi); | assert($dto instanceof TripApi); | ||||
| $dto->dbId = $entity->getId(); | $dto->dbId = $entity->getId(); | ||||
| $dto->pilotageReference = "P-" . $entity->getId() . "-" . $entity->getStartDate()->format('Y'); | |||||
| $dto->pilotageReference = $entity->getPilotageReference(); | |||||
| $dto->startDate = $entity->getStartDate(); | $dto->startDate = $entity->getStartDate(); | ||||
| $dto->endDate = $entity->getEndDate(); | $dto->endDate = $entity->getEndDate(); | ||||
| $dto->note = $entity->getNote(); | $dto->note = $entity->getNote(); | ||||