diff --git a/src/Entity/Attachments/AttachmentType.php b/src/Entity/Attachments/AttachmentType.php index 6eeb06ce..41a83deb 100644 --- a/src/Entity/Attachments/AttachmentType.php +++ b/src/Entity/Attachments/AttachmentType.php @@ -87,19 +87,20 @@ class AttachmentType extends StructuralDBElement */ protected $filetype_filter = ""; + public function __construct() + { + parent::__construct(); + $this->attachments = new ArrayCollection(); + } + /** - * Get all attachements ("Attachement" objects) with this type. + * Get all attachments ("Attachment" objects) with this type. * - * @return Collection|Attachment[] all attachements with this type, as a one-dimensional array of Attachement-objects + * @return Collection|Attachment[] all attachements with this type, as a one-dimensional array of Attachements * (sorted by their names) */ - public function getAttachementsForType(): Collection + public function getAttachmentsForType(): Collection { - // the attribute $this->attachements is used from class "AttachementsContainingDBELement" - if (null === $this->attachments) { - $this->attachments = new ArrayCollection(); - } - return $this->attachments; } diff --git a/src/Entity/Base/NamedDBElement.php b/src/Entity/Base/NamedDBElement.php index 42779c19..9560b74a 100644 --- a/src/Entity/Base/NamedDBElement.php +++ b/src/Entity/Base/NamedDBElement.php @@ -73,15 +73,11 @@ abstract class NamedDBElement extends DBElement *********************************************************************************/ /** - * Get the name. - * + * Get the name of this element * @return string the name of this element */ public function getName(): string { - /* - //Strip HTML from Name, so no XSS injection is possible. - return strip_tags($this->name); */ return $this->name; } @@ -94,12 +90,7 @@ abstract class NamedDBElement extends DBElement /** * Change the name of this element. * - * Spaces at the begin and at the end of the string will be removed - * automatically in NamedDBElement::check_values_validity(). - * So you don't have to do this yourself. - * * @param string $new_name the new name - * * @return self */ public function setName(string $new_name): self @@ -115,8 +106,6 @@ abstract class NamedDBElement extends DBElement * ******************************************************************************/ - - public function __toString() { return $this->getName(); diff --git a/src/Entity/Parts/PartLot.php b/src/Entity/Parts/PartLot.php index 5e910968..a9ccaac4 100644 --- a/src/Entity/Parts/PartLot.php +++ b/src/Entity/Parts/PartLot.php @@ -116,7 +116,6 @@ class PartLot extends DBElement * Check if the current part lot is expired. * This is the case, if the expiration date is greater the the current date. * @return bool|null True, if the part lot is expired. Returns null, if no expiration date was set. - * @throws \Exception */ public function isExpired(): ?bool { @@ -125,7 +124,7 @@ class PartLot extends DBElement } //Check if the expiration date is bigger then current time - return $this->expiration_date < new \DateTime(); + return $this->expiration_date < new \DateTime('now'); } /** diff --git a/src/Entity/Parts/PartTraits/InstockTrait.php b/src/Entity/Parts/PartTraits/InstockTrait.php index 1e20b487..29c4de63 100644 --- a/src/Entity/Parts/PartTraits/InstockTrait.php +++ b/src/Entity/Parts/PartTraits/InstockTrait.php @@ -35,7 +35,7 @@ use Doctrine\Common\Collections\Collection; trait InstockTrait { /** - * @var ?PartLot[]|Collection A list of part lots where this part is stored + * @var Collection|PartLot[] A list of part lots where this part is stored * @ORM\OneToMany(targetEntity="PartLot", mappedBy="part", cascade={"persist", "remove"}, orphanRemoval=true) * @Assert\Valid() * @ColumnSecurity(type="collection", prefix="lots") @@ -146,6 +146,7 @@ trait InstockTrait /** * Returns the summed amount of this part (over all part lots) + * Part Lots that have unknown value or are expired, are not used for this value * @return float The amount of parts given in partUnit */ public function getAmountSum() : float @@ -154,7 +155,7 @@ trait InstockTrait $sum = 0; foreach ($this->getPartLots() as $lot) { //Dont use the instock value, if it is unkown - if ($lot->isInstockUnknown()) { + if ($lot->isInstockUnknown() || $lot->isExpired() ?? false) { continue; } diff --git a/src/Entity/PriceInformations/Currency.php b/src/Entity/PriceInformations/Currency.php index 44176b45..c26cc65c 100644 --- a/src/Entity/PriceInformations/Currency.php +++ b/src/Entity/PriceInformations/Currency.php @@ -102,7 +102,7 @@ class Currency extends StructuralDBElement { $tmp = $this->getExchangeRate(); - if ($tmp === null || (float) $tmp === 0) { + if ($tmp === null || $tmp === "0") { return null; } diff --git a/src/Entity/PriceInformations/Orderdetail.php b/src/Entity/PriceInformations/Orderdetail.php index c5feb259..526bc8a6 100644 --- a/src/Entity/PriceInformations/Orderdetail.php +++ b/src/Entity/PriceInformations/Orderdetail.php @@ -138,9 +138,9 @@ class Orderdetail extends DBElement /** * Get the part. * - * @return Part the part of this orderdetails + * @return Part|null the part of this orderdetails */ - public function getPart(): Part + public function getPart(): ?Part { return $this->part; } @@ -235,12 +235,13 @@ class Orderdetail extends DBElement } /** - * Get the pricedetail for a specific quantity. + * Find the pricedetail that is correct for the desired amount (the one with the greatest discount value with a + * minimum order amount of the wished quantity) * @param float $quantity this is the quantity to choose the correct pricedetails * * @return Pricedetail|null: the price as a bcmath string. Null if there are no orderdetails for the given quantity */ - public function getPrice(float $quantity = 1) : ?Pricedetail + public function findPriceForQty(float $quantity = 1) : ?Pricedetail { if ($quantity <= 0) { return null; diff --git a/src/Entity/PriceInformations/Pricedetail.php b/src/Entity/PriceInformations/Pricedetail.php index 34186a92..89fc74e3 100644 --- a/src/Entity/PriceInformations/Pricedetail.php +++ b/src/Entity/PriceInformations/Pricedetail.php @@ -130,25 +130,15 @@ class Pricedetail extends DBElement *********************************************************************************/ /** - * Get the orderdetails of this pricedetails. + * Get the orderdetail to which this pricedetail belongs to this pricedetails. * - * @return Orderdetail the orderdetails object + * @return Orderdetail The orderdetail this price belongs to. */ - public function getOrderdetails(): Orderdetail + public function getOrderdetail(): Orderdetail { return $this->orderdetail; } - /** - * Returns the price associated with this pricedetail. - * It is given in current currency and for the price related quantity. - * @return float - */ - public function getPriceFloat() : float - { - return (float) $this->price; - } - /** * Returns the price associated with this pricedetail. * It is given in current currency and for the price related quantity. @@ -159,16 +149,6 @@ class Pricedetail extends DBElement return $this->price; } - /** - * Returns the price associated with this pricedetail as integer. - * It is given in current currency and for the price related quantity, in parts of 0.00001 (5 digits) - * @return int - */ - public function getPriceInt() : int - { - return (int) str_replace('.', '', $this->price); - } - /** * Get the price for a single unit in the currency associated with this price detail. * @@ -179,7 +159,6 @@ class Pricedetail extends DBElement * in the database, you have to pass the "price_related_quantity" count as $multiplier. * * @return string the price as a bcmath string - */ public function getPricePerUnit($multiplier = 1.0) : string { @@ -201,7 +180,7 @@ class Pricedetail extends DBElement */ public function getPriceRelatedQuantity(): float { - if ($this->orderdetail && $this->orderdetail->getPart() && !$this->orderdetail->getPart()->useFloatAmount()) { + if ($this->orderdetail && $this->orderdetail->getPart() && !$this->orderdetail->getPart()->useFloatAmount()) { $tmp = round($this->price_related_quantity); return $tmp < 1 ? 1 : $tmp; } diff --git a/src/Entity/UserSystem/User.php b/src/Entity/UserSystem/User.php index 1ff21fbc..5db0f661 100644 --- a/src/Entity/UserSystem/User.php +++ b/src/Entity/UserSystem/User.php @@ -406,12 +406,11 @@ class User extends AttachmentContainingDBElement implements UserInterface, HasPe */ public function getFullName(bool $including_username = false): string { - $str = $this->getFirstName().' '.$this->getLastName(); if ($including_username) { - $str .= ' ('.$this->getName().')'; + return sprintf('%s %s (%s)', $this->getFirstName(), $this->getLastName(), $this->getName()); } - return $str; + return sprintf('%s %s', $this->getFirstName(), $this->getLastName()); } public function setName(string $new_name): NamedDBElement diff --git a/src/Services/PricedetailHelper.php b/src/Services/PricedetailHelper.php index e939740b..a9374a33 100644 --- a/src/Services/PricedetailHelper.php +++ b/src/Services/PricedetailHelper.php @@ -147,7 +147,7 @@ class PricedetailHelper //Find the price for the amount, for the given foreach ($orderdetails as $orderdetail) { - $pricedetail = $orderdetail->getPrice($amount); + $pricedetail = $orderdetail->findPriceForQty($amount); //When we dont have informations about this amount, ignore it if ($pricedetail === null) { diff --git a/tests/Entity/Attachments/AttachmentTypeTest.php b/tests/Entity/Attachments/AttachmentTypeTest.php new file mode 100644 index 00000000..ecdbf9af --- /dev/null +++ b/tests/Entity/Attachments/AttachmentTypeTest.php @@ -0,0 +1,38 @@ +assertInstanceOf(Collection::class, $attachment_type->getAttachmentsForType()); + $this->assertEmpty($attachment_type->getFiletypeFilter()); + } +} \ No newline at end of file diff --git a/tests/Entity/PartInstockTest.php b/tests/Entity/PartInstockTest.php deleted file mode 100644 index d81c34cf..00000000 --- a/tests/Entity/PartInstockTest.php +++ /dev/null @@ -1,101 +0,0 @@ -float_unit = new MeasurementUnit(); - $this->float_unit->setIsInteger(false); - $this->int_unit = new MeasurementUnit(); - $this->int_unit->setIsInteger(true); - } - - public function testUseFloatAmount() - { - $part = new Part(); - $part->setPartUnit(null); - $this->assertFalse($part->useFloatAmount()); - - $part->setPartUnit($this->float_unit); - $this->assertTrue($part->useFloatAmount()); - - $part->setPartUnit($this->int_unit); - $this->assertFalse($part->useFloatAmount()); - } - - public function testGetMinAmount() - { - $part = new Part(); - $part->setMinAmount(10.32); - $part->setPartUnit(null); - $this->assertEquals(10.0, $part->getMinAmount()); - - $part->setPartUnit($this->float_unit); - $this->assertEquals(10.32, $part->getMinAmount()); - } - - public function testAddPartLot() - { - $part = new Part(); - //Part must be empty after creation - $this->assertEmpty($part->getPartLots()); - $part_lot = new PartLot(); - $part->addPartLot($part_lot); - - $this->assertCount(1, $part->getPartLots()); - //PartLot must now be assigned to part - $this->assertEquals($part, $part_lot->getPart()); - } - - public function testGetAmountSum() - { - $part = new Part(); - $part->addPartLot((new PartLot())->setAmount(5.42)); - $part->addPartLot((new PartLot())->setAmount(0.4)); - $part->addPartLot((new PartLot())->setAmount(10.4)); - $part->addPartLot((new PartLot())->setAmount(100)->setInstockUnknown(true)); - - $part->setPartUnit(null); - //It is important that we get 15 here (values are round and then summed), not 16 (sum and then round) - $this->assertEquals(15, $part->getAmountSum()); - - $part->setPartUnit($this->float_unit); - $this->assertEquals(16.22, $part->getAmountSum()); - } -} \ No newline at end of file diff --git a/tests/Entity/Parts/PartLotTest.php b/tests/Entity/Parts/PartLotTest.php new file mode 100644 index 00000000..ed6b9acd --- /dev/null +++ b/tests/Entity/Parts/PartLotTest.php @@ -0,0 +1,44 @@ +assertNull($lot->isExpired(), 'Lot must be return null when no Expiration date is set!'); + + $datetime = new \DateTime(); + + $lot->setExpirationDate($datetime->setTimestamp(strtotime('now +1 hour'))); + $this->assertFalse($lot->isExpired(), 'Lot with expiration date in the future must not be expired!'); + + $lot->setExpirationDate($datetime->setTimestamp(strtotime('now -1 hour'))); + $this->assertTrue($lot->isExpired(), 'Lot with expiration date in the past must be expired!'); + } +} \ No newline at end of file diff --git a/tests/Entity/Parts/PartTest.php b/tests/Entity/Parts/PartTest.php new file mode 100644 index 00000000..dd522b6f --- /dev/null +++ b/tests/Entity/Parts/PartTest.php @@ -0,0 +1,112 @@ +assertInstanceOf(Collection::class, $part->getPartLots()); + $this->assertTrue($part->getPartLots()->isEmpty()); + + //Add element + $lot = new PartLot(); + $part->addPartLot($lot); + $this->assertEquals($part, $lot->getPart()); + $this->assertEquals(1, $part->getPartLots()->count()); + + //Remove element + $part->removePartLot($lot); + $this->assertTrue($part->getPartLots()->isEmpty()); + } + + public function testGetSetMinamount() + { + $part = new Part(); + $measurement_unit = new MeasurementUnit(); + + //Without an set measurement unit the part must return an int + $part->setMinAmount(1.345); + $this->assertEquals(1, $part->getMinAmount()); + + //If an non int-based unit is assigned, an float is returned + $part->setPartUnit($measurement_unit); + $this->assertEquals(1.345, $part->getMinAmount()); + + //If an int-based unit is assigned an int is returned + $measurement_unit->setIsInteger(true); + $this->assertEquals(1, $part->getMinAmount()); + } + + public function testUseFloatAmount() + { + $part = new Part(); + $measurement_unit = new MeasurementUnit(); + + //Without an measurement unit int should be used + $this->assertFalse($part->useFloatAmount()); + + $part->setPartUnit($measurement_unit); + $this->assertTrue($part->useFloatAmount()); + + $measurement_unit->setIsInteger(true); + $this->assertFalse($part->useFloatAmount()); + } + + public function testGetAmountSum() + { + $part = new Part(); + $measurement_unit = new MeasurementUnit(); + $datetime = new \DateTime(); + + $this->assertEquals(0, $part->getAmountSum()); + + $part->addPartLot((new PartLot())->setAmount(3.141)); + $part->addPartLot((new PartLot())->setAmount(10.0)); + $part->addPartLot((new PartLot())->setAmount(5)->setInstockUnknown(true)); + $part->addPartLot( + (new PartLot()) + ->setAmount(6) + ->setExpirationDate($datetime->setTimestamp(strtotime('now -1 hour'))) + ); + + $this->assertEquals(13, $part->getAmountSum()); + + $part->setPartUnit($measurement_unit); + $this->assertEquals(13.141, $part->getAmountSum()); + + //1 billion part lot + $part->addPartLot((new PartLot())->setAmount(1000000000)); + $this->assertEquals(1000000013.141, $part->getAmountSum()); + $measurement_unit->setIsInteger(true); + $this->assertEquals(1000000013, $part->getAmountSum()); + } +} \ No newline at end of file diff --git a/tests/Entity/PriceSystem/CurrencyTest.php b/tests/Entity/PriceSystem/CurrencyTest.php new file mode 100644 index 00000000..e5895a33 --- /dev/null +++ b/tests/Entity/PriceSystem/CurrencyTest.php @@ -0,0 +1,44 @@ +assertNull($currency->getInverseExchangeRate()); + + $currency->setExchangeRate('0'); + $this->assertNull($currency->getInverseExchangeRate()); + + $currency->setExchangeRate("1.45643"); + $this->assertEquals("0.68661", $currency->getInverseExchangeRate()); + } +} \ No newline at end of file diff --git a/tests/Entity/PriceSystem/OrderdetailTest.php b/tests/Entity/PriceSystem/OrderdetailTest.php new file mode 100644 index 00000000..41bae66c --- /dev/null +++ b/tests/Entity/PriceSystem/OrderdetailTest.php @@ -0,0 +1,65 @@ +assertInstanceOf(Collection::class, $orderdetail->getPricedetails()); + $this->assertTrue($orderdetail->getPricedetails()->isEmpty()); + + $pricedetail = new Pricedetail(); + $orderdetail->addPricedetail($pricedetail); + $this->assertEquals($orderdetail, $pricedetail->getOrderdetail()); + $this->assertEquals(1, $orderdetail->getPricedetails()->count()); + + //After removal of the pricedetail, the orderdetail must be empty again + $orderdetail->removePricedetail($pricedetail); + $this->assertTrue($orderdetail->getPricedetails()->isEmpty()); + } + + public function testFindPriceForQty() + { + $price0 = (new Pricedetail())->setMinDiscountQuantity(0.23); + $price1 = (new Pricedetail())->setMinDiscountQuantity(1); + $price5 = (new Pricedetail())->setMinDiscountQuantity(5.3); + $orderdetail = (new Orderdetail())->addPricedetail($price0)->addPricedetail($price1)->addPricedetail($price5); + + $this->assertNull($orderdetail->findPriceForQty(0)); + $this->assertNull($orderdetail->findPriceForQty(0.1)); + + $this->assertEquals($price0, $orderdetail->findPriceForQty(0.5)); + $this->assertEquals($price1, $orderdetail->findPriceForQty(1)); + $this->assertEquals($price1, $orderdetail->findPriceForQty(1.5)); + $this->assertEquals($price5, $orderdetail->findPriceForQty(5.3)); + $this->assertEquals($price5, $orderdetail->findPriceForQty(10000)); + } +} \ No newline at end of file diff --git a/tests/Entity/PriceSystem/PricedetailTest.php b/tests/Entity/PriceSystem/PricedetailTest.php new file mode 100644 index 00000000..0af86e10 --- /dev/null +++ b/tests/Entity/PriceSystem/PricedetailTest.php @@ -0,0 +1,108 @@ +setPrice('100.234'); + + $this->assertEquals('100.23400', $pricedetail->getPricePerUnit()); + + $pricedetail->setPriceRelatedQuantity('2.3'); + $this->assertEquals('43.58000', $pricedetail->getPricePerUnit()); + $this->assertEquals('139.45600', $pricedetail->getPricePerUnit('3.2')); + + + $pricedetail->setPrice('10000000.2345'); //Ten million + $pricedetail->setPriceRelatedQuantity(1.234e9); //100 billion + $this->assertEquals('0.00810', $pricedetail->getPricePerUnit()); + } + + public function testGetPriceRelatedQuantity() + { + $pricedetail = new Pricedetail(); + $part = $this->createMock(Part::class); + $part->method('useFloatAmount')->willReturn(false); + $orderdetail = $this->createMock(Orderdetail::class); + $orderdetail->method('getPart')->willReturn($part); + + $part2 = $this->createMock(Part::class); + $part2->method('useFloatAmount')->willReturn(true); + $orderdetail2 = $this->createMock(Orderdetail::class); + $orderdetail2->method('getPart')->willReturn($part2); + + + //By default a price detail returns 1 + $this->assertEquals(1, $pricedetail->getPriceRelatedQuantity()); + + $pricedetail->setOrderdetail($orderdetail); + $pricedetail->setPriceRelatedQuantity(10.23); + $this->assertEquals(10, $pricedetail->getPriceRelatedQuantity()); + //Price related quantity must not be zero! + $pricedetail->setPriceRelatedQuantity(0.23); + $this->assertEquals(1, $pricedetail->getPriceRelatedQuantity()); + + //With an part that has an float amount unit, also values like 0.23 can be returned + $pricedetail->setOrderdetail($orderdetail2); + $this->assertEquals(0.23, $pricedetail->getPriceRelatedQuantity()); + } + + public function testGetMinDiscountQuantity() + { + $pricedetail = new Pricedetail(); + $part = $this->createMock(Part::class); + $part->method('useFloatAmount')->willReturn(false); + $orderdetail = $this->createMock(Orderdetail::class); + $orderdetail->method('getPart')->willReturn($part); + + $part2 = $this->createMock(Part::class); + $part2->method('useFloatAmount')->willReturn(true); + $orderdetail2 = $this->createMock(Orderdetail::class); + $orderdetail2->method('getPart')->willReturn($part2); + + + //By default a price detail returns 1 + $this->assertEquals(1, $pricedetail->getMinDiscountQuantity()); + + $pricedetail->setOrderdetail($orderdetail); + $pricedetail->setMinDiscountQuantity(10.23); + $this->assertEquals(10, $pricedetail->getMinDiscountQuantity()); + //Price related quantity must not be zero! + $pricedetail->setMinDiscountQuantity(0.23); + $this->assertEquals(1, $pricedetail->getMinDiscountQuantity()); + + //With an part that has an float amount unit, also values like 0.23 can be returned + $pricedetail->setOrderdetail($orderdetail2); + $this->assertEquals(0.23, $pricedetail->getMinDiscountQuantity()); + } +} \ No newline at end of file diff --git a/tests/Entity/PermissionsEmbedTest.php b/tests/Entity/UserSystem/PermissionsEmbedTest.php similarity index 99% rename from tests/Entity/PermissionsEmbedTest.php rename to tests/Entity/UserSystem/PermissionsEmbedTest.php index 1a025c4c..3a53cd83 100644 --- a/tests/Entity/PermissionsEmbedTest.php +++ b/tests/Entity/UserSystem/PermissionsEmbedTest.php @@ -20,7 +20,7 @@ * */ -namespace App\Tests\Entity; +namespace App\Tests\Entity\UserSystem; use App\Entity\UserSystem\PermissionsEmbed; use Doctrine\ORM\Mapping\Embedded; diff --git a/tests/Entity/UserSystem/UserTest.php b/tests/Entity/UserSystem/UserTest.php new file mode 100644 index 00000000..99c6ed35 --- /dev/null +++ b/tests/Entity/UserSystem/UserTest.php @@ -0,0 +1,41 @@ +setName('username'); + $user->setFirstName('John'); + $user->setLastName('Doe'); + + $this->assertEquals('John Doe', $user->getFullName(false)); + $this->assertEquals('John Doe (username)', $user->getFullName(true)); + } +} \ No newline at end of file