Part.php (25965B)
1 <?php 2 3 namespace PartKeepr\PartBundle\Entity; 4 5 use Doctrine\Common\Collections\ArrayCollection; 6 use Doctrine\ORM\Mapping as ORM; 7 use PartKeepr\CoreBundle\Entity\BaseEntity; 8 use PartKeepr\DoctrineReflectionBundle\Annotation\TargetService; 9 use PartKeepr\FootprintBundle\Entity\Footprint; 10 use PartKeepr\PartBundle\Exceptions\CategoryNotAssignedException; 11 use PartKeepr\PartBundle\Exceptions\MinStockLevelOutOfRangeException; 12 use PartKeepr\PartBundle\Exceptions\StorageLocationNotAssignedException; 13 use PartKeepr\ProjectBundle\Entity\Project; 14 use PartKeepr\ProjectBundle\Entity\ProjectPart; 15 use PartKeepr\StockBundle\Entity\StockEntry; 16 use PartKeepr\StorageLocationBundle\Entity\StorageLocation; 17 use PartKeepr\UploadedFileBundle\Annotation\UploadedFileCollection; 18 use Symfony\Component\Serializer\Annotation\Groups; 19 use Symfony\Component\Validator\Constraints as Assert; 20 21 /** 22 * Represents a part in the database. The heart of our project. Handle with care! 23 * 24 * @ORM\Entity 25 * @ORM\HasLifecycleCallbacks 26 * @TargetService(uri="/api/parts") 27 */ 28 class Part extends BaseEntity 29 { 30 /** 31 * The category of the part. 32 * 33 * @ORM\ManyToOne(targetEntity="PartKeepr\PartBundle\Entity\PartCategory") 34 * @Assert\NotNull() 35 * @Groups({"default"}) 36 * 37 * @var PartCategory 38 */ 39 private $category; 40 41 /** 42 * The part's name. 43 * 44 * @ORM\Column 45 * @Groups({"default"}) 46 * @Assert\NotBlank() 47 * 48 * @var string 49 */ 50 private $name; 51 52 /** 53 * The part's short description. 54 * 55 * @ORM\Column(type="string",nullable=true) 56 * @Groups({"default"}) 57 * 58 * @var string 59 */ 60 private $description; 61 62 /** 63 * The footprint of this part. 64 * 65 * @ORM\ManyToOne(targetEntity="PartKeepr\FootprintBundle\Entity\Footprint") 66 * @Groups({"default"}) 67 * 68 * @var Footprint 69 */ 70 private $footprint; 71 72 /** 73 * The unit in which the part's "amount" is calculated. This is necessary to count parts 74 * in "pieces", "meters" or "grams". 75 * 76 * @ORM\ManyToOne(targetEntity="PartKeepr\PartBundle\Entity\PartMeasurementUnit", inversedBy="parts") 77 * @Groups({"default"}) 78 * 79 * @var PartMeasurementUnit 80 */ 81 private $partUnit; 82 83 /** 84 * Defines the storage location of this part. 85 * 86 * @ORM\ManyToOne(targetEntity="PartKeepr\StorageLocationBundle\Entity\StorageLocation") 87 * @Groups({"default"}) 88 * 89 * @var StorageLocation 90 */ 91 private $storageLocation; 92 93 /** 94 * Holds the manufacturers which can manufacture this part. 95 * 96 * @ORM\OneToMany(targetEntity="PartKeepr\PartBundle\Entity\PartManufacturer",mappedBy="part",cascade={"persist", "remove"}, 97 * orphanRemoval=true) 98 * @Groups({"default"}) 99 * 100 * @var ArrayCollection 101 */ 102 private $manufacturers; 103 104 /** 105 * Holds the distributors from where we can buy the part. 106 * 107 * @ORM\OneToMany(targetEntity="PartKeepr\PartBundle\Entity\PartDistributor",mappedBy="part",cascade={"persist", "remove"}, 108 * orphanRemoval=true) 109 * @Groups({"default"}) 110 * 111 * @var ArrayCollection 112 */ 113 private $distributors; 114 115 /** 116 * Holds the part attachments. 117 * 118 * @ORM\OneToMany(targetEntity="PartKeepr\PartBundle\Entity\PartAttachment", 119 * mappedBy="part",cascade={"persist", "remove"}, orphanRemoval=true) 120 * @Groups({"default"}) 121 * @UploadedFileCollection() 122 * 123 * @var PartAttachment 124 */ 125 private $attachments; 126 127 /** 128 * The comment for this part. 129 * 130 * @ORM\Column(type="text") 131 * @Groups({"default"}) 132 */ 133 private $comment = ''; 134 135 /** 136 * The stock level. Note that this is a cached value, because it makes our summary queries easier. 137 * 138 * @todo It would be nice if we could get rid of that. 139 * @ORM\Column(type="integer") 140 * @Groups({"readonly"}) 141 * 142 * @var int 143 */ 144 private $stockLevel = 0; 145 146 /** 147 * The minimum stock level for this part. If we run out of this part (e.g. stockLevel < minStockLevel), 148 * we can see that in the system and re-order parts. 149 * 150 * @Groups({"default"}) 151 * @ORM\Column(type="integer") 152 * 153 * @var int 154 */ 155 private $minStockLevel = 0; 156 157 /** 158 * The average price for the part. Note that this is a cached value. 159 * 160 * @ORM\Column(type="decimal",precision=13,scale=4,nullable=false) 161 * @Groups({"readonly"}) 162 * 163 * @var float 164 */ 165 private $averagePrice = 0; 166 167 /** 168 * The stock level history. 169 * 170 * @ORM\OneToMany(targetEntity="PartKeepr\StockBundle\Entity\StockEntry",mappedBy="part",cascade={"persist", "remove"}) 171 * @Groups({"stock"}) 172 * 173 * @var ArrayCollection 174 */ 175 private $stockLevels; 176 177 /** 178 * The parameters for this part. 179 * 180 * @ORM\OneToMany(targetEntity="PartKeepr\PartBundle\Entity\PartParameter", 181 * mappedBy="part",cascade={"persist", "remove"}, orphanRemoval=true) 182 * @Groups({"default"}) 183 * 184 * @var ArrayCollection 185 */ 186 private $parameters; 187 188 /** 189 * The meta part parameter criterias for this part. 190 * 191 * @ORM\OneToMany(targetEntity="PartKeepr\PartBundle\Entity\MetaPartParameterCriteria", 192 * mappedBy="part",cascade={"persist", "remove"}, orphanRemoval=true) 193 * @Groups({"default"}) 194 * 195 * @var ArrayCollection 196 */ 197 private $metaPartParameterCriterias; 198 199 /** 200 * The part status for this part. 201 * 202 * @ORM\Column(type="string",nullable=true) 203 * @Groups({"default"}) 204 * 205 * @var string 206 */ 207 private $status; 208 209 /** 210 * Defines if the part needs review. 211 * 212 * @ORM\Column(type="boolean") 213 * @Groups({"default"}) 214 * 215 * @var bool 216 */ 217 private $needsReview; 218 219 /** 220 * Defines the condition of the part. 221 * 222 * @ORM\Column(type="string",nullable=true) 223 * @Groups({"default"}) 224 * 225 * @var string 226 */ 227 private $partCondition; 228 229 /** 230 * Defines the production remarks for a part. 231 * 232 * @ORM\Column(type="string",nullable=true) 233 * @Groups({"default"}) 234 * 235 * @var string 236 */ 237 private $productionRemarks; 238 239 /** 240 * The create date+time for this part. 241 * 242 * @ORM\Column(type="datetime",nullable=true) 243 * @Groups({"readonly"}) 244 * 245 * @var \DateTime 246 */ 247 private $createDate; 248 249 /** 250 * @ORM\OneToMany(targetEntity="PartKeepr\ProjectBundle\Entity\ProjectPart", mappedBy="part") 251 * 252 * @var ProjectPart[] 253 **/ 254 private $projectParts; 255 256 /** 257 * The internal part number. 258 * 259 * @ORM\Column(type="string",nullable=true) 260 * @Groups({"default"}) 261 * 262 * @var string 263 */ 264 private $internalPartNumber; 265 266 /** 267 * @ORM\Column(type="boolean",nullable=false) 268 * @Groups({"readonly"}) 269 * 270 * @var bool 271 */ 272 private $removals = false; 273 274 /** 275 * @ORM\Column(type="boolean",nullable=false) 276 * @Groups({"readonly"}) 277 * 278 * @var bool 279 */ 280 private $lowStock = false; 281 282 /** 283 * Defines if the part is a meta-part. 284 * 285 * @ORM\Column(type="boolean", options={ "default":false}) 286 * @Groups({"default"}) 287 * 288 * @var bool 289 */ 290 private $metaPart = false; 291 292 /** 293 * An array of all matching meta parts. 294 * 295 * @Groups({"default"}) 296 * 297 * @var array 298 */ 299 private $metaPartMatches; 300 301 public function __construct() 302 { 303 $this->distributors = new ArrayCollection(); 304 $this->manufacturers = new ArrayCollection(); 305 $this->parameters = new ArrayCollection(); 306 $this->attachments = new ArrayCollection(); 307 $this->stockLevels = new ArrayCollection(); 308 $this->projectParts = new ArrayCollection(); 309 $this->metaPartParameterCriterias = new ArrayCollection(); 310 $this->setCreateDate(new \DateTime()); 311 $this->setNeedsReview(false); 312 $this->setMetaPart(false); 313 } 314 315 /** 316 * Sets the create date for this part. 317 * 318 * @param \DateTime $dateTime The create date+time 319 */ 320 private function setCreateDate(\DateTime $dateTime) 321 { 322 $this->createDate = $dateTime; 323 } 324 325 /** 326 * @return string 327 */ 328 public function getProductionRemarks() 329 { 330 return $this->productionRemarks; 331 } 332 333 /** 334 * @param string $productionRemarks 335 */ 336 public function setProductionRemarks($productionRemarks) 337 { 338 $this->productionRemarks = $productionRemarks; 339 } 340 341 /** 342 * @return array 343 */ 344 public function getMetaPartMatches() 345 { 346 return $this->metaPartMatches; 347 } 348 349 /** 350 * @param array $metaPartMatches 351 */ 352 public function setMetaPartMatches($metaPartMatches) 353 { 354 $this->metaPartMatches = $metaPartMatches; 355 } 356 357 /** 358 * @return bool 359 */ 360 public function isLowStock() 361 { 362 return $this->lowStock; 363 } 364 365 /** 366 * @param bool $lowStock 367 */ 368 public function setLowStock($lowStock) 369 { 370 $this->lowStock = $lowStock; 371 } 372 373 /** 374 * @return mixed 375 */ 376 public function hasRemovals() 377 { 378 return $this->removals; 379 } 380 381 /** 382 * Returns the name of this part. 383 * 384 * @return string The part name 385 */ 386 public function getName() 387 { 388 return $this->name; 389 } 390 391 /** 392 * Sets the name for this part. 393 * 394 * @param string $name The part's name 395 */ 396 public function setName($name) 397 { 398 $this->name = $name; 399 } 400 401 /** 402 * Returns the internal part number for this part. 403 * 404 * @return string the internal part number 405 */ 406 public function getInternalPartNumber() 407 { 408 return $this->internalPartNumber; 409 } 410 411 /** 412 * Sets the internal part number for this part. 413 * 414 * @param string $partNumber 415 */ 416 public function setInternalPartNumber($partNumber) 417 { 418 $this->internalPartNumber = $partNumber; 419 } 420 421 /** 422 * Returns the short description of this part. 423 * 424 * @return string The part description 425 */ 426 public function getDescription() 427 { 428 return $this->description; 429 } 430 431 /** 432 * Sets the description for this part. 433 * 434 * @param string $description The part's short description 435 */ 436 public function setDescription($description) 437 { 438 $this->description = $description; 439 } 440 441 /** 442 * Returns the part unit. 443 * 444 * @param none 445 * 446 * @return PartMeasurementUnit The part unit object 447 */ 448 public function getPartUnit() 449 { 450 return $this->partUnit; 451 } 452 453 /** 454 * Sets the part unit. 455 * 456 * @param PartMeasurementUnit $partUnit The part unit object to set 457 */ 458 public function setPartUnit(PartMeasurementUnit $partUnit = null) 459 { 460 $this->partUnit = $partUnit; 461 } 462 463 /** 464 * Returns the review flag. 465 * 466 * @return bool True if the part needs review, false otherwise 467 */ 468 public function getNeedsReview() 469 { 470 return $this->needsReview; 471 } 472 473 /** 474 * Sets the review flag. 475 * 476 * @param bool $bReview True if the part needs review, false otherwise 477 */ 478 public function setNeedsReview($bReview) 479 { 480 $this->needsReview = $bReview; 481 } 482 483 /** 484 * Returns the condition of this part. 485 * 486 * @return string The part condition 487 */ 488 public function getPartCondition() 489 { 490 return $this->partCondition; 491 } 492 493 /** 494 * Sets the condition for this part. 495 * 496 * @param string $partCondition The part's condition 497 */ 498 public function setPartCondition($partCondition) 499 { 500 $this->partCondition = $partCondition; 501 } 502 503 /** 504 * Returns the category path. 505 * 506 * @Groups({"default"}) 507 * 508 * @return string 509 */ 510 public function getCategoryPath() 511 { 512 if ($this->category !== null) { 513 return $this->category->getCategoryPath(); 514 } else { 515 return ''; 516 } 517 } 518 519 /** 520 * Retrieves the footprint. 521 */ 522 public function getFootprint() 523 { 524 return $this->footprint; 525 } 526 527 /** 528 * Sets the footprint for this part. 529 * 530 * @param \PartKeepr\FootprintBundle\Entity\Footprint $footprint The footprint to set 531 */ 532 public function setFootprint(Footprint $footprint = null) 533 { 534 $this->footprint = $footprint; 535 } 536 537 /** 538 * Returns the comment for this part. 539 * 540 * @return string The comment 541 */ 542 public function getComment() 543 { 544 return $this->comment; 545 } 546 547 /** 548 * Sets the comment for this part. 549 * 550 * @param string $comment The comment for this part 551 */ 552 public function setComment($comment) 553 { 554 $this->comment = $comment; 555 } 556 557 /** 558 * Returns the distributors array. 559 * 560 * @return ArrayCollection the distributors 561 */ 562 public function getDistributors() 563 { 564 return $this->distributors->getValues(); 565 } 566 567 /** 568 * Returns the part attachments array. 569 * 570 * @return ArrayCollection the part attachments 571 */ 572 public function getAttachments() 573 { 574 return $this->attachments->getValues(); 575 } 576 577 /** 578 * Returns the manufacturers array. 579 * 580 * @return ArrayCollection the manufacturers 581 */ 582 public function getManufacturers() 583 { 584 return $this->manufacturers->getValues(); 585 } 586 587 /** 588 * Returns the parameters assigned to this part. 589 * 590 * @return ArrayCollection An array of PartParameter objects 591 */ 592 public function getParameters() 593 { 594 return $this->parameters->getValues(); 595 } 596 597 /** 598 * Returns the meta part parameter criterias assigned to this part. 599 * 600 * @return MetaPartParameterCriteria[] An array of MetaPartParameterCriteria objects 601 */ 602 public function getMetaPartParameterCriterias() 603 { 604 return $this->metaPartParameterCriterias->getValues(); 605 } 606 607 /** 608 * Returns the create date. 609 * 610 * @return \DateTime The create date+time 611 */ 612 public function getCreateDate() 613 { 614 return $this->createDate; 615 } 616 617 /** 618 * Returns the status for this part. 619 * 620 * @return string The status 621 */ 622 public function getStatus() 623 { 624 return $this->status; 625 } 626 627 /** 628 * Sets the status for this part. A status is any string describing the status, 629 * e.g. "new", "used", "broken" etc. 630 * 631 * @param string $status The status 632 */ 633 public function setStatus($status) 634 { 635 $this->status = $status; 636 } 637 638 /** 639 * Checks if the requirements for database persisting are given. 640 * 641 * @throws CategoryNotAssignedException Thrown if no category is set 642 * @throws StorageLocationNotAssignedException Thrown if no storage location is set 643 * 644 * @ORM\PrePersist 645 */ 646 public function onPrePersist() 647 { 648 $this->executeSaveListener(); 649 } 650 651 public function executeSaveListener() 652 { 653 $this->checkCategoryConsistency(); 654 $this->checkStorageLocationConsistency(); 655 } 656 657 /** 658 * Checks if the part category is set. 659 * 660 * @throws CategoryNotAssignedException 661 */ 662 private function checkCategoryConsistency() 663 { 664 if ($this->getCategory() === null) { 665 throw new CategoryNotAssignedException(); 666 } 667 } 668 669 /** 670 * Returns the assigned category. 671 * 672 * @return PartCategory 673 */ 674 public function getCategory() 675 { 676 return $this->category; 677 } 678 679 /** 680 * Sets the category for this part. 681 * 682 * @param PartCategory $category The category 683 */ 684 public function setCategory($category) 685 { 686 $this->category = $category; 687 } 688 689 /** 690 * Checks if the part storage location is set. 691 * 692 * @throws \PartKeepr\PartBundle\Exceptions\StorageLocationNotAssignedException 693 */ 694 private function checkStorageLocationConsistency() 695 { 696 if ($this->getStorageLocation() === null && !$this->isMetaPart()) { 697 throw new StorageLocationNotAssignedException(); 698 } 699 } 700 701 /** 702 * Returns the storage location for this part. 703 * 704 * @return \PartKeepr\StorageLocationBundle\Entity\StorageLocation $storageLocation The storage location 705 */ 706 public function getStorageLocation() 707 { 708 return $this->storageLocation; 709 } 710 711 /** 712 * Sets the storage location for this part. 713 * 714 * @param \PartKeepr\StorageLocationBundle\Entity\StorageLocation $storageLocation The storage location 715 */ 716 public function setStorageLocation(StorageLocation $storageLocation = null) 717 { 718 $this->storageLocation = $storageLocation; 719 } 720 721 /** 722 * @return bool 723 */ 724 public function isMetaPart() 725 { 726 return $this->metaPart; 727 } 728 729 /** 730 * @param bool $metaPart 731 */ 732 public function setMetaPart($metaPart) 733 { 734 $this->metaPart = $metaPart; 735 } 736 737 /** 738 * @param mixed $removals 739 */ 740 public function setRemovals($removals = false) 741 { 742 $this->removals = $removals; 743 } 744 745 /** 746 * Returns the acrage price. 747 * 748 * @return float 749 */ 750 public function getAveragePrice() 751 { 752 return $this->averagePrice; 753 } 754 755 /** 756 * Sets the average price for this part. 757 * 758 * @param float $price The price to set 759 */ 760 public function setAveragePrice($price) 761 { 762 $this->averagePrice = $price; 763 } 764 765 /** 766 * Checks if the requirements for database persisting are given. 767 * 768 * For a list of exceptions, see 769 * 770 * @see Part::onPrePersist() 771 * 772 * @ORM\PreUpdate 773 */ 774 public function onPreUpdate() 775 { 776 $this->executeSaveListener(); 777 } 778 779 /** 780 * Adds a new stock entry to this part. 781 * 782 * @param StockEntry $stockEntry 783 */ 784 public function addStockLevel(StockEntry $stockEntry) 785 { 786 $stockEntry->setPart($this); 787 $this->stockLevels->add($stockEntry); 788 } 789 790 /** 791 * Removes a stock entry from this part. 792 * 793 * @param StockEntry $stockEntry 794 */ 795 public function removeStockLevel($stockEntry) 796 { 797 $stockEntry->setPart(null); 798 $this->stockLevels->removeElement($stockEntry); 799 } 800 801 /** 802 * Adds a Part Parameter. 803 * 804 * @param PartParameter $partParameter A parameter to add 805 */ 806 public function addParameter($partParameter) 807 { 808 if ($partParameter instanceof PartParameter) { 809 $partParameter->setPart($this); 810 } 811 $this->parameters->add($partParameter); 812 } 813 814 /** 815 * Removes a Part Parameter. 816 * 817 * @param PartParameter $partParameter An parameter to remove 818 */ 819 public function removeParameter($partParameter) 820 { 821 $partParameter->setPart(null); 822 $this->parameters->removeElement($partParameter); 823 } 824 825 /** 826 * Adds a Meta Part Parameter Criteria. 827 * 828 * @param MetaPartParameterCriteria $metaPartParameterCriteria A meta part parameter criteria to 829 */ 830 public function addMetaPartParameterCriteria($metaPartParameterCriteria) 831 { 832 if ($metaPartParameterCriteria instanceof MetaPartParameterCriteria) { 833 $metaPartParameterCriteria->setPart($this); 834 } 835 $this->metaPartParameterCriterias->add($metaPartParameterCriteria); 836 } 837 838 /** 839 * Removes a Part Parameter. 840 * 841 * @param MetaPartParameterCriteria $metaPartParameterCriteria A meta part parameter criteria to remove 842 */ 843 public function removeMetaPartParameterCriteria($metaPartParameterCriteria) 844 { 845 $metaPartParameterCriteria->setPart(null); 846 $this->metaPartParameterCriterias->removeElement($metaPartParameterCriteria); 847 } 848 849 /** 850 * Adds a Part Attachment. 851 * 852 * @param PartAttachment $partAttachment An attachment to add 853 */ 854 public function addAttachment($partAttachment) 855 { 856 if ($partAttachment instanceof PartAttachment) { 857 $partAttachment->setPart($this); 858 } 859 $this->attachments->add($partAttachment); 860 } 861 862 /** 863 * Removes a Part Attachment. 864 * 865 * @param PartAttachment $partAttachment An attachment to remove 866 */ 867 public function removeAttachment($partAttachment) 868 { 869 if ($partAttachment instanceof PartAttachment) { 870 $partAttachment->setPart(null); 871 } 872 873 $this->attachments->removeElement($partAttachment); 874 } 875 876 /** 877 * Adds a Part Manufacturer. 878 * 879 * @param PartManufacturer $partManufacturer A part manufacturer to add 880 */ 881 public function addManufacturer(PartManufacturer $partManufacturer) 882 { 883 $partManufacturer->setPart($this); 884 $this->manufacturers->add($partManufacturer); 885 } 886 887 /** 888 * Removes a part manufacturer. 889 * 890 * @param PartManufacturer $partManufacturer A part manufacturer to remove 891 */ 892 public function removeManufacturer(PartManufacturer $partManufacturer) 893 { 894 $partManufacturer->setPart(null); 895 $this->manufacturers->removeElement($partManufacturer); 896 } 897 898 /** 899 * Adds a Part Distributor. 900 * 901 * @param PartDistributor $partDistributor A part distributor to add 902 */ 903 public function addDistributor(PartDistributor $partDistributor) 904 { 905 $partDistributor->setPart($this); 906 $this->distributors->add($partDistributor); 907 } 908 909 /** 910 * Removes a part distributor. 911 * 912 * @param PartDistributor $partDistributor A part distributor to remove 913 */ 914 public function removeDistributor(PartDistributor $partDistributor) 915 { 916 $partDistributor->setPart(null); 917 $this->distributors->removeElement($partDistributor); 918 } 919 920 /** 921 * Returns the project parts. 922 * 923 * @return ArrayCollection 924 */ 925 public function getProjectParts() 926 { 927 return $this->projectParts->getValues(); 928 } 929 930 /** 931 * Returns the project names this part is used in. 932 * 933 * @Groups({"default"}) 934 * 935 * @return array 936 */ 937 public function getProjectNames() 938 { 939 $projectNames = []; 940 foreach ($this->projectParts as $projectPart) { 941 if ($projectPart->getProject() instanceof Project) { 942 $projectNames[] = $projectPart->getProject()->getName(); 943 } 944 } 945 946 return array_unique($projectNames); 947 } 948 949 public function recomputeStockLevels() 950 { 951 $currentStock = 0; 952 $avgPrice = 0; 953 954 $totalPartStockPrice = 0; 955 $lastPosEntryQuant = 0; 956 $lastPosEntryPrice = 0; 957 $negativeStock = 0; 958 959 foreach ($this->getStockLevels() as $stockLevel) { 960 $currentStock += $stockLevel->getStockLevel(); 961 962 if ($currentStock <= 0) { 963 $avgPrice = 0; 964 $totalPartStockPrice = 0; 965 $negativeStock = $currentStock; 966 } else { 967 if ($stockLevel->getStockLevel() > 0) { 968 $lastPosEntryQuant = $stockLevel->getStockLevel(); 969 $lastPosEntryPrice = $stockLevel->getPrice(); 970 $totalPartStockPrice += $lastPosEntryPrice * ($lastPosEntryQuant + $negativeStock); 971 $avgPrice = $totalPartStockPrice / $currentStock; 972 } else { 973 if ($currentStock < $lastPosEntryQuant) { 974 $totalPartStockPrice = $currentStock * $lastPosEntryPrice; 975 $avgPrice = $totalPartStockPrice / $currentStock; 976 } else { 977 $totalPartStockPrice += $stockLevel->getStockLevel() * $avgPrice; 978 $avgPrice = $totalPartStockPrice / $currentStock; 979 } 980 $negativeStock = 0; 981 } 982 } 983 } 984 985 $this->setStockLevel($currentStock); 986 $this->setAveragePrice($avgPrice); 987 988 if ($currentStock < $this->getMinStockLevel()) { 989 $this->setLowStock(true); 990 } else { 991 $this->setLowStock(false); 992 } 993 } 994 995 /** 996 * Returns all stock entries. 997 * 998 * @return ArrayCollection 999 */ 1000 public function getStockLevels() 1001 { 1002 return $this->stockLevels->getValues(); 1003 } 1004 1005 /** 1006 * Returns the minimum stock level. 1007 * 1008 * @return int 1009 */ 1010 public function getMinStockLevel() 1011 { 1012 return $this->minStockLevel; 1013 } 1014 1015 /** 1016 * Set the minimum stock level for this part. 1017 * 1018 * Only positive values are allowed. 1019 * 1020 * @param int $minStockLevel A minimum stock level, only values >= 0 are allowed. 1021 * 1022 * @throws MinStockLevelOutOfRangeException If the passed stock level is not in range (>=0) 1023 */ 1024 public function setMinStockLevel($minStockLevel) 1025 { 1026 $minStockLevel = intval($minStockLevel); 1027 1028 if ($minStockLevel < 0) { 1029 throw new MinStockLevelOutOfRangeException(); 1030 } 1031 1032 $this->minStockLevel = $minStockLevel; 1033 1034 if ($this->getStockLevel() < $this->getMinStockLevel()) { 1035 $this->setLowStock(true); 1036 } else { 1037 $this->setLowStock(false); 1038 } 1039 } 1040 1041 /** 1042 * Returns the stock level. 1043 * 1044 * @return int The stock level 1045 */ 1046 public function getStockLevel() 1047 { 1048 return $this->stockLevel; 1049 } 1050 1051 /** 1052 * Sets the stock level. 1053 * 1054 * @param $stockLevel int The stock level to set 1055 */ 1056 public function setStockLevel($stockLevel) 1057 { 1058 $this->stockLevel = $stockLevel; 1059 } 1060 }