src/Entity/Sales/WorkOrder.php line 196

  1. <?php
  2. namespace App\Entity\Sales;
  3. use ApiPlatform\Doctrine\Orm\Filter\SearchFilter;
  4. use ApiPlatform\Metadata\ApiFilter;
  5. use ApiPlatform\Metadata\ApiProperty;
  6. use ApiPlatform\Metadata\ApiResource;
  7. use ApiPlatform\Metadata\Delete;
  8. use ApiPlatform\Metadata\Get;
  9. use ApiPlatform\Metadata\GetCollection;
  10. use ApiPlatform\Metadata\Link;
  11. use ApiPlatform\Metadata\Patch;
  12. use ApiPlatform\Metadata\Post;
  13. use ApiPlatform\Metadata\Put;
  14. use ApiPlatform\OpenApi\Model;
  15. use App\Controller\Expediting\FreightDatasheetUploadAction;
  16. use App\Controller\Sales\WorkOrderDocumentUploadAction;
  17. use App\Doctrine\Type\Sales\Incoterm;
  18. use App\Doctrine\Type\Sales\WorkOrderStatus;
  19. use App\Dto\Common\ObservationInput;
  20. use App\Dto\Expediting\FreightDatasheetInput;
  21. use App\Dto\Expediting\ReceptionInput;
  22. use App\Dto\Expediting\ReceptionPlanInput;
  23. use App\Dto\Expediting\ShippingPlanInput;
  24. use App\Dto\Sales\WorkOrderInput;
  25. use App\Dto\Sales\WorkOrderOutput;
  26. use App\Dto\Sales\WorkOrderStatusInput;
  27. use App\Entity\Common\Blameable;
  28. use App\Entity\Common\Company;
  29. use App\Entity\Common\Observation;
  30. use App\Entity\Common\Trackable;
  31. use App\Entity\Delete\Waybill;
  32. use App\Entity\Expediting\Freight;
  33. use App\Entity\Expediting\Item;
  34. use App\Entity\Expediting\Package;
  35. use App\Entity\Expediting\ShippingPlan;
  36. use App\Entity\File\File;
  37. use App\Entity\File\Parsable;
  38. use App\Entity\Identity\User;
  39. use App\Entity\Places\Facility;
  40. use App\Entity\Scheduler\Task;
  41. use App\Processor\Expediting\ReceptionInputProcessor;
  42. use App\Processor\Expediting\ReceptionPlanInputProcessor;
  43. use App\Processor\Expediting\ShippingPlanCreationProcessor;
  44. use App\Processor\Sales\FreightDatasheetProcessor;
  45. use App\Processor\Sales\WorkOrderCreationProcessor;
  46. use App\Processor\Sales\WorkOrderObservationProcessor;
  47. use App\Processor\Sales\WorkOrderStatusInputProcessor;
  48. use App\Provider\Finance\WorkOrderQuotationsProvider;
  49. use App\Provider\Sales\WorkOrderProvider;
  50. use App\Validator\IsValidEnum\IsValidEnum;
  51. use ArrayObject;
  52. use DateTimeInterface;
  53. use Doctrine\Common\Collections\ArrayCollection;
  54. use Doctrine\Common\Collections\Collection;
  55. use Doctrine\DBAL\Types\Types;
  56. use Doctrine\ORM\Mapping as ORM;
  57. use Gedmo\Mapping\Annotation as Gedmo;
  58. use Symfony\Bridge\Doctrine\Validator\Constraints\UniqueEntity;
  59. use Symfony\Component\Validator\Constraints as Assert;
  60. #[ORM\Table(name'work_order')]
  61. #[ORM\Index(columns: ['issued_by'], name'work_order_issued_by_idx')]
  62. #[ORM\Index(columns: ['client_id'], name'work_order_client_id_idx')]
  63. #[ORM\Index(columns: ['supplier_id'], name'work_order_supplier_id_idx')]
  64. #[ORM\Index(columns: ['contract_id'], name'work_order_contract_id_idx')]
  65. #[ORM\Index(columns: ['place_of_loading_id'], name'work_order_place_of_loading_id_idx')]
  66. #[ORM\Index(columns: ['place_of_discharge_id'], name'work_order_place_of_discharge_id_idx')]
  67. #[ORM\Index(columns: ['source_id'], name'work_order_source_id_idx')]
  68. #[ORM\Index(columns: ['created_by'], name'work_order_created_by_idx')]
  69. #[ORM\Index(columns: ['updated_by'], name'work_order_updated_by_idx')]
  70. #[ORM\UniqueConstraint(name'work_order_slug_key'columns: ['slug'])]
  71. #[ORM\UniqueConstraint(name'work_order_reference_key'columns: ['reference'])]
  72. #[ORM\Entity]
  73. #[UniqueEntity(fields: ['reference''slug'])]
  74. #[ApiResource(
  75.     shortName'WorkOrder',
  76.     operations: [
  77.         new Get(outputWorkOrderOutput::class, providerWorkOrderProvider::class),
  78.         new GetCollection(),
  79.         new GetCollection(uriTemplate'/procurement/work_orders'name'work_order_procurement'),
  80.         new GetCollection(uriTemplate'/work_orders/{slug}/quotations'shortName'Quotation'providerWorkOrderQuotationsProvider::class),
  81.         new Post(inputWorkOrderInput::class, processorWorkOrderCreationProcessor::class),
  82.         new Patch(inputFormats: ['json' => ['application/merge-patch+json']], inputWorkOrderInput::class, processorWorkOrderCreationProcessor::class),
  83.         new Put(),
  84.         new Delete(),
  85.     ],
  86.     order: ['id' => 'DESC']
  87. )]
  88. #[ApiResource(
  89.     operations: [
  90.         new Patch(
  91.             uriTemplate'/work_orders/{slug}/status',
  92.             inputFormats: ['json' => ['application/merge-patch+json']],
  93.             inputWorkOrderStatusInput::class,
  94.             processorWorkOrderStatusInputProcessor::class
  95.         ),
  96.         new Post(
  97.             uriTemplate'/work_orders/{slug}/plan',
  98.             inputShippingPlanInput::class,
  99.             processorShippingPlanCreationProcessor::class
  100.         ),
  101.         new Post(
  102.             uriTemplate'/work_orders/{slug}/etr',
  103.             inputReceptionPlanInput::class,
  104.             processorReceptionPlanInputProcessor::class
  105.         ),
  106.         new Post(
  107.             uriTemplate'/work_orders/{slug}/atr',
  108.             inputReceptionInput::class,
  109.             processorReceptionInputProcessor::class
  110.         ),
  111.         new Post(
  112.             uriTemplate'/work_orders/{slug}/datasheet',
  113.             inputFreightDatasheetInput::class,
  114.             processorFreightDatasheetProcessor::class
  115.         ),
  116.         new Post(
  117.             uriTemplate'/work_orders/{slug}/observations',
  118.             inputObservationInput::class,
  119.             processorWorkOrderObservationProcessor::class
  120.         ),
  121.         new GetCollection(
  122.             uriTemplate'/scope/{slug}/work_orders',
  123.             uriVariables: [
  124.                 'slug' => new Link(fromProperty'workOrders'fromClassContract::class),
  125.             ],
  126.         ),
  127.     ]
  128. )]
  129. #[ApiResource(
  130.     // FIXME : This does not work well with docker
  131.     uriTemplate'/work_orders/{slug}/import',
  132.     operations: [
  133.         new Post(
  134.             controllerFreightDatasheetUploadAction::class,
  135.             openapi: new Model\Operation(
  136.                 requestBody: new Model\RequestBody(
  137.                     content: new ArrayObject([
  138.                         'multipart/form-data' => [
  139.                             'schema' => [
  140.                                 'type' => 'object',
  141.                                 'properties' => [
  142.                                     'file' => [
  143.                                         'type' => 'string',
  144.                                         'format' => 'binary'
  145.                                     ]
  146.                                 ]
  147.                             ]
  148.                         ]
  149.                     ])
  150.                 )
  151.             ),
  152.             shortName'Upload',
  153.             validationContext: ['groups' => ['Default''upload:create']],
  154.             deserializefalse,
  155.         ),
  156.     ],
  157. )]
  158. #[ApiResource(
  159.     // FIXME : This does not work well with docker
  160.     uriTemplate'/work_orders/{slug}/attachments',
  161.     operations: [
  162.         new Post(
  163.             controllerWorkOrderDocumentUploadAction::class,
  164.             openapi: new Model\Operation(
  165.                 requestBody: new Model\RequestBody(
  166.                     content: new ArrayObject([
  167.                         'multipart/form-data' => [
  168.                             'schema' => [
  169.                                 'type' => 'object',
  170.                                 'properties' => [
  171.                                     'file' => [
  172.                                         'type' => 'string',
  173.                                         'format' => 'binary'
  174.                                     ]
  175.                                 ]
  176.                             ]
  177.                         ]
  178.                     ])
  179.                 )
  180.             ),
  181.             shortName'Upload',
  182.             validationContext: ['groups' => ['Default''upload:create']],
  183.             deserializefalse,
  184.         ),
  185.     ],
  186. )]
  187. #[ApiFilter(SearchFilter::class, properties: [
  188.     'reference' => 'ipartial',
  189.     'tasks.type' => 'exact',
  190.     'tasks.status' => 'exact',
  191.     'freights.order.number' => 'ipartial',
  192. ])]
  193. class WorkOrder
  194. {
  195.     use Blameable;
  196.     use Trackable;
  197.     #[ORM\Id]
  198.     #[ORM\GeneratedValue(strategy'IDENTITY')]
  199.     #[ORM\SequenceGenerator(sequenceName'work_order_id_seq')]
  200.     #[ORM\Column(typeTypes::INTEGER)]
  201.     #[ApiProperty(identifierfalse)]
  202.     private ?int $id null;
  203.     #[Gedmo\Slug(fields: ['reference'])]
  204.     #[ORM\Column(typeTypes::STRING)]
  205.     #[ApiProperty(identifiertrue)]
  206.     private ?string $slug null;
  207.     #[Assert\NotNull]
  208.     #[Assert\Length(min5)]
  209.     #[ORM\Column(typeTypes::STRING)]
  210.     private ?string $reference null;
  211.     #[Assert\Type(typeUser::class)]
  212.     #[ORM\ManyToOne(targetEntityUser::class)]
  213.     #[ORM\JoinColumn(name'issued_by')]
  214.     private ?User $issuedBy null;
  215.     #[Assert\NotNull]
  216.     #[Assert\Type(typeCompany::class)]
  217.     #[ORM\ManyToOne(targetEntityCompany::class)]
  218.     #[ORM\JoinColumn(name'client_id'nullablefalse)]
  219.     private ?Company $client null;
  220.     #[Assert\Type(typeCompany::class)]
  221.     #[ORM\ManyToOne(targetEntityCompany::class)]
  222.     #[ORM\JoinColumn(name'supplier_id')]
  223.     private ?Company $supplier null;
  224.     #[Assert\Type(typeContract::class)]
  225.     #[ORM\ManyToOne(targetEntityContract::class, inversedBy'workOrders')]
  226.     #[ORM\JoinColumn(name'contract_id')]
  227.     private ?Contract $contract null;
  228.     #[Assert\NotNull]
  229.     #[ORM\ManyToOne(targetEntityFacility::class)]
  230.     #[ORM\JoinColumn(name'place_of_loading_id'nullablefalse)]
  231.     private ?Facility $placeOfLoading null;
  232.     #[Assert\NotNull]
  233.     #[ORM\ManyToOne(targetEntityFacility::class)]
  234.     #[ORM\JoinColumn(name'place_of_discharge_id'nullablefalse)]
  235.     private ?Facility $placeOfDischarge null;
  236.     #[Assert\Type(typeParsable::class)]
  237.     #[ORM\OneToOne(inversedBy'workOrder'targetEntityParsable::class)]
  238.     #[ORM\JoinColumn(name'source_id')]
  239.     private ?Parsable $source null;
  240.     /** @var Collection<int, ShippingPlan> */
  241.     #[ORM\OneToMany(mappedBy'workOrder'targetEntityShippingPlan::class)]
  242.     #[ORM\OrderBy(['id' => 'DESC'])]
  243.     private Collection $shippingPlans;
  244.     #[IsValidEnum(enumIncoterm::class)]
  245.     #[ORM\Column(typeTypes::STRINGnullabletrueenumTypeIncoterm::class)]
  246.     private ?Incoterm $incoterm null;
  247.     #[Assert\NotNull]
  248.     #[Assert\Type(typeDateTimeInterface::class)]
  249.     #[ORM\Column(typeTypes::DATE_MUTABLE)]
  250.     private ?DateTimeInterface $requestedOn null;
  251.     #[Assert\NotNull]
  252.     #[Assert\Type(typeDateTimeInterface::class)]
  253.     #[ORM\Column(typeTypes::DATE_MUTABLE)]
  254.     private ?DateTimeInterface $availableOn null;
  255.     #[Assert\NotNull]
  256.     #[IsValidEnum(enumWorkOrderStatus::class)]
  257.     #[ORM\Column(typeTypes::STRINGenumTypeWorkOrderStatus::class, options: ['default' => 'DRAFTED'])]
  258.     private ?WorkOrderStatus $status WorkOrderStatus::DRAFTED;
  259.     /** @var Collection<int, Task> */
  260.     #[ORM\ManyToMany(targetEntityTask::class, mappedBy'workOrders')]
  261.     private Collection $tasks;
  262.     /** @var Collection<int, Freight> */
  263.     #[ORM\OneToMany(mappedBy'workOrder'targetEntityFreight::class, cascade: ['persist''remove'])]
  264.     private Collection $freights;
  265.     /** @var Collection<int, User> */
  266.     #[ORM\ManyToMany(targetEntityUser::class)]
  267.     #[ORM\JoinTable(name'work_order_customer_contact_map')]
  268.     #[ORM\JoinColumn(name'work_order_id')]
  269.     #[ORM\InverseJoinColumn(name'customer_contact_id')]
  270.     private Collection $customerContacts;
  271.     /** @var Collection<int, User> */
  272.     #[ORM\ManyToMany(targetEntityUser::class)]
  273.     #[ORM\JoinTable(name'work_order_supplier_contact_map')]
  274.     #[ORM\JoinColumn(name'work_order_id')]
  275.     #[ORM\InverseJoinColumn(name'supplier_contact_id')]
  276.     private Collection $supplierContacts;
  277.     /** @var Collection<int, File> */
  278.     #[ORM\ManyToMany(targetEntityFile::class, cascade: ['persist''remove'])]
  279.     #[ORM\JoinTable(name'work_order_file_map')]
  280.     #[ORM\JoinColumn(name'work_order_id')]
  281.     #[ORM\InverseJoinColumn(name'file_id')]
  282.     #[ORM\OrderBy(['id' => 'ASC'])]
  283.     private Collection $attachments;
  284.     /** @var Collection<int, Observation> */
  285.     #[ORM\OneToMany(mappedBy'workOrder'targetEntityObservation::class, cascade: ['persist''remove'])]
  286.     private Collection $observations;
  287.     #[Assert\Type(typeFreightDatasheetInput::class)]
  288.     #[ORM\Column(type'json_document'options: ['jsonb' => true])]
  289.     private FreightDatasheetInput $datasheet;
  290.     #[Assert\Valid]
  291.     #[Assert\Type(typeWaybill::class)]
  292.     #[ORM\Column(type'json_document'nullabletrueoptions: ['jsonb' => true])]
  293.     private Waybill $waybill;
  294.     public function __construct()
  295.     {
  296.         $this->tasks = new ArrayCollection();
  297.         $this->freights = new ArrayCollection();
  298.         $this->customerContacts = new ArrayCollection();
  299.         $this->supplierContacts = new ArrayCollection();
  300.         $this->datasheet = new FreightDatasheetInput();
  301.         $this->attachments = new ArrayCollection();
  302.         $this->observations = new ArrayCollection();
  303.         $this->shippingPlans = new ArrayCollection();
  304.     }
  305.     public function getId(): ?int
  306.     {
  307.         return $this->id;
  308.     }
  309.     public function getSlug(): ?string
  310.     {
  311.         return $this->slug;
  312.     }
  313.     public function setSlug(string $slug): self
  314.     {
  315.         $this->slug $slug;
  316.         return $this;
  317.     }
  318.     public function getReference(): ?string
  319.     {
  320.         return $this->reference;
  321.     }
  322.     public function setReference(string $reference): self
  323.     {
  324.         $this->reference $reference;
  325.         return $this;
  326.     }
  327.     public function getIssuedBy(): ?User
  328.     {
  329.         return $this->issuedBy;
  330.     }
  331.     public function setIssuedBy(?User $issuedBy): self
  332.     {
  333.         $this->issuedBy $issuedBy;
  334.         return $this;
  335.     }
  336.     public function getClient(): ?Company
  337.     {
  338.         return $this->client;
  339.     }
  340.     public function setClient(?Company $client): self
  341.     {
  342.         $this->client $client;
  343.         return $this;
  344.     }
  345.     public function getSupplier(): ?Company
  346.     {
  347.         return $this->supplier;
  348.     }
  349.     public function setSupplier(?Company $supplier): self
  350.     {
  351.         $this->supplier $supplier;
  352.         return $this;
  353.     }
  354.     public function getContract(): ?Contract
  355.     {
  356.         return $this->contract;
  357.     }
  358.     public function setContract(?Contract $contract): self
  359.     {
  360.         $this->contract $contract;
  361.         return $this;
  362.     }
  363.     public function getPlaceOfLoading(): ?Facility
  364.     {
  365.         return $this->placeOfLoading;
  366.     }
  367.     public function setPlaceOfLoading(?Facility $placeOfLoading): self
  368.     {
  369.         $this->placeOfLoading $placeOfLoading;
  370.         return $this;
  371.     }
  372.     public function getPlaceOfDischarge(): ?Facility
  373.     {
  374.         return $this->placeOfDischarge;
  375.     }
  376.     public function setPlaceOfDischarge(?Facility $placeOfDischarge): self
  377.     {
  378.         $this->placeOfDischarge $placeOfDischarge;
  379.         return $this;
  380.     }
  381.     public function getSource(): ?Parsable
  382.     {
  383.         return $this->source;
  384.     }
  385.     public function setSource(?Parsable $source): self
  386.     {
  387.         $this->source $source;
  388.         return $this;
  389.     }
  390.     /** @return Collection<int, ShippingPlan> */
  391.     public function getShippingPlans(): Collection
  392.     {
  393.         return $this->shippingPlans;
  394.     }
  395.     public function addShippingPlan(ShippingPlan $shippingPlan): static
  396.     {
  397.         if (!$this->shippingPlans->contains($shippingPlan)) {
  398.             $this->shippingPlans[] = $shippingPlan;
  399.             $shippingPlan->setWorkOrder($this);
  400.         }
  401.         return $this;
  402.     }
  403.     public function removeShippingPlan(ShippingPlan $shippingPlan): static
  404.     {
  405.         if ($this->shippingPlans->removeElement($shippingPlan)) {
  406.             // set the owning side to null (unless already changed)
  407.             if ($shippingPlan->getWorkOrder() === $this) {
  408.                 $shippingPlan->setWorkOrder(null);
  409.             }
  410.         }
  411.         return $this;
  412.     }
  413.     public function getIncoterm(): ?Incoterm
  414.     {
  415.         return $this->incoterm;
  416.     }
  417.     public function setIncoterm(?Incoterm $incoterm): self
  418.     {
  419.         $this->incoterm $incoterm;
  420.         return $this;
  421.     }
  422.     public function getRequestedOn(): ?DateTimeInterface
  423.     {
  424.         return $this->requestedOn;
  425.     }
  426.     public function setRequestedOn(?DateTimeInterface $requestedOn): self
  427.     {
  428.         $this->requestedOn $requestedOn;
  429.         return $this;
  430.     }
  431.     public function getAvailableOn(): ?DateTimeInterface
  432.     {
  433.         return $this->availableOn;
  434.     }
  435.     public function setAvailableOn(?DateTimeInterface $availableOn): self
  436.     {
  437.         $this->availableOn $availableOn;
  438.         return $this;
  439.     }
  440.     public function getStatus(): ?WorkOrderStatus
  441.     {
  442.         return $this->status;
  443.     }
  444.     public function setStatus(WorkOrderStatus $status): self
  445.     {
  446.         $this->status $status;
  447.         return $this;
  448.     }
  449.     /**
  450.      * @return Collection<int, Task>
  451.      */
  452.     public function getTasks(): Collection
  453.     {
  454.         return $this->tasks;
  455.     }
  456.     public function addTask(Task $task): self
  457.     {
  458.         if (!$this->tasks->contains($task)) {
  459.             $this->tasks[] = $task;
  460.             $task->addWorkOrder($this);
  461.         }
  462.         return $this;
  463.     }
  464.     public function removeTask(Task $task): self
  465.     {
  466.         if ($this->tasks->removeElement($task)) {
  467.             $task->removeWorkOrder($this);
  468.         }
  469.         return $this;
  470.     }
  471.     /**
  472.      * @return Collection<int, Freight>
  473.      */
  474.     public function getFreights(): Collection
  475.     {
  476.         return $this->freights;
  477.     }
  478.     public function addFreight(Freight $freight): self
  479.     {
  480.         if (!$this->freights->contains($freight)) {
  481.             $this->freights->add($freight);
  482.             $freight->setWorkOrder($this);
  483.         }
  484.         return $this;
  485.     }
  486.     public function removeFreight(Freight $freight): self
  487.     {
  488.         if ($this->freights->removeElement($freight)) {
  489.             // set the owning side to null (unless already changed)
  490.             if ($freight->getWorkOrder() === $this) {
  491.                 $freight->setWorkOrder(null);
  492.             }
  493.         }
  494.         return $this;
  495.     }
  496.     /**
  497.      * @return Collection<int, Package>
  498.      */
  499.     public function getPackages(): Collection
  500.     {
  501.         $packages = new ArrayCollection();
  502.         foreach ($this->freights as $freight) {
  503.             foreach ($freight->getItems() as $item) {
  504.                 foreach ($item->getPackages() as $package) {
  505.                     if (!$packages->contains($package)) {
  506.                         $packages->add($package);
  507.                     }
  508.                 }
  509.             }
  510.         }
  511.         return $packages;
  512.     }
  513.     /**
  514.      * @return Collection<int, Item>
  515.      */
  516.     public function getItems(): Collection
  517.     {
  518.         $items = new ArrayCollection();
  519.         foreach ($this->freights as $freight) {
  520.             foreach ($freight->getItems() as $item) {
  521.                 if (!$items->contains($item)) {
  522.                     $items->add($item);
  523.                 }
  524.             }
  525.         }
  526.         return $items;
  527.     }
  528.     /**
  529.      * @return Collection<int, User>
  530.      */
  531.     public function getCustomerContacts(): Collection
  532.     {
  533.         return $this->customerContacts;
  534.     }
  535.     public function addCustomerContact(User $customerContact): self
  536.     {
  537.         if (!$this->customerContacts->contains($customerContact)) {
  538.             $this->customerContacts->add($customerContact);
  539.         }
  540.         return $this;
  541.     }
  542.     public function removeCustomerContact(User $customerContact): self
  543.     {
  544.         $this->customerContacts->removeElement($customerContact);
  545.         return $this;
  546.     }
  547.     /**
  548.      * @return Collection<int, User>
  549.      */
  550.     public function getSupplierContacts(): Collection
  551.     {
  552.         return $this->supplierContacts;
  553.     }
  554.     public function addSupplierContact(User $supplierContact): self
  555.     {
  556.         if (!$this->supplierContacts->contains($supplierContact)) {
  557.             $this->supplierContacts->add($supplierContact);
  558.         }
  559.         return $this;
  560.     }
  561.     public function removeSupplierContact(User $supplierContact): self
  562.     {
  563.         $this->supplierContacts->removeElement($supplierContact);
  564.         return $this;
  565.     }
  566.     /**
  567.      * @return Collection<int, File>
  568.      */
  569.     public function getAttachments(): Collection
  570.     {
  571.         return $this->attachments;
  572.     }
  573.     public function addAttachment(File $attachment): self
  574.     {
  575.         if (!$this->attachments->contains($attachment)) {
  576.             $this->attachments->add($attachment);
  577.         }
  578.         return $this;
  579.     }
  580.     public function removeAttachment(File $attachment): self
  581.     {
  582.         $this->attachments->removeElement($attachment);
  583.         return $this;
  584.     }
  585.     /**
  586.      * @return Collection<int, Observation>
  587.      */
  588.     public function getObservations(): Collection
  589.     {
  590.         return $this->observations;
  591.     }
  592.     public function addObservation(Observation $observation): self
  593.     {
  594.         if (!$this->observations->contains($observation)) {
  595.             $this->observations->add($observation);
  596.             $observation->setWorkOrder($this);
  597.         }
  598.         return $this;
  599.     }
  600.     public function removeObservation(Observation $observation): self
  601.     {
  602.         if ($this->observations->removeElement($observation)) {
  603.             // set the owning side to null (unless already changed)
  604.             if ($observation->getWorkOrder() === $this) {
  605.                 $observation->setWorkOrder(null);
  606.             }
  607.         }
  608.         return $this;
  609.     }
  610.     public function getDatasheet(): FreightDatasheetInput
  611.     {
  612.         return $this->datasheet;
  613.     }
  614.     public function setDatasheet(FreightDatasheetInput $datasheet): self
  615.     {
  616.         $this->datasheet $datasheet;
  617.         return $this;
  618.     }
  619.     public function getWaybill(): Waybill
  620.     {
  621.         return $this->waybill;
  622.     }
  623.     public function setWaybill(?Waybill $waybill): static
  624.     {
  625.         $this->waybill $waybill;
  626.         return $this;
  627.     }
  628. }