[#331] Mettre à jour l'entité Shipment et bovin_shipment (!30)

| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|      #331           |        Mettre à jour l'entité Shipment et bovin_shipment         |

## Description de la PR

## Modification du .env

## Check list

- [x] Pas de régression
- [ ] TU/TI/TF rédigée
- [x] TU/TI/TF OK
- [x] CHANGELOG modifié

Reviewed-on: https://gitea.malio.fr/MALIO-DEV/Ferme/pulls/30
Reviewed-by: Autin <tristan@yuno.malio.fr>
Co-authored-by: kevin <kevin@yuno.malio.fr>
Co-committed-by: kevin <kevin@yuno.malio.fr>
This commit is contained in:
kevin
2026-02-19 07:47:13 +00:00
committed by Autin
parent 0d258ae9c6
commit e7421e985e
13 changed files with 146 additions and 345 deletions
+1
View File
@@ -49,6 +49,7 @@ Ajouter dans le fichier .env du frontend
* fix layout admin * fix layout admin
* Creation page admin listing bovins * Creation page admin listing bovins
* Creation page admin ajout/modification bovins * Creation page admin ajout/modification bovins
* [#331] Mettre à jour l'entité Shipment et bovin_shipment
### Changed ### Changed
### Fixed ### Fixed
+20 -94
View File
@@ -155,12 +155,6 @@ import {useShipmentStore} from '~/stores/shipment'
import {computed, reactive, ref, watch, onMounted} from 'vue' import {computed, reactive, ref, watch, onMounted} from 'vue'
import type {ShipmentTypeData} from "~/services/dto/shipment-type-data"; import type {ShipmentTypeData} from "~/services/dto/shipment-type-data";
import {getShipmentTypeList} from "~/services/shipment-type"; import {getShipmentTypeList} from "~/services/shipment-type";
import {
createShipmentBovine,
deleteShipmentBovine,
getBovinShipmentList,
updateShipmentBovine
} from "~/services/bovin-shipment";
const users = ref<UserData[]>([]) const users = ref<UserData[]>([])
const customers = ref<CustomerData[]>([]) const customers = ref<CustomerData[]>([])
@@ -332,23 +326,15 @@ watch(
form.carrierId = shipment?.carrier?.id ? String(shipment.carrier.id) : '' form.carrierId = shipment?.carrier?.id ? String(shipment.carrier.id) : ''
form.driverId = shipment?.driver?.id ? String(shipment.driver.id) : '' form.driverId = shipment?.driver?.id ? String(shipment.driver.id) : ''
form.vehicleId = shipment?.vehicle?.id ? String(shipment.vehicle.id) : '' form.vehicleId = shipment?.vehicle?.id ? String(shipment.vehicle.id) : ''
if (!shipment || !shipment.bovinShipments) {
selectedShipmentTypeId.value = ''
shipmentQuantity.value = 0
} else {
const selectedEntry = shipment.bovinShipments.find((entry) => {
const typeId = entry.shipmentType?.id
return Boolean(typeId) && Number(entry.nbBovinSend ?? 0) > 0
}) ?? shipment.bovinShipments.find((entry) => Boolean(entry.shipmentType?.id))
if (!selectedEntry?.shipmentType?.id) {
selectedShipmentTypeId.value = '' selectedShipmentTypeId.value = shipment?.shipmentType?.id
shipmentQuantity.value = 0 ? String(shipment.shipmentType.id)
} else { : ''
selectedShipmentTypeId.value = String(selectedEntry.shipmentType.id)
shipmentQuantity.value = selectedEntry.nbBovinSend ?? 0 shipmentQuantity.value = shipment?.nbBovinSend ?? 0
}
}
isHydrating.value = false isHydrating.value = false
}, },
{immediate: true} {immediate: true}
@@ -474,68 +460,7 @@ watch(
} }
} }
) )
const buildDesiredBovinShipments = () => {
const typeId = Number(selectedShipmentTypeId.value)
if (!Number.isFinite(typeId)) {
return []
}
const type = bovineShipment.value.find((entry) => entry.id === typeId)
if (!type) {
return []
}
const raw = shipmentQuantity.value
const quantity = raw === null || raw === undefined ? 0 : Number(raw)
const normalizedQuantity = Number.isFinite(quantity) ? Math.max(0, Math.trunc(quantity)) : 0
if (normalizedQuantity <= 0) {
return []
}
return [{type, quantity: normalizedQuantity}]
}
const syncBovinShipments = async (
shipmentId: number,
existing: Array<{ id?: number; nbBovinSend: number | null; shipmentType?: unknown }> = []
) => {
const shipmentIri = `/api/shipments/${shipmentId}`
const desired = buildDesiredBovinShipments()
const desiredByTypeId = new Map<number, number>()
for (const entry of desired) {
desiredByTypeId.set(entry.type.id, entry.quantity)
}
for (const entry of existing) {
if (!entry.id) {
continue
}
const rawType = entry.shipmentType
let typeId: number | null = null
if (rawType && typeof rawType === 'object' && 'id' in rawType) {
typeId = Number((rawType as { id: number }).id)
} else if (typeof rawType === 'string') {
const match = rawType.match(/\/shipment_types\/(\\d+)$/)
typeId = match ? Number(match[1]) : null
}
if (!typeId) {
continue
}
const desiredQuantity = desiredByTypeId.get(typeId)
if (!desiredQuantity) {
await deleteShipmentBovine(entry.id)
continue
}
if (entry.nbBovinSend !== desiredQuantity) {
await updateShipmentBovine(entry.id, {nbBovinSend: desiredQuantity})
}
desiredByTypeId.delete(typeId)
}
for (const [typeId, quantity] of desiredByTypeId.entries()) {
await createShipmentBovine({
shipment: shipmentIri,
shipmentType: `/api/shipment_types/${typeId}`,
nbBovinSend: quantity
})
}
}
const buildPayload = () => { const buildPayload = () => {
const normalizedLicensePlate = form.licencePlate.trim() const normalizedLicensePlate = form.licencePlate.trim()
const normalizedShipmentDate = form.shipmentDate.trim() const normalizedShipmentDate = form.shipmentDate.trim()
@@ -563,6 +488,14 @@ const buildPayload = () => {
const addressIri = normalizedAddressId const addressIri = normalizedAddressId
? `/api/addresses/${normalizedAddressId}` ? `/api/addresses/${normalizedAddressId}`
: null : null
const normalizedShipmentTypeId = selectedShipmentTypeId.value.trim()
const shipmentTypeIri = normalizedShipmentTypeId
? `/api/shipment_types/${normalizedShipmentTypeId}`
: null
const rawQuantity = Number(shipmentQuantity.value ?? 0)
const normalizedQuantity = Number.isFinite(rawQuantity) ? Math.max(0,
Math.trunc(rawQuantity)) : 0
return { return {
licencePlate: normalizedLicensePlate, licencePlate: normalizedLicensePlate,
@@ -572,20 +505,19 @@ const buildPayload = () => {
carrier: carrierIri, carrier: carrierIri,
driver: driverIri, driver: driverIri,
user: userIri, user: userIri,
address: addressIri address: addressIri,
shipmentType: shipmentTypeIri,
nbBovinSend: normalizedQuantity,
} }
} }
const saveDraft = async () => { const saveDraft = async () => {
const payload = buildPayload() const payload = buildPayload()
if (!shipmentStore.current) { if (!shipmentStore.current) {
const created = await shipmentStore.createShipment({ await shipmentStore.createShipment({
currentStep: 0, currentStep: 0,
...payload ...payload
}) })
if (created) {
await syncBovinShipments(created.id, [])
}
return return
} }
@@ -593,10 +525,6 @@ const saveDraft = async () => {
currentStep: shipmentStore.current.currentStep, currentStep: shipmentStore.current.currentStep,
...payload ...payload
}) })
await syncBovinShipments(
shipmentStore.current.id,
shipmentStore.current?.bovinShipments ?? []
)
} }
defineExpose({saveDraft}) defineExpose({saveDraft})
@@ -610,7 +538,6 @@ const validate = async () => {
}) })
if (created) { if (created) {
await shipmentStore.loadShipment(created.id) await shipmentStore.loadShipment(created.id)
await syncBovinShipments(created.id, shipmentStore.current?.bovinShipments ?? [])
await router.push(`/shipment/${created.id}`) await router.push(`/shipment/${created.id}`)
} }
return return
@@ -621,6 +548,5 @@ const validate = async () => {
...payload ...payload
}) })
await shipmentStore.loadShipment(shipmentStore.current.id) await shipmentStore.loadShipment(shipmentStore.current.id)
await syncBovinShipments(shipmentStore.current.id, shipmentStore.current?.bovinShipments ?? [])
} }
</script> </script>
@@ -1,6 +1,6 @@
<template> <template>
<div class="flex flex-col items-center gap-[118px]"> <div class="flex flex-col items-center gap-[118px]">
<h1 class="font-bold text-5xl uppercase text-primary-500">Charment des bovins</h1> <h1 class="font-bold text-5xl uppercase text-primary-500">Chargement des bovins</h1>
<div <div
class="w-full flex flex-col items-center justify-center"> class="w-full flex flex-col items-center justify-center">
<UiLoadingDots /> <UiLoadingDots />
+11 -10
View File
@@ -28,9 +28,9 @@
<div>{{ shipment.customer?.name }}</div> <div>{{ shipment.customer?.name }}</div>
<div>{{ shipment.address?.fullAddress }}</div> <div>{{ shipment.address?.fullAddress }}</div>
<div> <div>
<template v-if="formatBovinShipmentLines(shipment).length"> <template v-if="formatShipmentLines(shipment).length">
<div <div
v-for="(line, index) in formatBovinShipmentLines(shipment)" v-for="(line, index) in formatShipmentLines(shipment)"
:key="index" :key="index"
class="leading-5" class="leading-5"
> >
@@ -62,16 +62,17 @@ const formatWeighing = (shipment: ShipmentData) => {
return `${gross - tare} kg` return `${gross - tare} kg`
} }
const formatBovinShipmentLines = (shipment: ShipmentData) => {
if (!shipment.bovinShipments?.length) { const formatShipmentLines = (shipment: ShipmentData) => {
if (!shipment.shipmentType && shipment.nbBovinSend == null) {
return [] return []
} }
return shipment.bovinShipments.map((entry) => {
const label = typeof entry.shipmentType === 'string' const label = typeof shipment.shipmentType === 'string'
? entry.shipmentType ? shipment.shipmentType
: entry.shipmentType?.label : shipment.shipmentType?.label
return `${label ?? ''} : ${entry.nbBovinSend ?? ''}`
}) return [`${label ?? ''} : ${shipment.nbBovinSend ?? ''}`]
} }
const goShipment = (id: number) => { const goShipment = (id: number) => {
+12 -11
View File
@@ -24,12 +24,12 @@
@click="goToShipment(shipment.id)" @click="goToShipment(shipment.id)"
@keydown.enter="goToShipment(shipment.id)" @keydown.enter="goToShipment(shipment.id)"
> >
<div>{{ shipment.customer?.label }}</div> <div>{{ shipment.customer?.name }}</div>
<div>{{ shipment.address?.fullAddress }}</div> <div>{{ shipment.address?.fullAddress }}</div>
<div> <div>
<template v-if="formatBovinShipmentLines(shipment).length"> <template v-if="formatShipmentLines(shipment).length">
<div <div
v-for="(line, index) in formatBovinShipmentLines(shipment)" v-for="(line, index) in formatShipmentLines(shipment)"
:key="index" :key="index"
class="leading-5" class="leading-5"
> >
@@ -55,16 +55,17 @@ const router = useRouter()
const goToShipment = (id: number) => { const goToShipment = (id: number) => {
router.push(`/shipment/${id}`) router.push(`/shipment/${id}`)
} }
const formatBovinShipmentLines = (shipment: ShipmentData) => {
if (!shipment.bovinShipments?.length) { const formatShipmentLines = (shipment: ShipmentData) => {
if (!shipment.shipmentType && shipment.nbBovinSend == null) {
return [] return []
} }
return shipment.bovinShipments.map((entry) => {
const label = typeof entry.shipmentType === 'string' const label = typeof shipment.shipmentType === 'string'
? entry.shipmentType ? shipment.shipmentType
: entry.shipmentType?.label : shipment.shipmentType?.label
return `${label ?? ''} : ${entry.nbBovinSend ?? ''}`
}) return [`${label ?? ''} : ${shipment.nbBovinSend ?? ''}`]
} }
onMounted(async () => { onMounted(async () => {
-50
View File
@@ -1,50 +0,0 @@
import { useApi } from '~/composables/useApi'
import type { BovinShipmentData } from '~/services/dto/bovin-shipment-data'
import type { ShipmentBovinePayload, BovinShipmentListResponse } from '~/services/dto/bovin-shipment-data'
export async function getBovinShipmentList(
shipmentIri: string
): Promise<BovinShipmentData[]> {
const api = useApi()
const response = await api.get<BovinShipmentListResponse>(
'bovin_shipments',
{ shipment: shipmentIri },
{
toastErrorKey: 'errors.shipmentBovine.list'
}
)
if (Array.isArray(response)) {
return response
}
if (response && typeof response === 'object' && Array.isArray(response['hydra:member'])) {
return response['hydra:member']
}
return []
}
export async function createShipmentBovine(
payload: ShipmentBovinePayload
): Promise<BovinShipmentData> {
const api = useApi()
return api.post<BovinShipmentData>('bovin_shipments', payload, {
toastErrorKey: 'errors.shipmentBovine.create'
})
}
export async function deleteShipmentBovine(id: number): Promise<void> {
const api = useApi()
await api.delete<void>(`bovin_shipments/${id}`, {}, {
toastErrorKey: 'errors.shipmentBovine.delete'
})
}
export async function updateShipmentBovine(
id: number,
payload: Partial<ShipmentBovinePayload>
): Promise<BovinShipmentData> {
const api = useApi()
return api.patch<BovinShipmentData>(`bovin_shipments/${id}`, payload, {
toastErrorKey: 'errors.shipmentBovine.update'
})
}
@@ -1,18 +0,0 @@
import type {ShipmentTypeData} from "~/services/dto/shipment-type-data";
export interface BovinShipmentData {
id: number
nbBovinSend: number | null
shipment?: string | null
shipmentType?: ShipmentTypeData | null
}
export type ShipmentBovinePayload = {
nbBovinSend: number
shipment: string
shipmentType: string
}
export type BovinShipmentListResponse =
| BovinShipmentData[]
| { 'hydra:member'?: BovinShipmentData[] }
+4 -9
View File
@@ -9,12 +9,6 @@ export interface ShipmentTypeData {
code: string code: string
} }
export interface BovinShipmentData {
id?: number
shipmentType?: ShipmentTypeData | string | null
nbBovinSend: number | null
}
export type ShipmentData = { export type ShipmentData = {
id: number id: number
identificationNumber?: string | null identificationNumber?: string | null
@@ -26,7 +20,8 @@ export type ShipmentData = {
carrier?: CarrierData | null carrier?: CarrierData | null
truck?: TruckData | null truck?: TruckData | null
customer?: CustomerData | null customer?: CustomerData | null
bovinShipments?: BovinShipmentData[] | null shipmentType?: ShipmentTypeData | null
nbBovinSend?: number | null
weights?: WeightShipmentEntryData[] | null weights?: WeightShipmentEntryData[] | null
} }
@@ -59,9 +54,9 @@ export type ShipmentPayload = {
carrier?: string | null carrier?: string | null
truck?: string | null truck?: string | null
customer?: string | null customer?: string | null
bovinShipments?: string[] | null
address?: string | null address?: string | null
user?: string | null user?: string | null
driver?: string | null driver?: string | null
shipmentType?: string | null
nbBovinSend?: number | null
} }
+52
View File
@@ -0,0 +1,52 @@
<?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 Version20260218144828 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 bovin_shipment DROP CONSTRAINT fk_7049f4502ee48a36');
$this->addSql('ALTER TABLE bovin_shipment DROP CONSTRAINT fk_7049f4507be036fc');
$this->addSql('DROP TABLE bovin_shipment');
$this->addSql('ALTER TABLE shipment ADD nb_bovin_send INT NOT NULL');
$this->addSql('ALTER TABLE shipment ADD shipment_type_id INT DEFAULT NULL');
$this->addSql('ALTER TABLE shipment ADD CONSTRAINT FK_2CB20DC2EE48A36 FOREIGN KEY (shipment_type_id) REFERENCES shipment_type (id) NOT DEFERRABLE');
$this->addSql('CREATE INDEX IDX_2CB20DC2EE48A36 ON shipment (shipment_type_id)');
$this->addSql('DROP INDEX uniq_weight_shipment_type');
$this->addSql('DROP INDEX uniq_weight_reception_type');
$this->addSql('ALTER INDEX idx_weight_shipment RENAME TO IDX_7CD55417BE036FC');
}
public function down(Schema $schema): void
{
// this down() migration is auto-generated, please modify it to your needs
$this->addSql('CREATE TABLE bovin_shipment (id INT GENERATED BY DEFAULT AS IDENTITY NOT NULL, nb_bovin_send INT NOT NULL, shipment_id INT DEFAULT NULL, shipment_type_id INT DEFAULT NULL, PRIMARY KEY (id))');
$this->addSql('CREATE INDEX idx_7049f4507be036fc ON bovin_shipment (shipment_id)');
$this->addSql('CREATE INDEX idx_7049f4502ee48a36 ON bovin_shipment (shipment_type_id)');
$this->addSql('CREATE UNIQUE INDEX uniq_bovin_shipment_one_type ON bovin_shipment (shipment_id)');
$this->addSql('ALTER TABLE bovin_shipment ADD CONSTRAINT fk_7049f4502ee48a36 FOREIGN KEY (shipment_type_id) REFERENCES shipment_type (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE bovin_shipment ADD CONSTRAINT fk_7049f4507be036fc FOREIGN KEY (shipment_id) REFERENCES shipment (id) NOT DEFERRABLE INITIALLY IMMEDIATE');
$this->addSql('ALTER TABLE shipment DROP CONSTRAINT FK_2CB20DC2EE48A36');
$this->addSql('DROP INDEX IDX_2CB20DC2EE48A36');
$this->addSql('ALTER TABLE shipment DROP nb_bovin_send');
$this->addSql('ALTER TABLE shipment DROP shipment_type_id');
$this->addSql('CREATE UNIQUE INDEX uniq_weight_shipment_type ON weight (shipment_id, type)');
$this->addSql('CREATE UNIQUE INDEX uniq_weight_reception_type ON weight (reception_id, type)');
$this->addSql('ALTER INDEX idx_7cd55417be036fc RENAME TO idx_weight_shipment');
}
}
-101
View File
@@ -1,101 +0,0 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
use ApiPlatform\Metadata\ApiFilter;
use ApiPlatform\Metadata\ApiProperty;
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 Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity]
#[ApiFilter(SearchFilter::class, properties: ['shipment' => 'exact'])]
#[ORM\UniqueConstraint(name: 'uniq_bovin_shipment_one_type', columns: ['shipment_id'])]
#[ORM\Table(name: 'bovin_shipment')]
#[ApiResource(
operations: [
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment-bovine:read']],
),
new GetCollection(
normalizationContext: ['groups' => ['shipment-bovine:read']],
),
new Post(
normalizationContext: ['groups' => ['shipment-bovine:read']],
denormalizationContext: ['groups' => ['shipment-bovine:write']],
),
new Patch(
normalizationContext: ['groups' => ['shipment-bovine:read']],
denormalizationContext: ['groups' => ['shipment-bovine:write']],
),
new Delete(),
],
security: "is_granted('ROLE_USER')",
)]
class BovinShipment
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['shipment:read', 'shipment-bovine:read'])]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'bovinShipments')]
#[Groups(['shipment-bovine:read', 'shipment-bovine:write'])]
#[ApiProperty(readableLink: true)]
private ?Shipment $shipment = null;
#[ORM\ManyToOne]
#[Groups(['shipment:read', 'shipment-bovine:write', 'shipment-bovine:read'])]
#[ApiProperty(readableLink: true)]
private ?ShipmentType $shipmentType = null;
#[ORM\Column]
#[Groups(['shipment:read', 'shipment-bovine:write', 'shipment-bovine:read'])]
private ?int $nbBovinSend = null;
public function getId(): ?int
{
return $this->id;
}
public function getShipment(): ?Shipment
{
return $this->shipment;
}
public function setShipment(?Shipment $shipment): void
{
$this->shipment = $shipment;
}
public function getShipmentType(): ?ShipmentType
{
return $this->shipmentType;
}
public function setShipmentType(?ShipmentType $shipmentType): void
{
$this->shipmentType = $shipmentType;
}
public function getNbBovinSend(): ?int
{
return $this->nbBovinSend;
}
public function setNbBovinSend(?int $nbBovinSend): void
{
$this->nbBovinSend = $nbBovinSend;
}
}
+28 -42
View File
@@ -123,17 +123,15 @@ class Shipment
#[ApiProperty(readableLink: true)] #[ApiProperty(readableLink: true)]
private ?Customer $customer = null; private ?Customer $customer = null;
/** #[ORM\ManyToOne(inversedBy: 'shipments')]
* @var Collection<int, BovinShipment> #[ORM\JoinColumn(nullable: true)]
*/
#[ORM\OneToMany(
targetEntity: BovinShipment::class,
mappedBy: 'shipment',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
#[Groups(['shipment:read', 'shipment:write'])] #[Groups(['shipment:read', 'shipment:write'])]
private Collection $bovinShipments; #[ApiProperty(readableLink: true)]
private ?ShipmentType $shipmentType = null;
#[ORM\Column]
#[Groups(['shipment:read', 'shipment:write'])]
private int $nbBovinSend = 0;
/** /**
* @var Collection<int, Weight> * @var Collection<int, Weight>
@@ -156,7 +154,6 @@ class Shipment
public function __construct() public function __construct()
{ {
$this->bovinShipments = new ArrayCollection();
$this->weights = new ArrayCollection(); $this->weights = new ArrayCollection();
} }
@@ -195,6 +192,26 @@ class Shipment
$this->currentStep = $currentStep; $this->currentStep = $currentStep;
} }
public function getShipmentType(): ?ShipmentType
{
return $this->shipmentType;
}
public function setShipmentType(?ShipmentType $shipmentType): void
{
$this->shipmentType = $shipmentType;
}
public function getNbBovinSend(): int
{
return $this->nbBovinSend;
}
public function setNbBovinSend(int $nbBovinSend): void
{
$this->nbBovinSend = $nbBovinSend;
}
public function getIsValid(): ?bool public function getIsValid(): ?bool
{ {
return $this->isValid; return $this->isValid;
@@ -261,37 +278,6 @@ class Shipment
$this->customer = $customer; $this->customer = $customer;
} }
public function getBovinShipments(): Collection
{
return $this->bovinShipments;
}
public function setBovinShipments(Collection $bovinShipments): void
{
$this->bovinShipments = $bovinShipments;
}
public function addBovinShipment(BovinShipment $bovinShipment): self
{
if (!$this->bovinShipments->contains($bovinShipment)) {
$this->bovinShipments->add($bovinShipment);
$bovinShipment->setShipment($this);
}
return $this;
}
public function removeBovinShipment(BovinShipment $bovinShipment): self
{
if ($this->bovinShipments->removeElement($bovinShipment)) {
if ($bovinShipment->getShipment() === $this) {
$bovinShipment->setShipment(null);
}
}
return $this;
}
/** /**
* @return Collection<int, Weight> * @return Collection<int, Weight>
*/ */
+10
View File
@@ -7,6 +7,8 @@ namespace App\Entity;
use ApiPlatform\Metadata\ApiResource; use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get; use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection; use ApiPlatform\Metadata\GetCollection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM; use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups; use Symfony\Component\Serializer\Attribute\Groups;
@@ -40,6 +42,14 @@ class ShipmentType
#[Groups(['shipment-type:read', 'shipment:read'])] #[Groups(['shipment-type:read', 'shipment:read'])]
private ?string $code = null; private ?string $code = null;
#[ORM\OneToMany(mappedBy: 'shipmentType', targetEntity: Shipment::class)]
private Collection $shipments;
public function __construct()
{
$this->shipments = new ArrayCollection();
}
public function getId(): ?int public function getId(): ?int
{ {
return $this->id; return $this->id;
+3 -5
View File
@@ -250,13 +250,11 @@
<td> <td>
<strong>Bovin</strong><br><br> <strong>Bovin</strong><br><br>
<div class="bigtable-notes"> <div class="bigtable-notes">
{% if shipment.bovinShipments is not empty %} {% if shipment.shipmentType %}
{% for entry in shipment.bovinShipments %}
<p> <p>
{{ entry.shipmentType ? entry.shipmentType.label : '-' }} : {{ shipment.shipmentType.label ?? '-' }} :
{{ entry.nbBovinSend ?? 0 }} {{ shipment.nbBovinSend ?? 0 }}
</p> </p>
{% endfor %}
{% else %} {% else %}
<p>-</p> <p>-</p>
{% endif %} {% endif %}