diff --git a/src/Entity/Parts/Part.php b/src/Entity/Parts/Part.php index 48a74693..ddffd7fc 100644 --- a/src/Entity/Parts/Part.php +++ b/src/Entity/Parts/Part.php @@ -64,6 +64,12 @@ namespace App\Entity\Parts; use App\Entity\Attachments\Attachment; use App\Entity\Attachments\AttachmentContainingDBElement; use App\Entity\Devices\Device; +use App\Entity\Parts\PartTraits\AdvancedPropertyTrait; +use App\Entity\Parts\PartTraits\MasterAttachmentTrait; +use App\Entity\Parts\PartTraits\BasicPropertyTrait; +use App\Entity\Parts\PartTraits\InstockTrait; +use App\Entity\Parts\PartTraits\ManufacturerTrait; +use App\Entity\Parts\PartTraits\OrderTrait; use App\Entity\PriceInformations\Orderdetail; use App\Security\Annotations\ColumnSecurity; use App\Validator\Constraints\Selectable; @@ -79,78 +85,26 @@ use Symfony\Component\Validator\Constraints as Assert; * DONT USE orphanRemoval on properties with ColumnSecurity!! An empty collection will be created as placeholder, * and the partlots are deleted, even if we want dont want that! * + * The class properties are split over various traits in directory PartTraits. + * Otherwise this class would be too big, to be maintained. + * * @ORM\Entity(repositoryClass="App\Repository\PartRepository") * @ORM\Table("`parts`") */ class Part extends AttachmentContainingDBElement { - public const INSTOCK_UNKNOWN = -2; - - /** - * @ORM\OneToMany(targetEntity="App\Entity\Attachments\PartAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=false) - * @ColumnSecurity(type="collection", prefix="attachments") - * @Assert\Valid() - */ - protected $attachments; - - /** - * @var Category - * @ORM\ManyToOne(targetEntity="Category", inversedBy="parts") - * @ORM\JoinColumn(name="id_category", referencedColumnName="id", nullable=false) - * @ColumnSecurity(prefix="category", type="App\Entity\Parts\Category") - * @Selectable() - */ - protected $category; - - /** - * @var Footprint|null - * @ORM\ManyToOne(targetEntity="Footprint", inversedBy="parts") - * @ORM\JoinColumn(name="id_footprint", referencedColumnName="id") - * @ColumnSecurity(prefix="footprint", type="App\Entity\Parts\Footprint") - * @Selectable() - */ - protected $footprint; - - /** - * @var Manufacturer|null - * @ORM\ManyToOne(targetEntity="Manufacturer", inversedBy="parts") - * @ORM\JoinColumn(name="id_manufacturer", referencedColumnName="id") - * @ColumnSecurity(prefix="manufacturer", type="App\Entity\Parts\Manufacturer") - * @Selectable() - */ - protected $manufacturer; - - /** - * @var Attachment - * @ORM\ManyToOne(targetEntity="App\Entity\Attachments\Attachment") - * @ORM\JoinColumn(name="id_master_picture_attachement", referencedColumnName="id") - * @Assert\Expression("value == null or value.isPicture()", message="part.master_attachment.must_be_picture") - * @ColumnSecurity(prefix="attachments", type="object") - */ - protected $master_picture_attachment; - - /** - * @var Orderdetail[] - * @ORM\OneToMany(targetEntity="App\Entity\PriceInformations\Orderdetail", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=false) - * @Assert\Valid() - * @ColumnSecurity(prefix="orderdetails", type="collection") - */ - protected $orderdetails; - - /** - * @var Orderdetail - * @ORM\OneToOne(targetEntity="App\Entity\PriceInformations\Orderdetail") - * @ORM\JoinColumn(name="order_orderdetails_id", referencedColumnName="id") - * - * @ColumnSecurity(prefix="order", type="object") - */ - protected $order_orderdetail; + use AdvancedPropertyTrait; + use MasterAttachmentTrait; + use BasicPropertyTrait; + use InstockTrait; + use ManufacturerTrait; + use OrderTrait; //TODO protected $devices; /** - * @ColumnSecurity(type="datetime") + * @ColumnSecurity(type="datetime") * @ORM\Column(type="datetime", name="datetime_added", options={"default"="CURRENT_TIMESTAMP"}) */ protected $addedDate; @@ -162,128 +116,12 @@ class Part extends AttachmentContainingDBElement */ protected $lastModified; - /********************** - * Propertys - ***********************/ - /** - * @var string - * @ORM\Column(type="string") - * - * @ColumnSecurity(prefix="name") - */ - protected $name = ''; - - /** - * @var string - * @ORM\Column(type="text") - * @ColumnSecurity(prefix="description") - */ - protected $description = ''; - - /** - * @var ?PartLot[] - * @ORM\OneToMany(targetEntity="PartLot", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=false) + * @ORM\OneToMany(targetEntity="App\Entity\Attachments\PartAttachment", mappedBy="element", cascade={"persist", "remove"}, orphanRemoval=false) + * @ColumnSecurity(type="collection", prefix="attachments") * @Assert\Valid() - * @ColumnSecurity(type="collection", prefix="lots") */ - protected $partLots; - - /** - * @var float - * @ORM\Column(type="float") - * @Assert\PositiveOrZero() - * - * @ColumnSecurity(prefix="mininstock", type="integer") - */ - protected $minamount = 0; - - /** - * @var string - * @ORM\Column(type="text") - * @ColumnSecurity(prefix="comment") - */ - protected $comment = ''; - - /** - * @var bool - * @ORM\Column(type="boolean") - */ - protected $visible = true; - - /** - * @var bool - * @ORM\Column(type="boolean") - * @ColumnSecurity(type="boolean") - */ - protected $favorite = false; - - /** - * @var int - * @ORM\Column(type="integer") - * @ColumnSecurity(prefix="order", type="integer") - */ - protected $order_quantity = 0; - - /** - * @var bool - * @ORM\Column(type="boolean") - * @ColumnSecurity(prefix="order", type="boolean") - */ - protected $manual_order = false; - - /** - * @var string - * @ORM\Column(type="string") - * @Assert\Url() - * @ColumnSecurity(prefix="mpn", type="string", placeholder="") - */ - protected $manufacturer_product_url = ''; - - /** - * @var string - * @ORM\Column(type="string") - * @ColumnSecurity(prefix="mpn", type="string", placeholder="") - */ - protected $manufacturer_product_number = ''; - - /** - * @var string - * @ORM\Column(type="string", length=255, nullable=true) - * @Assert\Choice({"announced", "active", "nrfnd", "eol", "discontinued", ""}) - * @ColumnSecurity(type="string", prefix="status", placeholder="") - */ - protected $manufacturing_status = ""; - - /** - * @var bool Determines if this part entry needs review (for example, because it is work in progress) - * @ORM\Column(type="boolean") - * @ColumnSecurity(type="boolean") - */ - protected $needs_review = false; - - /** - * @var ?MeasurementUnit The unit in which the part's amount is measured. - * @ORM\ManyToOne(targetEntity="MeasurementUnit", inversedBy="parts") - * @ORM\JoinColumn(name="id_part_unit", referencedColumnName="id", nullable=true) - * @ColumnSecurity(type="object", prefix="unit") - */ - protected $partUnit; - - /** - * @var string A comma seperated list of tags, assocciated with the part. - * @ORM\Column(type="text") - * @ColumnSecurity(type="string", prefix="tags", placeholder="") - */ - protected $tags = ''; - - /** - * @var float|null How much a single part unit weighs in gramms. - * @ORM\Column(type="float", nullable=true) - * @ColumnSecurity(type="float", placeholder=null) - * @Assert\PositiveOrZero() - */ - protected $mass; + protected $attachments; public function __construct() { @@ -303,280 +141,6 @@ class Part extends AttachmentContainingDBElement return 'P' . sprintf('%06d', $this->getID()); } - /********************************************************************************* - * Getters - ********************************************************************************/ - - /** - * Get the description string like it is saved in the database. - * This can contain BBCode, it is not parsed yet. - * - * @return string the description - */ - public function getDescription(): string - { - return htmlspecialchars($this->description); - } - - /** - * Get the count of parts which must be in stock at least. - * If a integer-based part unit is selected, the value will be rounded to integers - * - * @return float count of parts which must be in stock at least - */ - public function getMinAmount(): float - { - if ($this->useFloatAmount()) { - return $this->minamount; - } - - return round($this->minamount); - - } - - /** - * Get the comment associated with this part. - * - * @return string The raw/unparsed comment - */ - public function getComment(): string - { - return htmlspecialchars($this->comment); - } - - /** - * Get if this part is obsolete. - * - * A Part is marked as "obsolete" if all their orderdetails are marked as "obsolete". - * If a part has no orderdetails, the part isn't marked as obsolete. - * - * @return bool true, if this part is obsolete. false, if this part isn't obsolete - */ - public function isObsolete(): bool - { - $all_orderdetails = $this->getOrderdetails(); - - if (0 === count($all_orderdetails)) { - return false; - } - - foreach ($all_orderdetails as $orderdetails) { - if (!$orderdetails->getObsolete()) { - return false; - } - } - - return true; - } - - /** - * Get if this part is visible. - * - * @return bool true if this part is visible - * false if this part isn't visible - */ - public function isVisible(): bool - { - return $this->visible; - } - - /** - * Get if this part is a favorite. - * - * @return bool * true if this part is a favorite - * * false if this part is not a favorite. - */ - public function isFavorite(): bool - { - return $this->favorite; - } - - /** - * Get the selected order orderdetails of this part. - * @return Orderdetail the selected order orderdetails - */ - public function getOrderOrderdetails(): ?Orderdetail - { - return $this->order_orderdetail; - } - - /** - * Get the order quantity of this part. - * - * @return int the order quantity - */ - public function getOrderQuantity(): int - { - return $this->order_quantity; - } - - /** - * Check if this part is marked for manual ordering. - * - * @return bool the "manual_order" attribute - */ - public function isMarkedForManualOrder(): bool - { - return $this->manual_order; - } - - /** - * Get the link to the website of the article on the manufacturers website - * When no this part has no explicit url set, then it is tried to generate one from the Manufacturer of this part - * automatically. - * - * @param - * - * @return string the link to the article - */ - public function getManufacturerProductUrl(): string - { - if ('' !== $this->manufacturer_product_url) { - return $this->manufacturer_product_url; - } - - if (null !== $this->getManufacturer()) { - return $this->getManufacturer()->getAutoProductUrl($this->name); - } - - return ''; // no url is available - } - - /** - * Similar to getManufacturerProductUrl, but here only the database value is returned. - * - * @return string The manufacturer url saved in DB for this part. - */ - public function getCustomProductURL(): string - { - return $this->manufacturer_product_url; - } - - /** - * Returns the manufacturing/production status for this part. - * The status can be one of the following: - * (Similar to https://designspark.zendesk.com/hc/en-us/articles/213584805-What-are-the-Lifecycle-Status-definitions-) - * * "": Status unknown - * * "announced": Part has been announced, but is not in production yet - * * "active": Part is in production and will be for the forseeable future - * * "nrfnd": Not recommended for new designs. - * * "eol": Part will become discontinued soon - * * "discontinued": Part is obsolete/discontinued by the manufacturer - * @return string - */ - public function getManufacturingStatus(): ?string - { - return $this->manufacturing_status; - } - - /** - * Sets the manufacturing status for this part - * See getManufacturingStatus() for valid values. - * @param string $manufacturing_status - * @return Part - */ - public function setManufacturingStatus(string $manufacturing_status): Part - { - $this->manufacturing_status = $manufacturing_status; - return $this; - } - - - - /** - * Get the category of this part. - * - * There is always a category, for each part! - * - * @return Category the category of this part - */ - public function getCategory(): ?Category - { - return $this->category; - } - - /** - * Get the footprint of this part (if there is one). - * - * @return Footprint the footprint of this part (if there is one) - */ - public function getFootprint(): ?Footprint - { - return $this->footprint; - } - - /** - * Get the manufacturer of this part (if there is one). - * - * @return Manufacturer the manufacturer of this part (if there is one) - */ - public function getManufacturer(): ?Manufacturer - { - return $this->manufacturer; - } - - /** - * Get the master picture "Attachment"-object of this part (if there is one). - * The master picture should be used as a visual description/representation of this part. - * - * @return Attachment the master picture Attachement of this part (if there is one) - */ - public function getMasterPictureAttachment(): ?Attachment - { - return $this->master_picture_attachment; - } - - /** - * Sets the new master picture for this part. - * @param Attachment|null $new_master_attachment - * @return Part - */ - public function setMasterPictureAttachment(?Attachment $new_master_attachment): Part - { - $this->master_picture_attachment = $new_master_attachment; - return $this; - } - - /** - * Get all orderdetails of this part. - * - * @param bool $hide_obsolete If true, obsolete orderdetails will NOT be returned - * - * @return Collection|Orderdetail[] * all orderdetails as a one-dimensional array of Orderdetails objects - * (empty array if there are no ones) - * * the array is sorted by the suppliers names / minimum order quantity - * - */ - public function getOrderdetails(bool $hide_obsolete = false) : Collection - { - //If needed hide the obsolete entries - if ($hide_obsolete) { - $orderdetails = $this->orderdetails; - foreach ($orderdetails as $key => $details) { - if ($details->getObsolete()) { - unset($orderdetails[$key]); - } - } - - return $orderdetails; - } - - return $this->orderdetails; - } - - public function addOrderdetail(Orderdetail $orderdetail) : Part - { - $orderdetail->setPart($this); - $this->orderdetails->add($orderdetail); - return $this; - } - - public function removeOrderdetail(Orderdetail $orderdetail) : Part - { - $this->orderdetails->removeElement($orderdetail); - return $this; - } - /** * Get all devices which uses this part. * @@ -590,322 +154,4 @@ class Part extends AttachmentContainingDBElement return $this->devices; } - /** - * Checks if this part is marked, for that it needs further review. - * @return bool - */ - public function isNeedsReview(): bool - { - return $this->needs_review; - } - - /** - * Sets the "needs review" status of this part. - * @param bool $needs_review - * @return Part - */ - public function setNeedsReview(bool $needs_review): Part - { - $this->needs_review = $needs_review; - return $this; - } - - /** - * Get all part lots where this part is stored. - * @return PartLot[]|Collection - */ - public function getPartLots() : Collection - { - return $this->partLots; - } - - public function addPartLot(PartLot $lot): Part - { - $lot->setPart($this); - $this->partLots->add($lot); - return $this; - } - - public function removePartLot(PartLot $lot): Part - { - $this->partLots->removeElement($lot); - return $this; - } - - /** - * Returns the assigned manufacturer product number (MPN) for this part. - * @return string - */ - public function getManufacturerProductNumber(): string - { - return $this->manufacturer_product_number; - } - - /** - * Sets the manufacturer product number (MPN) for this part. - * @param string $manufacturer_product_number - * @return Part - */ - public function setManufacturerProductNumber(string $manufacturer_product_number): Part - { - $this->manufacturer_product_number = $manufacturer_product_number; - return $this; - } - - /** - * Gets the measurement unit in which the part's amount should be measured. - * Returns null if no specific unit was that. That means the parts are measured simply in quantity numbers. - * @return MeasurementUnit|null - */ - public function getPartUnit(): ?MeasurementUnit - { - return $this->partUnit; - } - - /** - * Sets the measurement unit in which the part's amount should be measured. - * Set to null, if the part should be measured in quantities. - * @param MeasurementUnit|null $partUnit - * @return Part - */ - public function setPartUnit(?MeasurementUnit $partUnit): Part - { - $this->partUnit = $partUnit; - return $this; - } - - /** - * Gets a comma separated list, of tags, that are assigned to this part - * @return string - */ - public function getTags(): string - { - return $this->tags; - } - - /** - * Sets a comma separated list of tags, that are assigned to this part. - * @param string $tags - * @return Part - */ - public function setTags(string $tags): Part - { - $this->tags = $tags; - return $this; - } - - /** - * Returns the mass of a single part unit. - * Returns null, if the mass is unknown/not set yet - * @return float|null - */ - public function getMass(): ?float - { - return $this->mass; - } - - /** - * Sets the mass of a single part unit. - * Sett to null, if the mass is unknown. - * @param float|null $mass - * @return Part - */ - public function setMass(?float $mass): Part - { - $this->mass = $mass; - return $this; - } - - /** - * Checks if this part uses the float amount . - * This setting is based on the part unit (see MeasurementUnit->isInteger()). - * @return bool True if the float amount field should be used. False if the integer instock field should be used. - */ - public function useFloatAmount(): bool - { - if ($this->partUnit instanceof MeasurementUnit) { - return !$this->partUnit->isInteger(); - } - - //When no part unit is set, treat it as part count, and so use the integer value. - return false; - } - - /** - * Returns the summed amount of this part (over all part lots) - * @return float - */ - public function getAmountSum() : float - { - //TODO: Find a method to do this natively in SQL, the current method could be a bit slow - $sum = 0; - foreach ($this->getPartLots() as $lot) { - //Dont use the instock value, if it is unkown - if ($lot->isInstockUnknown()) { - continue; - } - - $sum += $lot->getAmount(); - } - - if ($this->useFloatAmount()) { - return $sum; - } - - return round($sum); - } - - /******************************************************************************** - * - * Setters - * - *********************************************************************************/ - - /** - * Set the description. - * - * @param string $new_description the new description - * - * @return self - */ - public function setDescription(?string $new_description): self - { - $this->description = $new_description; - - return $this; - } - - /** - * Set the minimum amount of parts that have to be instock. - * See getPartUnit() for the associated unit. - * - * @param int $new_minamount the new count of parts which should be in stock at least - * - * @return self - */ - public function setMinAmount(float $new_minamount): self - { - //Assert::natural($new_mininstock, 'The new minimum instock value must be positive! Got %s.'); - - $this->minamount = $new_minamount; - - return $this; - } - - /** - * Set the comment. - * - * @param string $new_comment the new comment - * - * @return self - */ - public function setComment(string $new_comment): self - { - $this->comment = $new_comment; - - return $this; - } - - /** - * Set the "manual_order" attribute. - * - * @param bool $new_manual_order the new "manual_order" attribute - * @param int $new_order_quantity the new order quantity - * @param int|null $new_order_orderdetails_id * the ID of the new order orderdetails - * * or Zero for "no order orderdetails" - * * or NULL for automatic order orderdetails - * (if the part has exactly one orderdetails, - * set this orderdetails as order orderdetails. - * Otherwise, set "no order orderdetails") - * - * @return self - */ - public function setManualOrder(bool $new_manual_order, int $new_order_quantity = 1, ?Orderdetail $new_order_orderdetail = null): Part - { - //Assert::greaterThan($new_order_quantity, 0, 'The new order quantity must be greater zero. Got %s!'); - - $this->manual_order = $new_manual_order; - - //TODO; - $this->order_orderdetail = $new_order_orderdetail; - $this->order_quantity = $new_order_quantity; - - return $this; - } - - /** - * Set the category of this Part. - * - * Every part must have a valid category (in contrast to the - * attributes "footprint", "storelocation", ...)! - * - * @param Category $category The new category of this part - * - * @return self - */ - public function setCategory(Category $category): Part - { - $this->category = $category; - - return $this; - } - - /** - * Set the new Footprint of this Part. - * - * @param Footprint|null $new_footprint The new footprint of this part. Set to null, if this part should not have - * a footprint. - * - * @return self - */ - public function setFootprint(?Footprint $new_footprint): Part - { - $this->footprint = $new_footprint; - - return $this; - } - - /** - * Sets the new manufacturer of this part. - * - * @param Manufacturer|null $new_manufacturer The new Manufacturer of this part. Set to null, if this part should - * not have a manufacturer. - * - * @return Part - */ - public function setManufacturer(?Manufacturer $new_manufacturer): self - { - $this->manufacturer = $new_manufacturer; - - return $this; - } - - /** - * Set the favorite status for this part. - * - * @param $new_favorite_status bool The new favorite status, that should be applied on this part. - * Set this to true, when the part should be a favorite. - * - * @return self - */ - public function setFavorite(bool $new_favorite_status): self - { - $this->favorite = $new_favorite_status; - - return $this; - } - - /** - * Sets the URL to the manufacturer site about this Part. Set to "" if this part should use the automatically URL based on its manufacturer. - * - * @param string $new_url The new url - * - * @return self - */ - public function setManufacturerProductURL(string $new_url): self - { - $this->manufacturer_product_url = $new_url; - - return $this; - } } diff --git a/src/Entity/Parts/PartLot.php b/src/Entity/Parts/PartLot.php index 884bdbcf..08a376c4 100644 --- a/src/Entity/Parts/PartLot.php +++ b/src/Entity/Parts/PartLot.php @@ -34,6 +34,7 @@ namespace App\Entity\Parts; use App\Entity\Base\DBElement; use App\Entity\Base\TimestampTrait; +use App\Entity\Parts\PartTraits\InstockTrait; use App\Validator\Constraints\Selectable; use App\Validator\Constraints\ValidPartLot; use Doctrine\ORM\Mapping as ORM; @@ -227,7 +228,7 @@ class PartLot extends DBElement /** * Sets the part that is stored in this part lot. - * @param Part $part + * @param Part|InstockTrait $part * @return PartLot */ public function setPart(Part $part): PartLot diff --git a/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php new file mode 100644 index 00000000..66d8fd56 --- /dev/null +++ b/src/Entity/Parts/PartTraits/AdvancedPropertyTrait.php @@ -0,0 +1,130 @@ +needs_review; + } + + /** + * Sets the "needs review" status of this part. + * @param bool $needs_review + * @return Part|self + */ + public function setNeedsReview(bool $needs_review): self + { + $this->needs_review = $needs_review; + return $this; + } + + + /** + * Gets a comma separated list, of tags, that are assigned to this part + * @return string + */ + public function getTags(): string + { + return $this->tags; + } + + /** + * Sets a comma separated list of tags, that are assigned to this part. + * @param string $tags + * @return self + */ + public function setTags(string $tags): self + { + $this->tags = $tags; + return $this; + } + + /** + * Returns the mass of a single part unit. + * Returns null, if the mass is unknown/not set yet + * @return float|null + */ + public function getMass(): ?float + { + return $this->mass; + } + + /** + * Sets the mass of a single part unit. + * Sett to null, if the mass is unknown. + * @param float|null $mass + * @return self + */ + public function setMass(?float $mass): self + { + $this->mass = $mass; + return $this; + } + + +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/BasicPropertyTrait.php b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php new file mode 100644 index 00000000..295ba6fe --- /dev/null +++ b/src/Entity/Parts/PartTraits/BasicPropertyTrait.php @@ -0,0 +1,219 @@ +description; + } + + /** + * Get the comment associated with this part. + * @return string The raw/unparsed comment + */ + public function getComment(): string + { + return $this->comment; + } + + /** + * Get if this part is visible. + * This property is not used yet. + * @return bool true if this part is visible + * false if this part isn't visible + */ + public function isVisible(): bool + { + return $this->visible; + } + + /** + * Check if this part is a favorite. + * @return bool * true if this part is a favorite + * * false if this part is not a favorite. + */ + public function isFavorite(): bool + { + return $this->favorite; + } + + + /** + * Get the category of this part (e.g. Resistors). + * There is always a category, for each part! + * @return Category the category of this part + */ + public function getCategory(): ?Category + { + return $this->category; + } + + /** + * Gets the Footprint of this part (e.g. DIP8) + * @return Footprint|null The footprint of this part. Null if this part should no have a footprint. + */ + public function getFootprint(): ?Footprint + { + return $this->footprint; + } + + /** + * Sets the description of this part. + * @param string $new_description the new description + * @return self + */ + public function setDescription(?string $new_description): self + { + $this->description = $new_description; + return $this; + } + + /** + * Sets the comment property of this part. + * @param string $new_comment the new comment + * @return self + */ + public function setComment(string $new_comment): self + { + $this->comment = $new_comment; + return $this; + } + + + /** + * Set the category of this Part. + * The category property is required for every part, so you can not pass null like the other properties (footprints) + * @param Category $category The new category of this part + * @return self + */ + public function setCategory(Category $category): Part + { + $this->category = $category; + return $this; + } + + /** + * Set the new Footprint of this Part. + * + * @param Footprint|null $new_footprint The new footprint of this part. Set to null, if this part should not have + * a footprint. + * + * @return self + */ + public function setFootprint(?Footprint $new_footprint): Part + { + $this->footprint = $new_footprint; + return $this; + } + + /** + * Set the favorite status for this part. + * + * @param $new_favorite_status bool The new favorite status, that should be applied on this part. + * Set this to true, when the part should be a favorite. + * + * @return self + */ + public function setFavorite(bool $new_favorite_status): self + { + $this->favorite = $new_favorite_status; + return $this; + } + +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/InstockTrait.php b/src/Entity/Parts/PartTraits/InstockTrait.php new file mode 100644 index 00000000..9a728b63 --- /dev/null +++ b/src/Entity/Parts/PartTraits/InstockTrait.php @@ -0,0 +1,192 @@ +partLots; + } + + /** + * Adds the given part lot, to the list of part lots. + * The part lot is assigned to this part. + * @param PartLot $lot + * @return self + */ + public function addPartLot(PartLot $lot): self + { + $lot->setPart($this); + $this->partLots->add($lot); + return $this; + } + + /** + * Removes the given part lot from the list of part lots. + * @param PartLot $lot The part lot that should be deleted. + * @return self + */ + public function removePartLot(PartLot $lot): self + { + $this->partLots->removeElement($lot); + return $this; + } + + /** + * Gets the measurement unit in which the part's amount should be measured. + * Returns null if no specific unit was that. That means the parts are measured simply in quantity numbers. + * @return MeasurementUnit|null + */ + public function getPartUnit(): ?MeasurementUnit + { + return $this->partUnit; + } + + /** + * Sets the measurement unit in which the part's amount should be measured. + * Set to null, if the part should be measured in quantities. + * @param MeasurementUnit|null $partUnit + * @return self + */ + public function setPartUnit(?MeasurementUnit $partUnit): self + { + $this->partUnit = $partUnit; + return $this; + } + + /** + * Get the count of parts which must be in stock at least. + * If a integer-based part unit is selected, the value will be rounded to integers + * + * @return float count of parts which must be in stock at least + */ + public function getMinAmount(): float + { + if ($this->useFloatAmount()) { + return $this->minamount; + } + + return round($this->minamount); + } + + /** + * Checks if this part uses the float amount . + * This setting is based on the part unit (see MeasurementUnit->isInteger()). + * @return bool True if the float amount field should be used. False if the integer instock field should be used. + */ + public function useFloatAmount(): bool + { + if ($this->partUnit instanceof MeasurementUnit) { + return !$this->partUnit->isInteger(); + } + + //When no part unit is set, treat it as part count, and so use the integer value. + return false; + } + + /** + * Returns the summed amount of this part (over all part lots) + * @return float The amount of parts given in partUnit + */ + public function getAmountSum() : float + { + //TODO: Find a method to do this natively in SQL, the current method could be a bit slow + $sum = 0; + foreach ($this->getPartLots() as $lot) { + //Dont use the instock value, if it is unkown + if ($lot->isInstockUnknown()) { + continue; + } + + $sum += $lot->getAmount(); + } + + if ($this->useFloatAmount()) { + return $sum; + } + + return round($sum); + } + + /** + * Set the minimum amount of parts that have to be instock. + * See getPartUnit() for the associated unit. + * @param int $new_minamount the new count of parts which should be in stock at least + * @return self + */ + public function setMinAmount(float $new_minamount): self + { + $this->minamount = $new_minamount; + return $this; + } +} diff --git a/src/Entity/Parts/PartTraits/ManufacturerTrait.php b/src/Entity/Parts/PartTraits/ManufacturerTrait.php new file mode 100644 index 00000000..36226957 --- /dev/null +++ b/src/Entity/Parts/PartTraits/ManufacturerTrait.php @@ -0,0 +1,194 @@ +manufacturer_product_url) { + return $this->manufacturer_product_url; + } + + if (null !== $this->getManufacturer()) { + return $this->getManufacturer()->getAutoProductUrl($this->name); + } + + return ''; // no url is available + } + + /** + * Similar to getManufacturerProductUrl, but here only the database value is returned. + * @return string The manufacturer url saved in DB for this part. + */ + public function getCustomProductURL(): string + { + return $this->manufacturer_product_url; + } + + /** + * Returns the manufacturing/production status for this part. + * The status can be one of the following: + * (Similar to https://designspark.zendesk.com/hc/en-us/articles/213584805-What-are-the-Lifecycle-Status-definitions-) + * * "": Status unknown + * * "announced": Part has been announced, but is not in production yet + * * "active": Part is in production and will be for the forseeable future + * * "nrfnd": Not recommended for new designs. + * * "eol": Part will become discontinued soon + * * "discontinued": Part is obsolete/discontinued by the manufacturer + * @return string + */ + public function getManufacturingStatus(): ?string + { + return $this->manufacturing_status; + } + + /** + * Sets the manufacturing status for this part + * See getManufacturingStatus() for valid values. + * @param string $manufacturing_status + * @return Part + */ + public function setManufacturingStatus(string $manufacturing_status): self + { + $this->manufacturing_status = $manufacturing_status; + return $this; + } + + /** + * Get the manufacturer of this part (if there is one). + * + * @return Manufacturer the manufacturer of this part (if there is one) + */ + public function getManufacturer(): ?Manufacturer + { + return $this->manufacturer; + } + + + /** + * Returns the assigned manufacturer product number (MPN) for this part. + * @return string + */ + public function getManufacturerProductNumber(): string + { + return $this->manufacturer_product_number; + } + + /** + * Sets the manufacturer product number (MPN) for this part. + * @param string $manufacturer_product_number + * @return Part + */ + public function setManufacturerProductNumber(string $manufacturer_product_number): self + { + $this->manufacturer_product_number = $manufacturer_product_number; + return $this; + } + + /** + * Sets the URL to the manufacturer site about this Part. + * Set to "" if this part should use the automatically URL based on its manufacturer. + * @param string $new_url The new url + * @return self + */ + public function setManufacturerProductURL(string $new_url): self + { + $this->manufacturer_product_url = $new_url; + + return $this; + } + + /** + * Sets the new manufacturer of this part. + * + * @param Manufacturer|null $new_manufacturer The new Manufacturer of this part. Set to null, if this part should + * not have a manufacturer. + * + * @return self + */ + public function setManufacturer(?Manufacturer $new_manufacturer): self + { + $this->manufacturer = $new_manufacturer; + + return $this; + } + +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/MasterAttachmentTrait.php b/src/Entity/Parts/PartTraits/MasterAttachmentTrait.php new file mode 100644 index 00000000..4b76f9cc --- /dev/null +++ b/src/Entity/Parts/PartTraits/MasterAttachmentTrait.php @@ -0,0 +1,77 @@ +master_picture_attachment; + } + + /** + * Sets the new master picture for this part. + * @param Attachment|null $new_master_attachment + * @return Part + */ + public function setMasterPictureAttachment(?Attachment $new_master_attachment): self + { + $this->master_picture_attachment = $new_master_attachment; + return $this; + } + + +} \ No newline at end of file diff --git a/src/Entity/Parts/PartTraits/OrderTrait.php b/src/Entity/Parts/PartTraits/OrderTrait.php new file mode 100644 index 00000000..acedbf06 --- /dev/null +++ b/src/Entity/Parts/PartTraits/OrderTrait.php @@ -0,0 +1,208 @@ +order_orderdetail; + } + + /** + * Get the order quantity of this part. + * @return int the order quantity + */ + public function getOrderQuantity(): int + { + return $this->order_quantity; + } + + /** + * Check if this part is marked for manual ordering. + * + * @return bool the "manual_order" attribute + */ + public function isMarkedForManualOrder(): bool + { + return $this->manual_order; + } + + /** + * Get all orderdetails of this part. + * + * @param bool $hide_obsolete If true, obsolete orderdetails will NOT be returned + * + * @return Collection|Orderdetail[] * all orderdetails as a one-dimensional array of Orderdetails objects + * (empty array if there are no ones) + * * the array is sorted by the suppliers names / minimum order quantity + * + */ + public function getOrderdetails(bool $hide_obsolete = false) : Collection + { + //If needed hide the obsolete entries + if ($hide_obsolete) { + $orderdetails = $this->orderdetails; + foreach ($orderdetails as $key => $details) { + if ($details->getObsolete()) { + unset($orderdetails[$key]); + } + } + + return $orderdetails; + } + + return $this->orderdetails; + } + + /** + * Adds the given orderdetail to list of orderdetails. + * The orderdetail is assigned to this part. + * @param Orderdetail $orderdetail The orderdetail that should be added. + * @return self + */ + public function addOrderdetail(Orderdetail $orderdetail) : self + { + $orderdetail->setPart($this); + $this->orderdetails->add($orderdetail); + return $this; + } + + /** + * Removes the given orderdetail from the list of orderdetails. + * @param Orderdetail $orderdetail + * @return OrderTrait + */ + public function removeOrderdetail(Orderdetail $orderdetail) : self + { + $this->orderdetails->removeElement($orderdetail); + return $this; + } + + /** + * Set the "manual_order" attribute. + * + * @param bool $new_manual_order the new "manual_order" attribute + * @param int $new_order_quantity the new order quantity + * @param int|null $new_order_orderdetails_id * the ID of the new order orderdetails + * * or Zero for "no order orderdetails" + * * or NULL for automatic order orderdetails + * (if the part has exactly one orderdetails, + * set this orderdetails as order orderdetails. + * Otherwise, set "no order orderdetails") + * + * @return self + */ + public function setManualOrder(bool $new_manual_order, int $new_order_quantity = 1, ?Orderdetail $new_order_orderdetail = null): Part + { + //Assert::greaterThan($new_order_quantity, 0, 'The new order quantity must be greater zero. Got %s!'); + + $this->manual_order = $new_manual_order; + + //TODO; + $this->order_orderdetail = $new_order_orderdetail; + $this->order_quantity = $new_order_quantity; + + return $this; + } + + /** + * Check if this part is obsolete. + * + * A Part is marked as "obsolete" if all their orderdetails are marked as "obsolete". + * If a part has no orderdetails, the part isn't marked as obsolete. + * + * @return bool true, if this part is obsolete. false, if this part isn't obsolete + */ + public function isObsolete(): bool + { + $all_orderdetails = $this->getOrderdetails(); + + if (0 === count($all_orderdetails)) { + return false; + } + + foreach ($all_orderdetails as $orderdetails) { + if (!$orderdetails->getObsolete()) { + return false; + } + } + + return true; + } + +} \ No newline at end of file