<?php /** * This file contains QUI\ERP\Money\Price */ namespace QUI\ERP\Money; use QUI; use QUI\ERP\Currency\Currency; use QUI\ERP\Discount\Discount; use QUI\Interfaces\Users\User; use function floatval; use function is_float; use function is_int; use function mb_strpos; use function mb_substr; use function preg_replace; use function round; use function str_replace; use function trim; /** * Class Price * @package QUI\ERP\Products\Price */ class Price { /** * Netto Price * @var float|int */ protected float | int $price; /** * Price currency * @var QUI\ERP\Currency\Currency */ protected QUI\ERP\Currency\Currency $Currency; /** * Flag for Price from * @var bool */ protected bool $isMinimalPrice = false; /** * @var array */ protected array $discounts; /** * User * @var ?QUI\Interfaces\Users\User */ protected ?QUI\Interfaces\Users\User $User = null; /** * Price constructor. * * @param float|int|null $price * @param Currency $Currency * @param User|null $User - optional, if no user, session user are used */ public function __construct( float | int | null $price, QUI\ERP\Currency\Currency $Currency, null | QUI\Interfaces\Users\User $User = null ) { if (!$price) { $price = 0; } $this->price = $price; $this->Currency = $Currency; $this->User = $User; $this->discounts = []; if (!QUI::getUsers()->isUser($User)) { $this->User = QUI::getUserBySession(); } } /** * Return the price as array notation * @return array */ public function toArray(): array { return [ 'price' => $this->value(), 'currency' => $this->getCurrency()->getCode(), 'display' => $this->getDisplayPrice(), 'isMinimalPrice' => $this->isMinimalPrice() ]; } /** * Return the real price * * @return float|int|null */ public function getPrice(): float | int | null { return $this->validatePrice($this->price); } /** * Alias for getPrice * * @return float|int|null */ public function value(): float | int | null { return $this->getPrice(); } /** * Alias for getPrice * * @return float|int|null */ public function getValue(): float | int | null { return $this->getPrice(); } /** * Return the price for the view / displaying * * @return string */ public function getDisplayPrice(): string { return $this->Currency->format($this->getPrice()); } /** * Add a discount to the price * * @param QUI\ERP\Discount\Discount $Discount * @throws QUI\Exception */ public function addDiscount(Discount $Discount): void { /* @var $Disc Discount */ foreach ($this->discounts as $Disc) { // der gleiche discount kann nur einmal enthalten sein if ($Disc->getId() == $Discount->getId()) { return; } if ($Disc->canCombinedWith($Discount) === false) { throw new QUI\Exception([ 'quiqqer/products', 'exception.discount.not.combinable', [ 'id1' => $Disc->getId(), 'id2' => $Discount->getId() ] ]); } } $this->discounts[] = $Discount; } /** * Return the assigned discounts * * @return array [Discount, Discount, Discount] */ public function getDiscounts(): array { return $this->discounts; } /** * Return the currency from the price * * @return QUI\ERP\Currency\Currency */ public function getCurrency(): QUI\ERP\Currency\Currency { return $this->Currency; } /** * calculation */ /** * Validates a price value * * @param mixed $value * @param QUI\Locale|null $Locale - based locale, in which the price is * @return float|int|null */ public static function validatePrice(mixed $value, null | QUI\Locale $Locale = null): float | int | null { if (is_float($value) || is_int($value)) { return round($value, QUI\ERP\Defaults::getPrecision()); } if ($value instanceof Price) { $value = $value->getPrice(); } $value = (string)$value; $isNegative = str_starts_with($value, '-'); // value cleanup $value = preg_replace('#[^\d,.]#i', '', $value); if (trim($value) === '') { return null; } if ($Locale === null) { $Locale = QUI::getSystemLocale(); } $negativeTurn = 1; if ($isNegative) { $negativeTurn = -1; } $decimalSeparator = $Locale->getDecimalSeparator(); $thousandSeparator = $Locale->getGroupingSeparator(); $decimal = mb_strpos($value, $decimalSeparator); $thousands = mb_strpos($value, $thousandSeparator); if ($thousands === false && $decimal === false) { return round(floatval($value), 4) * $negativeTurn; } if ($thousands !== false && $decimal === false) { if (mb_substr($value, -4, 1) === $thousandSeparator) { $value = str_replace($thousandSeparator, '', $value); } } if ($thousands === false && $decimal !== false) { $value = str_replace($decimalSeparator, '.', $value); } if ($thousands !== false && $decimal !== false) { $value = str_replace($thousandSeparator, '', $value); $value = str_replace($decimalSeparator, '.', $value); } $value = floatval($value); $value = round($value, QUI\ERP\Defaults::getPrecision()); return $value * $negativeTurn; } /** * Return if the price is minimal price and higher prices exists * * @return bool */ public function isMinimalPrice(): bool { return $this->isMinimalPrice; } /** * enables the minimal price * -> price from * -> ab */ public function enableMinimalPrice(): void { $this->isMinimalPrice = true; } /** * enables the minimal price * -> price from * -> ab */ public function disableMinimalPrice(): void { $this->isMinimalPrice = false; } }