<?php /** * This file contains QUI\ERP\Accounting\ArticleList */ namespace QUI\ERP\Accounting; use IteratorAggregate; use QUI; use QUI\ERP\Accounting\PriceFactors\Factor; use QUI\ERP\Currency\Currency; use QUI\ERP\Exception; use QUI\Interfaces\Users\User; use function count; use function is_null; use function key; use function round; /** * Class ArticleList * * @package QUI\ERP\Accounting */ class ArticleList extends ArticleListUnique implements IteratorAggregate { /** * is the article list calculated? * @var bool */ protected bool $calculated = false; /** * @var int|float */ protected int | float $sum; /** * @var int|float */ protected int | float $grandSubSum; /** * @var ?QUI\Interfaces\Users\User */ protected QUI\Interfaces\Users\User | null $User = null; /** * @var ?QUI\ERP\Order\AbstractOrder */ protected ?QUI\ERP\Order\AbstractOrder $Order = null; /** * @var ?QUI\ERP\Currency\Currency */ protected ?QUI\ERP\Currency\Currency $Currency = null; /** * @var int|float */ protected int | float $subSum; /** * @var int|float */ protected int | float $nettoSum; /** * @var int|float */ protected int | float $nettoSubSum; /** * key 19% value[sum] = sum value[text] = text value[display_sum] formatted * * @var array */ protected array $vatArray = []; /** * key 19% value[sum] = sum value[text] = text value[display_sum] formatted * * @var array */ protected array $vatText; /** * Prüfen ob EU Vat für den Benutzer in Frage kommt */ protected bool $isEuVat = false; /** * Wird Brutto oder Netto gerechnet * * @var bool */ protected bool $isNetto = true; /** * Currency information * * @var array */ protected array $currencyData = [ 'currency_sign' => '', 'currency_code' => '', 'user_currency' => '', 'currency_rate' => '' ]; /** * ArticleList constructor. * * @param array $attributes * @throws Exception|QUI\Exception */ public function __construct(array $attributes = []) { if (!isset($attributes['calculations'])) { $attributes['calculations'] = []; } if (!isset($attributes['articles'])) { $attributes['articles'] = []; } if (!isset($attributes['priceFactors'])) { $attributes['priceFactors'] = []; } parent::__construct($attributes); if (!empty($this->calculations)) { $this->calculated = true; } } /** * Set the user for the list * User for calculation * * @param null|QUI\Interfaces\Users\User $User */ public function setUser(null | QUI\Interfaces\Users\User $User): void { if ($this->User === $User) { return; } $this->calculated = false; $this->User = $User; foreach ($this->articles as $Article) { $Article->setUser($User); } $this->calc(); } /** * Return the list user * * @return User|null */ public function getUser(): ?QUI\Interfaces\Users\User { return $this->User; } /** * Return the currency * * @return Currency|null */ public function getCurrency(): ?QUI\ERP\Currency\Currency { if (!is_null($this->Currency)) { return $this->Currency; } if (!empty($this->currencyData['currency_code'])) { try { $this->Currency = QUI\ERP\Currency\Handler::getCurrency( $this->currencyData['currency_code'] ); return $this->Currency; } catch (QUI\Exception) { } } return QUI\ERP\Defaults::getCurrency(); } /** * Set the currency for the list * * @param QUI\ERP\Currency\Currency $Currency */ public function setCurrency(QUI\ERP\Currency\Currency $Currency): void { if ($this->Currency === $Currency) { return; } $this->Currency = $Currency; $this->currencyData = [ 'currency_sign' => $this->Currency->getSign(), 'currency_code' => $this->Currency->getCode(), 'user_currency' => '', 'currency_rate' => $this->Currency->getExchangeRate() ]; if (isset($this->calculations['currencyData'])) { $this->calculations['currencyData'] = [ 'code' => $this->Currency->getCode(), 'sign' => $this->Currency->getSign(), 'rate' => $this->Currency->getExchangeRate() ]; } if (count($this->articles)) { foreach ($this->articles as $Article) { $Article->setCurrency($Currency); } } $PriceFactors = $this->getPriceFactors(); $priceFactors = $PriceFactors->toArray(); foreach ($priceFactors as $k => $factor) { $priceFactors[$k]['sumFormatted'] = $Currency->format($factor['sum']); $priceFactors[$k]['nettoSumFormatted'] = $Currency->format($factor['nettoSum']); $priceFactors[$k]['valueText'] = $priceFactors[$k]['sumFormatted']; if ($factor['sum'] > 0) { $priceFactors[$k]['valueText'] = '+' . $priceFactors[$k]['sumFormatted']; } } $this->PriceFactors = new QUI\ERP\Accounting\PriceFactors\FactorList($priceFactors); } /** * Return the list as an array * * @return array */ public function toArray(): array { $data = parent::toArray(); if (empty($data['calculations'])) { return $data; } $Currency = $this->getCurrency(); // format $articles = $data['articles']; $calculations = $data['calculations']; $calculations['currencyData'] = $Currency->toArray(); $calculations['vatSum'] = QUI\ERP\Accounting\Calc::calculateTotalVatOfInvoice( $calculations['vatArray'] ); $calculations['display_subSum'] = $Currency->format($calculations['subSum']); $calculations['display_sum'] = $Currency->format($calculations['sum']); $calculations['display_vatSum'] = $Currency->format($calculations['vatSum']); foreach ($articles as $key => $article) { $articles[$key]['position'] = $key + 1; $articles[$key]['display_sum'] = $Currency->format($article['sum']); $articles[$key]['display_unitPrice'] = $Currency->format($article['unitPrice']); } $data['articles'] = $articles; $data['calculations'] = $calculations; /* @var $Factor PriceFactors\Factor */ foreach ($this->PriceFactors as $Factor) { if (!$Factor->isVisible()) { continue; } $key = 'attributes'; if ($Factor->getCalculationBasis() === QUI\ERP\Accounting\Calc::CALCULATION_GRAND_TOTAL) { $key = 'grandTotalFactors'; } $data[$key][] = [ 'title' => $Factor->getTitle(), 'value' => $Factor->getSumFormatted(), 'valueText' => '' ]; } return $data; } /** * Parse this ArticleList to an ArticleListUnique * * @return ArticleListUnique * * @throws Exception * @throws QUI\Exception */ public function toUniqueList(): ArticleListUnique { $this->calc(); $List = new ArticleListUnique($this->toArray(), $this->getUser()); if ($this->ExchangeCurrency) { $List->setExchangeCurrency($this->ExchangeCurrency); } return $List; } /** * @param ?QUI\ERP\Accounting\Calc $Calc */ public function recalculate(?QUI\ERP\Accounting\Calc $Calc = null): void { $this->calculated = false; foreach ($this->articles as $Article) { if ($this->User) { $Article->setUser($this->User); } } $this->calc($Calc); } /** * @param null|QUI\ERP\Accounting\Calc $Calc $Calc * @return ArticleList */ public function calc(?QUI\ERP\Accounting\Calc $Calc = null): ArticleList { if ($this->calculated) { return $this; } if (!$Calc) { $Calc = Calc::getInstance(); if ($this->User) { $Calc->setUser($this->User); } } $Calc->calcArticleList($this, function ($data) { $self = $this; $self->sum = $data['sum']; $self->grandSubSum = $data['grandSubSum']; $self->subSum = $data['subSum']; $self->nettoSum = $data['nettoSum']; $self->nettoSubSum = $data['nettoSubSum']; $self->vatArray = $data['vatArray']; $self->vatText = $data['vatText']; $self->isEuVat = $data['isEuVat']; $self->isNetto = $data['isNetto']; $self->currencyData = $data['currencyData']; $this->calculations = [ 'sum' => $self->sum, 'grandSubSum' => $self->grandSubSum, 'subSum' => $self->subSum, 'nettoSum' => $self->nettoSum, 'nettoSubSum' => $self->nettoSubSum, 'vatArray' => $self->vatArray, 'vatText' => $self->vatText, 'isEuVat' => $self->isEuVat, 'isNetto' => $self->isNetto, 'currencyData' => $self->currencyData ]; $self->setCurrency($self->getCurrency()); $self->calculated = true; }); return $this; } //region Article Management /** * Add an article to the list * * @param Article $Article */ public function addArticle(Article $Article): void { $this->articles[] = $Article; $this->calculated = false; if ($this->User) { $Article->setUser($this->User); } if ($this->Currency) { $Article->setCurrency($this->Currency); } } /** * Remove an article by its index position * * @param integer $index */ public function removeArticle(int $index): void { if (isset($this->articles[$index])) { unset($this->articles[$index]); } } /** * @param $pos * @return Article|null */ public function getArticle($pos): ?Article { if (isset($this->articles[$pos])) { return $this->articles[$pos]; } return null; } /** * Replace an article at a specific position * * @param Article $Article * @param integer $index */ public function replaceArticle(Article $Article, int $index): void { $this->articles[$index] = $Article; } /** * Clears the list */ public function clear(): void { $this->articles = []; } /** * Return the length of the list * * @return int */ public function count(): int { return count($this->articles); } //endregion //region Price Factors /** * Import a price factor list * * @param QUI\ERP\Accounting\PriceFactors\FactorList $PriceFactors */ public function importPriceFactors(QUI\ERP\Accounting\PriceFactors\FactorList $PriceFactors): void { $this->PriceFactors = $PriceFactors; } /** * @param Factor|QUI\ERP\Products\Utils\PriceFactor $PriceFactor * @return void * * @throws Exception */ public function addPriceFactor(Factor | QUI\ERP\Products\Utils\PriceFactor $PriceFactor): void { if ($PriceFactor instanceof QUI\ERP\Products\Utils\PriceFactor) { $isNetto = $this->isNetto; $vat = 0; $netto = $PriceFactor->getNettoSum(); $precision = $this->getCurrency()->getPrecision(); if (count($this->vatArray)) { $vat = key($this->vatArray); } if ($PriceFactor->getVat()) { $vat = $PriceFactor->getVat(); } $PriceFactor->setVat($vat); $brutto = $netto * ((100 + $vat) / 100); $brutto = round($brutto, $precision); if ($isNetto) { $PriceFactor->setSum($netto); } else { $PriceFactor->setSum($brutto); } $PriceFactor = new Factor($PriceFactor->toArray()); } $this->PriceFactors->addFactor($PriceFactor); $this->recalculate(); } //endregion //region order /** * @param QUI\ERP\Order\AbstractOrder $Order */ public function setOrder(QUI\ERP\Order\AbstractOrder $Order): void { $this->Order = $Order; } /** * @return QUI\ERP\Order\AbstractOrder|null */ public function getOrder(): ?QUI\ERP\Order\AbstractOrder { return $this->Order; } //endregion //render public function renderForMail(): string { return $this->toUniqueList()->renderForMail(); } public function toHTMLWithCSS( bool | string $template = false, bool | string $articleTemplate = false, ?QUI\Interfaces\Template\EngineInterface $Engine = null, ): string { return $this->toUniqueList()->toHTMLWithCSS($template, $articleTemplate, $Engine); } //endregion }