Skip to content
Code-Schnipsel Gruppen Projekte
ArticleList.php 12,9 KiB
Newer Older
<?php

/**
 * This file contains QUI\ERP\Accounting\ArticleList
 */

namespace QUI\ERP\Accounting;

Henning Leutz's avatar
Henning Leutz committed
use IteratorAggregate;
Henning Leutz's avatar
Henning Leutz committed
use function count;
use function is_null;
use function key;
use function round;
/**
 * Class ArticleList
 *
 * @package QUI\ERP\Accounting
 */
Henning Leutz's avatar
Henning Leutz committed
class ArticleList extends ArticleListUnique implements IteratorAggregate
    /**
     * is the article list calculated?
     * @var bool
     */
Henning Leutz's avatar
Henning Leutz committed
    protected bool $calculated = false;
Henning Leutz's avatar
Henning Leutz committed
     * @var int|float
Henning Leutz's avatar
Henning Leutz committed
    /**
     * @var int|float
     */
    protected $grandSubSum;

    /**
     * @var QUI\Interfaces\Users\User
     */
    protected $User = null;

Henning Leutz's avatar
Henning Leutz committed
     * @var ?QUI\ERP\Order\AbstractOrder
Henning Leutz's avatar
Henning Leutz committed
    protected ?QUI\ERP\Order\AbstractOrder $Order = null;
Henning Leutz's avatar
Henning Leutz committed
     * @var ?QUI\ERP\Currency\Currency
Henning Leutz's avatar
Henning Leutz committed
    protected ?QUI\ERP\Currency\Currency $Currency = null;
Henning Leutz's avatar
Henning Leutz committed
     * @var int|float
     */
    protected $subSum;

    /**
Henning Leutz's avatar
Henning Leutz committed
     * @var int|float
     */
    protected $nettoSum;

    /**
Henning Leutz's avatar
Henning Leutz committed
     * @var int|float
     */
    protected $nettoSubSum;

    /**
Henning Leutz's avatar
Henning Leutz committed
     * key 19% value[sum] = sum value[text] = text value[display_sum] formatted
     *
     * @var array
     */
Henning Leutz's avatar
Henning Leutz committed
    protected array $vatArray = [];
Henning Leutz's avatar
Henning Leutz committed
     * key 19% value[sum] = sum value[text] = text value[display_sum] formatted
     *
     * @var array
Henning Leutz's avatar
Henning Leutz committed
    protected array $vatText;

    /**
     * Prüfen ob EU Vat für den Benutzer in Frage kommt
Henning Leutz's avatar
Henning Leutz committed
     *
Henning Leutz's avatar
Henning Leutz committed
    protected bool $isEuVat = false;

    /**
     * Wird Brutto oder Netto gerechnet
Henning Leutz's avatar
Henning Leutz committed
     *
Henning Leutz's avatar
Henning Leutz committed
    protected bool $isNetto = true;

    /**
     * Currency information
Henning Leutz's avatar
Henning Leutz committed
     *
Henning Leutz's avatar
Henning Leutz committed
    protected array $currencyData = [
        'currency_sign' => '',
        'currency_code' => '',
        'user_currency' => '',
        'currency_rate' => ''

    /**
     * ArticleList constructor.
Henning Leutz's avatar
Henning Leutz committed
     *
     * @param array $attributes
Henning Leutz's avatar
Henning Leutz committed
     * @throws QUI\ERP\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);
Henning Leutz's avatar
Henning Leutz committed

        if (!empty($this->calculations)) {
            $this->calculated = true;
        }
    }

    /**
     * Set the user for the list
     * User for calculation
     *
     * @param QUI\Interfaces\Users\User $User
     */
    public function setUser(QUI\Interfaces\Users\User $User)
    {
Henning Leutz's avatar
Henning Leutz committed
        $this->User       = $User;

        foreach ($this->articles as $Article) {
            $Article->setUser($User);
        }

        $this->calc();
    }

    /**
     * Return the list user
     *
Henning Leutz's avatar
Henning Leutz committed
     * @return QUI\Interfaces\Users\User
Henning Leutz's avatar
Henning Leutz committed
    public function getUser(): ?QUI\Interfaces\Users\User
    /**
     * Return the currency
     *
     * @return QUI\ERP\Currency\Currency
     */
Henning Leutz's avatar
Henning Leutz committed
    public function getCurrency(): ?QUI\ERP\Currency\Currency
Henning Leutz's avatar
Henning Leutz committed
        if (!is_null($this->Currency)) {
Henning Leutz's avatar
Henning Leutz committed
        if (!empty($this->currencyData['currency_code'])) {
            try {
                $this->Currency = QUI\ERP\Currency\Handler::getCurrency(
                    $this->currencyData['currency_code']
                );

                return $this->Currency;
            } catch (QUI\Exception $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)
    {
        $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()
            ];
        }
Henning Leutz's avatar
Henning Leutz committed
        if (count($this->articles)) {
            foreach ($this->articles as $Article) {
                $Article->setCurrency($Currency);
            }
        }
Henning Leutz's avatar
Henning Leutz committed

        $PriceFactors = $this->getPriceFactors();
        $priceFactors = $PriceFactors->toArray();

        foreach ($priceFactors as $k => $factor) {
Henning Leutz's avatar
Henning Leutz committed
            $priceFactors[$k]['sumFormatted']      = $Currency->format($factor['sum']);
Henning Leutz's avatar
Henning Leutz committed
            $priceFactors[$k]['nettoSumFormatted'] = $Currency->format($factor['nettoSum']);
Henning Leutz's avatar
Henning Leutz committed
            $priceFactors[$k]['valueText']         = $priceFactors[$k]['sumFormatted'];
Henning Leutz's avatar
Henning Leutz committed

            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
     */
Henning Leutz's avatar
Henning Leutz committed
    public function toArray(): array
    {
        $data = parent::toArray();

        if (empty($data['calculations'])) {
            return $data;
        }

        $Currency = $this->getCurrency();

        // format
Henning Leutz's avatar
Henning Leutz committed
        $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']);
Henning Leutz's avatar
Henning Leutz committed
        $calculations['display_sum']    = $Currency->format($calculations['sum']);
        $calculations['display_vatSum'] = $Currency->format($calculations['vatSum']);

        foreach ($articles as $key => $article) {
Henning Leutz's avatar
Henning Leutz committed
            $articles[$key]['position']          = $key + 1;
            $articles[$key]['display_sum']       = $Currency->format($article['sum']);
            $articles[$key]['display_unitPrice'] = $Currency->format($article['unitPrice']);
        }

Henning Leutz's avatar
Henning Leutz committed
        $data['articles']     = $articles;
        $data['calculations'] = $calculations;

        /* @var $Factor PriceFactors\Factor */
        foreach ($this->PriceFactors as $Factor) {
            if (!$Factor->isVisible()) {
                continue;
            }

Henning Leutz's avatar
Henning Leutz committed
            $key = 'attributes';

            if ($Factor->getCalculationBasis() === QUI\ERP\Accounting\Calc::CALCULATION_GRAND_TOTAL) {
                $key = 'grandTotalFactors';
            }

            $data[$key][] = [
                'title'     => $Factor->getTitle(),
                'value'     => $Factor->getSumFormatted(),
                'valueText' => ''
    /**
     * Parse this ArticleList to an ArticleListUnique
     *
     * @return ArticleListUnique
Henning Leutz's avatar
Henning Leutz committed
     *
     * @throws QUI\ERP\Exception
     * @throws QUI\Exception
Henning Leutz's avatar
Henning Leutz committed
    public function toUniqueList(): ArticleListUnique
        $List = new ArticleListUnique($this->toArray(), $this->getUser());

        if ($this->ExchangeCurrency) {
            $List->setExchangeCurrency($this->ExchangeCurrency);
        }

        return $List;
    /**
     * @param null $Calc
     */
    public function recalculate($Calc = null)
    {
        $this->calculated = false;
Henning Leutz's avatar
Henning Leutz committed

        foreach ($this->articles as $Article) {
            if ($this->User) {
                $Article->setUser($this->User);
            }
     * @param null|Calc $Calc
     * @return ArticleList|ArticleListUnique
Henning Leutz's avatar
Henning Leutz committed
    public function calc($Calc = null): ArticleList
        $self = $this;

        if (!$Calc) {
            $Calc = Calc::getInstance();

            if ($this->User) {
                $Calc->setUser($this->User);
            }
        }

        $Calc->calcArticleList($this, function ($data) use ($self) {
Henning Leutz's avatar
Henning Leutz committed
            $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,
Henning Leutz's avatar
Henning Leutz committed
                '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)
    {
        $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
     */
Henning Leutz's avatar
Henning Leutz committed
    public function removeArticle(int $index)
    {
        if (isset($this->articles[$index])) {
            unset($this->articles[$index]);
        }
    }

    /**
     * @param $pos
     * @return Article|null
     */
Henning Leutz's avatar
Henning Leutz committed
    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
     */
Henning Leutz's avatar
Henning Leutz committed
    public function replaceArticle(Article $Article, int $index)
    {
        $this->articles[$index] = $Article;
    }

    /**
     * Clears the list
     */
    public function clear()
    {
        $this->articles = [];
     * Return the length of the list
     * @return int
Henning Leutz's avatar
Henning Leutz committed
    public function count(): int
Henning Leutz's avatar
Henning Leutz committed
        return count($this->articles);

    //region Price Factors

    /**
     * Import a price factor list
     *
     * @param QUI\ERP\Accounting\PriceFactors\FactorList $PriceFactors
    public function importPriceFactors(QUI\ERP\Accounting\PriceFactors\FactorList $PriceFactors)
    {
        $this->PriceFactors = $PriceFactors;
    }

    /**
     * @param \QUI\ERP\Accounting\PriceFactors\Factor|QUI\ERP\Products\Utils\PriceFactor $PriceFactor
     * @return void
     *
     * @throws \QUI\ERP\Exception
     */
    public function addPriceFactor($PriceFactor)
    {
        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);
            }

            $PriceFactor->setVat($vat);

            $brutto = $netto * ((100 + $vat) / 100);
            $brutto = round($brutto, $precision);

            if ($isNetto) {
                $PriceFactor->setSum($netto);
            } else {
                $PriceFactor->setSum($brutto);
            }

            $PriceFactor = new QUI\ERP\Accounting\PriceFactors\Factor($PriceFactor->toArray());
        }

        $this->PriceFactors->addFactor($PriceFactor);
        $this->recalculate();
    }


    //region order

    /**
     * @param QUI\ERP\Order\AbstractOrder $Order
     */
    public function setOrder(QUI\ERP\Order\AbstractOrder $Order)
    {
        $this->Order = $Order;
    }

    /**
     * @return QUI\ERP\Order\AbstractOrder|null
     */
Henning Leutz's avatar
Henning Leutz committed
    public function getOrder(): ?QUI\ERP\Order\AbstractOrder
    {
        return $this->Order;
    }

    //endregion