diff --git a/src/Entity/Parts/Part.php b/src/Entity/Parts/Part.php index 5087ddf4..e31ae63a 100644 --- a/src/Entity/Parts/Part.php +++ b/src/Entity/Parts/Part.php @@ -537,68 +537,6 @@ class Part extends AttachmentContainingDBElement return $this->devices; } - /** - * Get all prices of this part. - * - * This method simply gets the prices of the orderdetails and prepare them.\n - * In the returned array/string there is a price for every supplier. - * @param int $quantity this is the quantity to choose the correct priceinformation - * @param int|null $multiplier * This is the multiplier which will be applied to every single price - * * If you pass NULL, the number from $quantity will be used - * @param bool $hide_obsolete If true, prices from obsolete orderdetails will NOT be returned - * - * @return float[] all prices as an array of floats (if "$delimeter == NULL" & "$float_array == true") - * - * @throws \Exception if there was an error - */ - public function getPrices(int $quantity = 1, $multiplier = null, bool $hide_obsolete = false) : array - { - $prices = array(); - - foreach ($this->getOrderdetails($hide_obsolete) as $details) { - $prices[] = $details->getPrice($quantity, $multiplier); - } - - return $prices; - } - - /** - * Get the average price of all orderdetails. - * - * With the $multiplier you're able to multiply the price before it will be returned. - * This is useful if you want to have the price as a string with currency, but multiplied with a factor. - * - * @param int $quantity this is the quantity to choose the correct priceinformations - * @param int|null $multiplier * This is the multiplier which will be applied to every single price - * * If you pass NULL, the number from $quantity will be used - * - * @return float price (if "$as_money_string == false") - * - * @throws \Exception if there was an error - */ - public function getAveragePrice(int $quantity = 1, $multiplier = null) : ?float - { - $prices = $this->getPrices($quantity, $multiplier, true); - //Findout out - - $average_price = null; - - $count = 0; - foreach ($this->getOrderdetails() as $orderdetail) { - $price = $orderdetail->getPrice(1, null); - if (null !== $price) { - $average_price += $price; - ++$count; - } - } - - if ($count > 0) { - $average_price /= $count; - } - - return $average_price; - } - /** * Checks if this part is marked, for that it needs further review. * @return bool diff --git a/src/Entity/PriceInformations/Orderdetail.php b/src/Entity/PriceInformations/Orderdetail.php index 13530816..ec5d31fc 100644 --- a/src/Entity/PriceInformations/Orderdetail.php +++ b/src/Entity/PriceInformations/Orderdetail.php @@ -217,8 +217,6 @@ class Orderdetail extends DBElement * * @return Pricedetail[]|Collection all pricedetails as a one-dimensional array of Pricedetails objects, * sorted by minimum discount quantity - * - * @throws Exception if there was an error */ public function getPricedetails(): Collection { @@ -249,50 +247,30 @@ class Orderdetail extends DBElement } /** - * Get the price for a specific quantity. + * Get the pricedetail for a specific quantity. * @param float $quantity this is the quantity to choose the correct pricedetails - * @param string|float|int $multiplier * This is the multiplier which will be applied to every single price - * * If you pass NULL, the number from $quantity will be used * - * @return string|null: the price as a bcmath string. Null if there are no orderdetails for the given quantity - * - * @throws Exception if there are no pricedetails for the choosed quantity - * (for example, there are only one pricedetails with the minimum discount quantity '10', - * but the choosed quantity is '5' --> the price for 5 parts is not defined!) - * @throws Exception if there was an error + * @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, $multiplier = 1) : ?string + public function getPrice(float $quantity = 1) : ?Pricedetail { - if (($quantity === 0) && ($multiplier === null)) { - return "0.0"; + if ($quantity <= 0) { + return null; } $all_pricedetails = $this->getPricedetails(); - if (count($all_pricedetails) == 0) { - return null; - } - - - $correct_pricedetails = null; - foreach ($all_pricedetails as $pricedetails) { + $correct_pricedetail = null; + foreach ($all_pricedetails as $pricedetail) { // choose the correct pricedetails for the choosed quantity ($quantity) - if ($quantity < $pricedetails->getMinDiscountQuantity()) { + if ($quantity < $pricedetail->getMinDiscountQuantity()) { break; } - $correct_pricedetails = $pricedetails; + $correct_pricedetail = $pricedetail; } - if ($correct_pricedetails === null) { - return null; - } - - if ($multiplier === null) { - $multiplier = $quantity; - } - - return $correct_pricedetails->getPricePerUnit($multiplier); + return $correct_pricedetail; } /******************************************************************************** diff --git a/src/Entity/PriceInformations/Pricedetail.php b/src/Entity/PriceInformations/Pricedetail.php index 2eaa0519..557183d2 100644 --- a/src/Entity/PriceInformations/Pricedetail.php +++ b/src/Entity/PriceInformations/Pricedetail.php @@ -181,7 +181,7 @@ class Pricedetail extends DBElement /** * Get the price for a single unit in the currency associated with this price detail. * - * @param float $multiplier The returned price (float or string) will be multiplied + * @param float|string $multiplier The returned price (float or string) will be multiplied * with this multiplier. * * You will get the price for $multiplier parts. If you want the price which is stored @@ -190,7 +190,7 @@ class Pricedetail extends DBElement * @return string the price as a bcmath string */ - public function getPricePerUnit($multiplier = 1) : string + public function getPricePerUnit($multiplier = 1.0) : string { $multiplier = (string) $multiplier; $tmp = bcmul($this->price, $multiplier, static::PRICE_PRECISION); diff --git a/src/Services/PricedetailHelper.php b/src/Services/PricedetailHelper.php index d0e33bec..5dbbfee8 100644 --- a/src/Services/PricedetailHelper.php +++ b/src/Services/PricedetailHelper.php @@ -31,11 +31,10 @@ namespace App\Services; +use App\Entity\Parts\Part; use App\Entity\PriceInformations\Currency; use App\Entity\PriceInformations\Pricedetail; use Locale; -use Money\Number; -use Symfony\Component\Intl\Currencies; class PricedetailHelper { @@ -48,6 +47,119 @@ class PricedetailHelper $this->locale = Locale::getDefault(); } + /** + * Determines the highest amount, for which you get additional discount. + * This function determines the highest min_discount_quantity for the given part. + * @param Part $part + * @return float|null + */ + public function getMaxDiscountAmount(Part $part) : ?float + { + $orderdetails = $part->getOrderdetails(true); + + $max = 0; + + foreach ($orderdetails as $orderdetail) { + $pricedetails = $orderdetail->getPricedetails(); + //The orderdetail must have pricedetails, otherwise this will not work! + if (empty($pricedetails)) { + continue; + } + + /* Pricedetails in orderdetails are ordered by min discount quantity, + so our first object is our min order amount for the current orderdetail */ + $max_amount = $pricedetails->last()->getMinDiscountQuantity(); + + if ($max_amount > $max) { + $max = $max_amount; + } + } + + if ($max > 0) { + return $max; + } + + return null; + } + + /** + * Determines the minimum amount of the part that can be ordered + * @param Part $part The part for which the minimum order amount should be determined. + * @return float + */ + public function getMinOrderAmount(Part $part) : ?float + { + $orderdetails = $part->getOrderdetails(true); + + $min = INF; + + foreach ($orderdetails as $orderdetail) { + $pricedetails = $orderdetail->getPricedetails(); + //The orderdetail must have pricedetails, otherwise this will not work! + if (count($pricedetails) === 0) { + continue; + } + + /* Pricedetails in orderdetails are ordered by min discount quantity, + so our first object is our min order amount for the current orderdetail */ + $min_amount = $pricedetails[0]->getMinDiscountQuantity(); + + if ($min_amount < $min) { + $min = $min_amount; + } + } + + if ($min < INF) { + return $min; + } + + return null; + } + + /** + * Calculates the average price of a part, when ordering the amount $amount. + * @param Part $part The part for which the average price should be calculated. + * @param float $amount The order amount for which the average price should be calculated. + * If set to null, the mininmum order amount for the part is used. + * @param Currency|null $currency The currency in which the average price should be calculated + * @return string|null The Average price as bcmath string. Returns null, if it was not possible to calculate the + * price for the given + */ + public function calculateAvgPrice(Part $part, ?float $amount = null, ?Currency $currency = null) : ?string + { + if ($amount === null) { + $amount = $this->getMinOrderAmount($part); + } + + if ($amount === null) { + return null; + } + + $orderdetails = $part->getOrderdetails(true); + + $avg = "0"; + $count = 0; + + //Find the price for the amount, for the given + foreach ($orderdetails as $orderdetail) { + $pricedetail = $orderdetail->getPrice($amount); + + //When we dont have informations about this amount, ignore it + if ($pricedetail === null) { + continue; + } + + $avg = bcadd($avg, $this->convertMoneyToCurrency($pricedetail->getPricePerUnit(), $pricedetail->getCurrency(), $currency), Pricedetail::PRICE_PRECISION); + $count++; + } + + if ($count === 0) { + return null; + } + + return bcdiv($avg, (string) $count, Pricedetail::PRICE_PRECISION); + } + /** * Converts the given value in origin currency to the choosen target currency * @param $value float|string The value that should be converted @@ -60,11 +172,16 @@ class PricedetailHelper */ public function convertMoneyToCurrency($value, ?Currency $originCurrency = null, ?Currency $targetCurrency = null) : ?string { + //Skip conversion, if both currencies are same + if ($originCurrency === $targetCurrency) { + return $value; + } + $value = (string) $value; //Convert value to base currency $val_base = $value; - if($originCurrency !== null) { + if ($originCurrency !== null) { //Without an exchange rate we can not calculate the exchange rate if ((float) $originCurrency->getExchangeRate() === 0) { return null; diff --git a/templates/Parts/info/_main_infos.html.twig b/templates/Parts/info/_main_infos.html.twig index 71a9635c..65e507a6 100644 --- a/templates/Parts/info/_main_infos.html.twig +++ b/templates/Parts/info/_main_infos.html.twig @@ -34,9 +34,23 @@ {{ part.footprint.fullPath ?? "-"}} -