[#271]Créer une nouvelle expédition (étape 1) (!12)

| Numéro du ticket | Titre du ticket |
|------------------|-----------------|
|          #271        |         Créer une nouvelle expédition (étape 1)        |

## 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é

Co-authored-by: kevin <kevin@yuno.malio.fr>
Reviewed-on: https://gitea.malio.fr/MALIO-DEV/Ferme/pulls/12
Reviewed-by: Autin <tristan@yuno.malio.fr>
Co-authored-by: Matteo <matteo@yuno.malio.fr>
Co-committed-by: Matteo <matteo@yuno.malio.fr>
This commit is contained in:
Matteo
2026-02-12 07:31:40 +00:00
committed by Kevin Boudet
parent ab6de16319
commit b1c3952d09
50 changed files with 2842 additions and 335 deletions
+3 -3
View File
@@ -12,11 +12,11 @@ use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
final readonly class PontBasculeReading
{
public function __construct(
#[Groups(['reception:weigh:read'])]
#[Groups(['reception:weigh:read', 'shipment:weigh:read'])]
private ?int $dsd,
#[Groups(['reception:weigh:read'])]
#[Groups(['reception:weigh:read', 'shipment:weigh:read'])]
private ?float $weight,
#[Groups(['reception:weigh:read'])]
#[Groups(['reception:weigh:read', 'shipment:weigh:read'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
private ?DateTimeImmutable $weighedAt = null,
) {}
+45 -8
View File
@@ -31,31 +31,31 @@ class Address
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['address:read', 'supplier:read'])]
#[Groups(['address:read', 'supplier:read', 'customer:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 120)]
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'customer:read', 'shipment:read'])]
private string $label = '';
#[ORM\Column(length: 180)]
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'customer:read', 'shipment:read'])]
private string $street = '';
#[ORM\Column(name: 'street2', length: 180, nullable: true)]
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'customer:read', 'shipment:read'])]
private ?string $street2 = null;
#[ORM\Column(name: 'postal_code', length: 20)]
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'customer:read', 'shipment:read'])]
private string $postalCode = '';
#[ORM\Column(length: 120)]
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'customer:read', 'shipment:read'])]
private string $city = '';
#[ORM\Column(name: 'country_code', length: 2)]
#[Groups(['address:read', 'supplier:read'])]
#[Groups(['address:read', 'supplier:read', 'customer:read'])]
private string $countryCode = '';
/**
@@ -64,9 +64,16 @@ class Address
#[ORM\ManyToMany(targetEntity: Supplier::class, mappedBy: 'addresses')]
private Collection $suppliers;
/**
* @var Collection<int, Shipment>
*/
#[ORM\OneToMany(targetEntity: Shipment::class, mappedBy: 'address')]
private Collection $shipments;
public function __construct()
{
$this->suppliers = new ArrayCollection();
$this->shipments = new ArrayCollection();
}
public function getId(): ?int
@@ -146,7 +153,7 @@ class Address
return $this;
}
#[Groups(['address:read', 'supplier:read', 'reception:read'])]
#[Groups(['address:read', 'supplier:read', 'reception:read', 'shipment:read', 'customer:read'])]
public function getFullAddress(): string
{
$parts = array_filter([
@@ -165,4 +172,34 @@ class Address
{
return $this->suppliers;
}
/**
* @return Collection<int, Shipment>
*/
public function getShipments(): Collection
{
return $this->shipments;
}
public function addShipment(Shipment $shipment): static
{
if (!$this->shipments->contains($shipment)) {
$this->shipments->add($shipment);
$shipment->setAddress($this);
}
return $this;
}
public function removeShipment(Shipment $shipment): static
{
if ($this->shipments->removeElement($shipment)) {
// set the owning side to null (unless already changed)
if ($shipment->getAddress() === $this) {
$shipment->setAddress(null);
}
}
return $this;
}
}
+101
View File
@@ -0,0 +1,101 @@
<?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', columns: ['shipment_id', 'shipment_type_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;
}
}
+3 -3
View File
@@ -42,15 +42,15 @@ class Carrier
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['carrier:read', 'driver:read', 'vehicle:read', 'reception:read'])]
#[Groups(['carrier:read', 'driver:read', 'vehicle:read', 'reception:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 180)]
#[Groups(['carrier:read', 'carrier:write', 'driver:read', 'vehicle:read', 'reception:read'])]
#[Groups(['carrier:read', 'carrier:write', 'driver:read', 'vehicle:read', 'reception:read', 'shipment:read'])]
private string $name = '';
#[ORM\Column(length: 30, nullable: true)]
#[Groups(['carrier:read', 'carrier:write', 'driver:read', 'vehicle:read', 'reception:read'])]
#[Groups(['carrier:read', 'carrier:write', 'driver:read', 'vehicle:read', 'reception:read', 'shipment:read'])]
private ?string $code = null;
public function getId(): ?int
+94
View File
@@ -0,0 +1,94 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity]
#[ORM\Table(name: 'customer')]
#[ApiResource(
operations: [
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['customer:read']],
),
new GetCollection(
normalizationContext: ['groups' => ['customer:read']],
),
],
security: "is_granted('ROLE_USER')",
)]
class Customer
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['shipment:read', 'customer:read'])]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Groups(['customer:read', 'shipment:read'])]
private ?string $label = null;
#[ORM\Column(length: 255)]
#[Groups(['customer:read', 'shipment:read'])]
private ?string $code = null;
/**
* @var Collection<int, Address>
*/
#[ORM\ManyToMany(targetEntity: Address::class, inversedBy: 'customers')]
#[ORM\JoinTable(name: 'customer_address')]
#[Groups(['customer:read'])]
#[ApiProperty(readableLink: true)]
private Collection $addresses;
public function __construct()
{
$this->addresses = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(?string $label): void
{
$this->label = $label;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(?string $code): void
{
$this->code = $code;
}
public function getAddresses(): Collection
{
return $this->addresses;
}
public function setAddresses(Collection $addresses): void
{
$this->addresses = $addresses;
}
}
+2 -2
View File
@@ -30,11 +30,11 @@ class Driver
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['driver:read', 'reception:read'])]
#[Groups(['driver:read', 'reception:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 180)]
#[Groups(['driver:read', 'reception:read'])]
#[Groups(['driver:read', 'reception:read', 'shipment:read'])]
private string $name = '';
#[ORM\ManyToOne]
+366
View File
@@ -0,0 +1,366 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Metadata\ApiProperty;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use ApiPlatform\Metadata\Patch;
use ApiPlatform\Metadata\Post;
use ApiPlatform\OpenApi\Model\Operation as OpenApiOperation;
use App\Dto\PontBasculeReading;
use App\State\ShipmentReceiptProvider;
use App\State\ShipmentWeighingProvider;
use DateTimeImmutable;
use Doctrine\Common\Collections\ArrayCollection;
use Doctrine\Common\Collections\Collection;
use Doctrine\ORM\Event\PostPersistEventArgs;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Context;
use Symfony\Component\Serializer\Attribute\Groups;
use Symfony\Component\Serializer\Normalizer\DateTimeNormalizer;
#[ORM\Entity]
#[ORM\HasLifecycleCallbacks]
#[ORM\Table(name: 'shipment')]
#[ApiResource(
operations: [
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment:read']],
),
new GetCollection(
normalizationContext: ['groups' => ['shipment:read']],
),
new Post(
normalizationContext: ['groups' => ['shipment:read']],
denormalizationContext: ['groups' => ['shipment:write']],
),
new Patch(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment:read']],
denormalizationContext: ['groups' => ['shipment:write']],
),
new Get(
uriTemplate: '/shipments/weigh',
openapi: new OpenApiOperation(
summary: 'Fetch the current weight reading',
description: 'Queries the pont-bascule and returns the weight data.',
),
normalizationContext: ['groups' => ['shipment:weigh:read']],
output: PontBasculeReading::class,
provider: ShipmentWeighingProvider::class,
),
new Get(
uriTemplate: '/shipments/{id}/receipt',
requirements: ['id' => '\d+'],
openapi: new OpenApiOperation(
summary: 'Render a shipment receipt',
description: 'Returns a PDF receipt for the shipment.',
),
output: false,
provider: ShipmentReceiptProvider::class,
),
],
security: "is_granted('ROLE_USER')",
)]
class Shipment
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Groups(['shipment:read', 'shipment:write'])]
private ?string $licencePlate = null;
#[ORM\Column(length: 20, unique: true, nullable: true)]
#[Groups(['shipment:read'])]
private ?string $identificationNumber = null;
#[ORM\Column(options: ['default' => 0])]
#[Groups(['shipment:read', 'shipment:write'])]
private int $currentStep = 0;
#[ORM\Column]
#[Groups(['shipment:read', 'shipment:write'])]
private bool $isValid = false;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?User $user = null;
#[ORM\Column(name: 'shipment_date', type: 'datetime_immutable')]
#[Groups(['shipment:read', 'shipment:write'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
private ?DateTimeImmutable $shipmentDate = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?Carrier $carrier = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?Truck $truck = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?Customer $customer = null;
/**
* @var Collection<int, BovinShipment>
*/
#[ORM\OneToMany(
targetEntity: BovinShipment::class,
mappedBy: 'shipment',
cascade: ['persist', 'remove'],
orphanRemoval: true
)]
#[Groups(['shipment:read', 'shipment:write'])]
private Collection $bovinShipments;
/**
* @var Collection<int, Weight>
*/
#[ORM\OneToMany(targetEntity: Weight::class, mappedBy: 'shipment', cascade: ['persist', 'remove'], orphanRemoval: true)]
#[Groups(['shipment:read'])]
private Collection $weights;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?Driver $driver = null;
#[ORM\ManyToOne]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['shipment:read', 'shipment:write'])]
#[ApiProperty(readableLink: true)]
private ?Address $address = null;
public function __construct()
{
$this->bovinShipments = new ArrayCollection();
$this->weights = new ArrayCollection();
}
public function getId(): ?int
{
return $this->id;
}
public function getLicencePlate(): ?string
{
return $this->licencePlate;
}
public function setLicencePlate(?string $licencePlate): void
{
$this->licencePlate = $licencePlate;
}
public function getIdentificationNumber(): ?string
{
return $this->identificationNumber;
}
public function setIdentificationNumber(?string $identificationNumber): void
{
$this->identificationNumber = $identificationNumber;
}
public function getCurrentStep(): int
{
return $this->currentStep;
}
public function setCurrentStep(int $currentStep): void
{
$this->currentStep = $currentStep;
}
public function getIsValid(): ?bool
{
return $this->isValid;
}
#[Groups(['shipment:read'])]
public function isValid(): bool
{
return $this->isValid;
}
public function getUser(): ?User
{
return $this->user;
}
public function setUser(?User $user): void
{
$this->user = $user;
}
public function setIsValid(?bool $isValid): void
{
$this->isValid = $isValid;
}
public function getShipmentDate(): ?DateTimeImmutable
{
return $this->shipmentDate;
}
public function setShipmentDate(?DateTimeImmutable $shipmentDate): void
{
$this->shipmentDate = $shipmentDate;
}
public function getCarrier(): ?Carrier
{
return $this->carrier;
}
public function setCarrier(?Carrier $carrier): void
{
$this->carrier = $carrier;
}
public function getTruck(): ?Truck
{
return $this->truck;
}
public function setTruck(?Truck $truck): void
{
$this->truck = $truck;
}
public function getCustomer(): ?Customer
{
return $this->customer;
}
public function setCustomer(?Customer $customer): void
{
$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>
*/
public function getWeights(): Collection
{
return $this->weights;
}
public function addWeight(Weight $weight): void
{
if (!$this->weights->contains($weight)) {
$this->weights->add($weight);
$weight->setShipment($this);
}
}
public function removeWeight(Weight $weight): void
{
if ($this->weights->removeElement($weight)) {
if ($weight->getShipment() === $this) {
$weight->setShipment(null);
}
}
}
#[ORM\PostPersist]
public function initializeIdentificationNumber(PostPersistEventArgs $args): void
{
if (null !== $this->identificationNumber) {
return;
}
if (null === $this->id) {
return;
}
$number = sprintf('P-BR-%04d', $this->id);
$this->identificationNumber = $number;
$args->getObjectManager()
->getConnection()
->executeStatement(
'UPDATE shipment SET identification_number = :number WHERE id = :id',
[
'number' => $number,
'id' => $this->id,
]
)
;
}
public function getDriver(): ?Driver
{
return $this->driver;
}
public function setDriver(?Driver $driver): static
{
$this->driver = $driver;
return $this;
}
public function getAddress(): ?Address
{
return $this->address;
}
public function setAddress(?Address $address): static
{
$this->address = $address;
return $this;
}
}
+71
View File
@@ -0,0 +1,71 @@
<?php
declare(strict_types=1);
namespace App\Entity;
use ApiPlatform\Metadata\ApiResource;
use ApiPlatform\Metadata\Get;
use ApiPlatform\Metadata\GetCollection;
use Doctrine\ORM\Mapping as ORM;
use Symfony\Component\Serializer\Attribute\Groups;
#[ORM\Entity]
#[ORM\Table(name: 'shipment_type')]
#[ApiResource(
operations: [
new Get(
requirements: ['id' => '\d+'],
normalizationContext: ['groups' => ['shipment-type:read']],
),
new GetCollection(
normalizationContext: ['groups' => ['shipment-type:read']],
),
],
security: "is_granted('ROLE_USER')",
)]
class ShipmentType
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['shipment-type:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 255)]
#[Groups(['shipment-type:read', 'shipment:read'])]
private ?string $label = null;
#[ORM\Column(length: 255)]
#[Groups(['shipment-type:read', 'shipment:read'])]
private ?string $code = null;
public function getId(): ?int
{
return $this->id;
}
public function getLabel(): ?string
{
return $this->label;
}
public function setLabel(string $label): static
{
$this->label = $label;
return $this;
}
public function getCode(): ?string
{
return $this->code;
}
public function setCode(string $code): self
{
$this->code = $code;
return $this;
}
}
+2 -2
View File
@@ -29,11 +29,11 @@ class Truck
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['truck:read', 'vehicle:read', 'reception:read'])]
#[Groups(['truck:read', 'vehicle:read', 'reception:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 180)]
#[Groups(['truck:read', 'vehicle:read', 'reception:read'])]
#[Groups(['truck:read', 'vehicle:read', 'reception:read', 'shipment:read'])]
private string $name = '';
public function getId(): ?int
+2 -2
View File
@@ -61,11 +61,11 @@ class User implements UserInterface, PasswordAuthenticatedUserInterface
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column(type: 'integer')]
#[Groups(['user:read', 'user-login:read', 'reception:read'])]
#[Groups(['user:read', 'user-login:read', 'reception:read', 'shipment:read'])]
private ?int $id = null;
#[ORM\Column(length: 180, unique: true)]
#[Groups(['user:read', 'user:write', 'user-login:read', 'reception:read'])]
#[Groups(['user:read', 'user:write', 'user-login:read', 'reception:read', 'shipment:read'])]
private string $username = '';
#[ORM\Column(type: 'json')]
+32 -6
View File
@@ -35,36 +35,46 @@ use Symfony\Component\Validator\Constraints as Assert;
security: "is_granted('ROLE_USER')",
)]
#[UniqueEntity(fields: ['reception', 'type'], message: 'A weighing already exists for this type.')]
#[UniqueEntity(fields: ['shipment', 'type'], message: 'A weighing already exists for this type.')]
#[Assert\Expression(
'(this.getReception() !== null and this.getShipment() === null) or (this.getReception() === null and this.getShipment() !== null)',
message: 'Either reception or shipment must be set, but not both.'
)]
class Weight
{
#[ORM\Id]
#[ORM\GeneratedValue]
#[ORM\Column]
#[Groups(['reception:read', 'weight:read'])]
#[Groups(['reception:read', 'shipment:read', 'weight:read'])]
private ?int $id = null;
#[ORM\ManyToOne(inversedBy: 'weights')]
#[ORM\JoinColumn(nullable: false)]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['weight:read', 'weight:write'])]
private ?Reception $reception = null;
#[ORM\ManyToOne(inversedBy: 'weights')]
#[ORM\JoinColumn(nullable: true)]
#[Groups(['weight:read', 'weight:write'])]
private ?Shipment $shipment = null;
#[ORM\Column(nullable: true)]
#[Groups(['reception:read', 'weight:read', 'weight:write'])]
#[Groups(['reception:read', 'shipment:read', 'weight:read', 'weight:write'])]
#[Assert\PositiveOrZero]
private ?int $dsd = null;
#[ORM\Column(nullable: true)]
#[Groups(['reception:read', 'weight:read', 'weight:write'])]
#[Groups(['reception:read', 'shipment:read', 'weight:read', 'weight:write'])]
#[Assert\PositiveOrZero]
private ?int $weight = null;
#[ORM\Column(type: 'datetime_immutable', nullable: true)]
#[Groups(['reception:read', 'weight:read', 'weight:write'])]
#[Groups(['reception:read', 'shipment:read', 'weight:read', 'weight:write'])]
#[Context([DateTimeNormalizer::FORMAT_KEY => 'Y-m-d'])]
private ?DateTimeImmutable $weighedAt = null;
#[ORM\Column(length: 10)]
#[Groups(['reception:read', 'weight:read', 'weight:write'])]
#[Groups(['reception:read', 'shipment:read', 'weight:read', 'weight:write'])]
#[Assert\NotBlank]
#[Assert\Choice(choices: ['gross', 'tare'])]
private string $type = 'gross';
@@ -90,6 +100,22 @@ class Weight
return $this;
}
public function getShipment(): ?Shipment
{
return $this->shipment;
}
public function setShipment(?Shipment $shipment): self
{
$this->shipment = $shipment;
if (null !== $shipment && !$shipment->getWeights()->contains($this)) {
$shipment->addWeight($this);
}
return $this;
}
public function getDsd(): ?int
{
return $this->dsd;
+63
View File
@@ -0,0 +1,63 @@
<?php
declare(strict_types=1);
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Entity\Shipment;
use Doctrine\ORM\EntityManagerInterface;
use Dompdf\Dompdf;
use Dompdf\Options;
use Symfony\Component\HttpFoundation\Response;
use Symfony\Component\HttpKernel\Exception\NotFoundHttpException;
use Twig\Environment;
use Twig\Error\LoaderError;
use Twig\Error\RuntimeError;
use Twig\Error\SyntaxError;
final readonly class ShipmentReceiptProvider implements ProviderInterface
{
public function __construct(
private Environment $twig,
private EntityManagerInterface $entityManager,
) {}
/**
* @throws RuntimeError
* @throws SyntaxError
* @throws LoaderError
*/
public function provide(Operation $operation, array $uriVariables = [], array $context = []): Response
{
$id = $uriVariables['id'] ?? null;
if (null === $id) {
throw new NotFoundHttpException('Shipment not found.');
}
$shipment = $this->entityManager->getRepository(Shipment::class)->find($id);
if (!$shipment instanceof Shipment) {
throw new NotFoundHttpException('Shipment not found.');
}
$options = new Options();
$options->set('isRemoteEnabled', true);
$dompdf = new Dompdf($options);
$html = $this->twig->render('shipment_voucher.html.twig', [
'shipment' => $shipment,
]);
$dompdf->loadHtml($html);
$dompdf->setPaper('A4');
$dompdf->render();
$filename = sprintf('bon-expedition-%d.pdf', $shipment->getId());
return new Response($dompdf->output(), Response::HTTP_OK, [
'Content-Type' => 'application/pdf',
'Content-Disposition' => 'inline; filename="'.$filename.'"',
]);
}
}
+30
View File
@@ -0,0 +1,30 @@
<?php
declare(strict_types=1);
namespace App\State;
use ApiPlatform\Metadata\Operation;
use ApiPlatform\State\ProviderInterface;
use App\Dto\PontBasculeReading;
use App\Exception\PontBasculeException;
use App\Service\PontBasculeService;
use Symfony\Component\HttpKernel\Exception\HttpException;
final readonly class ShipmentWeighingProvider implements ProviderInterface
{
public function __construct(
private PontBasculeService $pontBasculeService,
) {}
public function provide(Operation $operation, array $uriVariables = [], array $context = []): ?PontBasculeReading
{
try {
$result = $this->pontBasculeService->fetch();
} catch (PontBasculeException $exception) {
throw new HttpException(500, $exception->getMessage(), $exception);
}
return $result;
}
}