Skip to content
Code-Schnipsel Gruppen Projekte
Invoice.php 55,7 KiB
Newer Older
  • Learn to ignore specific revisions
  • Henning Leutz's avatar
    Henning Leutz committed
    <?php
    
    
    /**
     * This file contains QUI\ERP\Accounting\Invoice\Invoice
     */
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    namespace QUI\ERP\Accounting\Invoice;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    use IntlDateFormatter;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI;
    
    use QUI\ERP\Accounting\ArticleListUnique;
    
    use QUI\ERP\Accounting\Calculations;
    
    use QUI\ERP\Accounting\Invoice\Utils\Invoice as InvoiceUtils;
    
    use QUI\ERP\Accounting\Payments\Transactions\Transaction;
    
    use QUI\ERP\Address as ErpAddress;
    use QUI\ERP\Exception;
    
    use QUI\ERP\Money\Price;
    
    use QUI\ERP\Output\Output as ERPOutput;
    
    use QUI\ERP\Shipping\Api\ShippingInterface;
    use QUI\ExceptionStack;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use QUI\Interfaces\Users\User;
    
    use QUI\ERP\ErpEntityInterface;
    use QUI\ERP\ErpTransactionsInterface;
    use QUI\ERP\ErpCopyInterface;
    
    use QUI\Permissions\Permission;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function array_key_exists;
    use function class_exists;
    use function date;
    use function is_array;
    
    use function is_numeric;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function is_string;
    use function json_decode;
    use function json_encode;
    
    use function strip_tags;
    
    Henning Leutz's avatar
    Henning Leutz committed
    use function strtotime;
    use function time;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
    /**
     * Class Invoice
    
    Henning Leutz's avatar
    Henning Leutz committed
     * - Invoice class
    
     * - This class present a posted invoice
    
    Henning Leutz's avatar
    Henning Leutz committed
     *
     * @package QUI\ERP\Accounting\Invoice
     */
    
    class Invoice extends QUI\QDOM implements ErpEntityInterface, ErpTransactionsInterface, ErpCopyInterface
    
    Henning Leutz's avatar
    Henning Leutz committed
    {
    
        use QUI\ERP\ErpEntityCustomerFiles;
    
    
        const DUNNING_LEVEL_OPEN = 0; // No Dunning -> Keine Mahnung
        const DUNNING_LEVEL_REMIND = 1; // Payment reminding -> Zahlungserinnerung
        const DUNNING_LEVEL_DUNNING = 2; // Dunning -> Erste Mahnung
        const DUNNING_LEVEL_DUNNING2 = 3; // Second dunning -> Zweite Mahnung
    
        const DUNNING_LEVEL_COLLECTION = 4; // Collection -> Inkasso
    
    
        /**
         * Invoice type
         *
         * @var int
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        protected int $type;
    
        /**
         * @var string
         */
    
        protected mixed $prefix;
    
    Henning Leutz's avatar
    Henning Leutz committed
        protected int $id;
    
        /**
         * @var string
         */
        protected string $id_with_prefix = '';
    
    
        protected mixed $globalProcessId;
    
        protected array $data = [];
    
        /**
         * variable data for developers
         *
         * @var array
         */
    
        protected array $customData = [];
    
        /**
         * @var array
         */
    
        protected array $paymentData = [];
    
        protected ShippingInterface|null $Shipping = null;
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * Invoice constructor.
         *
         * @param $id
         * @param Handler $Handler
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
    
         * @throws QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
        public function __construct($id, Handler $Handler)
        {
    
            $invoiceData = $Handler->getInvoiceData($id);
            $this->setAttributes($invoiceData);
    
            $this->prefix = $this->getAttribute('id_prefix');
    
            if ($this->prefix === false) {
                $this->prefix = Settings::getInstance()->getInvoicePrefix();
            }
    
    
            $this->id = (int)$invoiceData['id'];
    
            $this->type = QUI\ERP\Constants::TYPE_INVOICE;
    
            if (!empty($invoiceData['id_with_prefix'])) {
                $this->id_with_prefix = $invoiceData['id_with_prefix'];
            } else {
                $this->id_with_prefix = $this->prefix . $this->id;
            }
    
    
            switch ((int)$this->getAttribute('type')) {
    
                case QUI\ERP\Constants::TYPE_INVOICE:
                case QUI\ERP\Constants::TYPE_INVOICE_TEMPORARY:
                case QUI\ERP\Constants::TYPE_INVOICE_CREDIT_NOTE:
                case QUI\ERP\Constants::TYPE_INVOICE_REVERSAL:
                case QUI\ERP\Constants::TYPE_INVOICE_CANCEL:
    
                    $this->type = (int)$this->getAttribute('type');
                    break;
            }
    
    
            if ($this->getAttribute('data')) {
    
                $this->data = json_decode($this->getAttribute('data'), true) ?? [];
    
            if ($this->getAttribute('custom_data')) {
    
                $this->customData = json_decode($this->getAttribute('custom_data'), true) ?? [];
    
            // fallback customer files
            if (!empty($this->data['customer_files']) && empty($this->customData['customer_files'])) {
                $this->customData['customer_files'] = $this->data['customer_files'];
            }
    
    
            if ($this->getAttribute('global_process_id')) {
                $this->globalProcessId = $this->getAttribute('global_process_id');
            }
    
    
            // invoice payment data
    
            if ($this->getAttribute('payment_data')) {
                $paymentData = QUI\Security\Encryption::decrypt($this->getAttribute('payment_data'));
    
    Henning Leutz's avatar
    Henning Leutz committed
                $paymentData = json_decode($paymentData, true);
    
                $this->paymentData = $paymentData ?? [];
    
    
            // shipping
            if ($this->getAttribute('shipping_id')) {
                $shippingData = $this->getAttribute('shipping_data');
    
    Henning Leutz's avatar
    Henning Leutz committed
                $shippingData = json_decode($shippingData, true);
    
                if (class_exists('QUI\ERP\Shipping\Types\ShippingUnique')) {
    
                    $this->Shipping = new QUI\ERP\Shipping\Types\ShippingUnique($shippingData);
                }
            }
    
    
    
            // consider contact person in address
    
            if (
                !empty($this->getAttribute('invoice_address')) &&
    
                !empty($this->getAttribute('contact_person'))
            ) {
                $invoiceAddress = $this->getAttribute('invoice_address');
    
    Henning Leutz's avatar
    Henning Leutz committed
                $invoiceAddress = json_decode($invoiceAddress, true);
    
    
                $invoiceAddress['contactPerson'] = $this->getAttribute('contact_person');
    
    Henning Leutz's avatar
    Henning Leutz committed
                $this->setAttribute('invoice_address', json_encode($invoiceAddress));
    
        }
    
        /**
         * Return the invoice id
    
         * (Rechnungs-ID)
    
         * @return int
         */
        public function getId(): int
        {
            return $this->id;
        }
    
        /**
    
         * @return string
    
         * @deprecated use getPrefixedNumber()
    
        public function getPrefixedId(): string
    
            return $this->getPrefixedNumber();
    
         * Rechnungsnummer
         *
         * @return string
         */
        public function getPrefixedNumber(): string
        {
            return $this->id_with_prefix;
        }
    
        /**
         * alias for getUUID()
    
         * (Vorgangsnummer)
         *
         * @return string
    
         * @deprecated use getUUID()
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getHash(): string
    
        {
            return $this->getUUID();
        }
    
        /**
         * Return the uuid of the invoice
         * (Vorgangsnummer)
         *
         * @return string
         */
        public function getUUID(): string
    
        {
            return $this->getAttribute('hash');
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getGlobalProcessId(): string
    
        /**
         * Returns only the integer id
         *
         * @return int
    
         * @deprecated use getId()
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCleanId(): int
    
            return $this->getId();
    
        /**
         * Return the invoice view
         *
         * @return InvoiceView
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @throws \QUI\ERP\Accounting\Invoice\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getView(): InvoiceView
    
        {
            return new InvoiceView($this);
        }
    
        /**
         * Return the unique article list
         *
         * @return ArticleListUnique
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @throws QUI\ERP\Exception|QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getArticles(): ArticleListUnique
    
            $articles = $this->getAttribute('articles');
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_string($articles)) {
                $articles = json_decode($articles, true);
    
            $List = new ArticleListUnique($articles, $this->getCustomer());
    
            $List->setLocale($this->getCustomer()->getLocale());
    
    
    
            // accounting currency, if exists
            $accountingCurrencyData = $this->getCustomDataEntry('accountingCurrencyData');
    
            try {
                if ($accountingCurrencyData) {
                    $List->setExchangeCurrency(
                        new QUI\ERP\Currency\Currency(
                            $accountingCurrencyData['accountingCurrency']
                        )
                    );
    
                    $List->setExchangeRate($accountingCurrencyData['rate']);
                }
    
        /**
         * Return the invoice currency
         *
         * @return QUI\ERP\Currency\Currency
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCurrency(): QUI\ERP\Currency\Currency
    
        {
            $currency = $this->getAttribute('currency_data');
    
            if (!$currency) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return QUI\ERP\Defaults::getCurrency();
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_string($currency)) {
                $currency = json_decode($currency, true);
    
            }
    
            if (!$currency || !isset($currency['code'])) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                return QUI\ERP\Defaults::getCurrency();
    
            $Currency = QUI\ERP\Currency\Handler::getCurrency($currency['code']);
    
            if (isset($currency['rate'])) {
                $Currency->setExchangeRate($currency['rate']);
            }
    
            return $Currency;
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
    
         * @throws QUI\ERP\Exception|QUI\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCustomer(): QUI\ERP\User
    
        {
            $invoiceAddress = $this->getAttribute('invoice_address');
    
            $customerData = $this->getAttribute('customer_data');
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_string($customerData)) {
                $customerData = json_decode($customerData, true);
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_string($invoiceAddress)) {
                $invoiceAddress = json_decode($invoiceAddress, true);
    
            }
    
            $userData = $customerData;
    
            if (!isset($userData['isCompany'])) {
                $userData['isCompany'] = false;
    
                if (isset($invoiceAddress['company'])) {
                    $userData['isCompany'] = true;
                }
            }
    
            $userData['address'] = $invoiceAddress;
    
    
            if (!isset($userData['id'])) {
                $userData['id'] = $this->getAttribute('customer_id');
            }
    
    
            // Country fallback
            if (empty($userData['country'])) {
                if (!empty($invoiceAddress['country'])) {
                    $userData['country'] = $invoiceAddress['country'];
                } else {
                    $userData['country'] = QUI\ERP\Defaults::getCountry()->getCode();
                }
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUI\ERP\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getEditor(): QUI\ERP\User
    
                'country' => '',
                'username' => '',
    
                'lastname' => $this->getAttribute('editor_name'),
                'lang' => '',
    
                'isCompany' => '',
    
                'isNetto' => ''
    
            ];
    
            if (is_numeric($this->getAttribute('editor_id'))) {
                $params['id'] = $this->getAttribute('editor_id');
            }
    
            if (is_string($this->getAttribute('editor_id'))) {
                $params['uuid'] = $this->getAttribute('editor_id');
            }
    
            return new QUI\ERP\User($params);
    
        /**
         * Return the payment paid status information
         * - How many has already been paid
         * - How many must be paid
         *
         * @return array
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getPaidStatusInformation(): array
    
            $oldStatus = $this->getAttribute('paid_status');
    
    
            QUI\ERP\Accounting\Calc::calculatePayments($this);
    
    Henning Leutz's avatar
    Henning Leutz committed
            // the status is another as canceled, to we must update the invoice data
    
            if ($this->getAttribute('paid_status') !== $oldStatus) {
                $this->calculatePayments();
            }
    
    
            if ($this->getInvoiceType() === QUI\ERP\Constants::TYPE_INVOICE_STORNO) {
    
                //$this->setAttribute('paid_status', QUI\ERP\Constants::PAYMENT_STATUS_CANCELED);
    
    Henning Leutz's avatar
    Henning Leutz committed
            return [
    
                'paidData' => $this->getAttribute('paid_data'),
                'paidDate' => $this->getAttribute('paid_date'),
    
                'paid' => $this->getAttribute('paid'),
                'toPay' => $this->getAttribute('toPay')
    
    Henning Leutz's avatar
    Henning Leutz committed
            ];
    
        /**
         * Return an entry in the payment data (decrypted)
         *
         * @param string $key
         * @return mixed|null
         */
    
        public function getPaymentDataEntry(string $key): mixed
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (array_key_exists($key, $this->paymentData)) {
    
        /**
         * ALIAS for $this->getPaymentDataEntry to be consistent with InvoiceTemporary.
         *
         * @param string $key
         * @return mixed|null
         */
    
        public function getPaymentData(string $key): mixed
    
            return $this->getPaymentDataEntry($key);
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
         * can a refund be made?
         *
         * @return bool
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function hasRefund(): bool
    
    Henning Leutz's avatar
    Henning Leutz committed
        {
            $transactions = InvoiceUtils::getTransactionsByInvoice($this);
    
            /* @var $Transaction Transaction */
            foreach ($transactions as $Transaction) {
                /* @var $Payment QUI\ERP\Accounting\Payments\Api\AbstractPayment */
                $Payment = $Transaction->getPayment();
    
    
    Henning Leutz's avatar
    Henning Leutz committed
                if ($Payment && $Payment->refundSupport()) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    return true;
                }
            }
    
            return false;
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function isPaid(): bool
    
            if ($this->getAttribute('toPay') === false) {
                try {
                    QUI\ERP\Accounting\Calc::calculatePayments($this);
                } catch (QUI\Exception $Exception) {
    
                    QUI\System\Log::writeDebugException($Exception);
    
            return $this->getAttribute('toPay') <= 0;
        }
    
    
        /**
         * Return the presentational payment method
         *
         * @return Payment
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getPayment(): Payment
    
        {
            $data = $this->getAttribute('payment_method_data');
    
            if (!$data) {
                QUI\System\Log::addCritical(
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'Error with invoice ' . $this->getUUID() . '. No payment Data available'
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (is_string($data)) {
                $data = json_decode($data, true);
    
        /**
         * Return the Shipping, if a shipping is set
         *
         * @return int|QUI\ERP\Shipping\Types\ShippingUnique|null
         */
    
        public function getShipping(): int|QUI\ERP\Shipping\Types\ShippingUnique|null
    
    Henning Leutz's avatar
    Henning Leutz committed
        /**
    
         * Return the invoice type
         *
         * - Handler::TYPE_INVOICE
         * - Handler::TYPE_INVOICE_TEMPORARY
         * - Handler::TYPE_INVOICE_CREDIT_NOTE
         * - Handler::TYPE_INVOICE_CANCEL
         *
         * @return int
    
    Henning Leutz's avatar
    Henning Leutz committed
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getInvoiceType(): int
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->type;
    
        }
    
        /**
         * Cancel the invoice
         * (Reversal, Storno, Cancel)
         *
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param string $reason
    
         * @param null|QUI\Interfaces\Users\User $PermissionUser
    
         * @return ?QUI\ERP\ErpEntityInterface
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\Permissions\Exception
    
        public function reversal(
            string $reason = '',
            QUI\Interfaces\Users\User $PermissionUser = null
        ): ?QUI\ERP\ErpEntityInterface {
    
    Henning Leutz's avatar
    Henning Leutz committed
            // is canceled / reversal possible?
    
            if (!Settings::getInstance()->get('invoice', 'storno')) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                // @todo implement credit note
                throw new Exception([
                    'quiqqer/invoice',
                    'exception.canceled.invoice.is.not.allowed'
                ]);
            }
    
    
            if ($PermissionUser === null) {
                $PermissionUser = QUI::getUserBySession();
            }
    
    
            Permission::checkPermission(
    
                'quiqqer.invoice.reversal',
                $PermissionUser
            );
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if (empty($reason)) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                throw new Exception([
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'quiqqer/invoice',
                    'exception.missing.reason.in.reversal'
    
    Henning Leutz's avatar
    Henning Leutz committed
                ]);
    
            // if invoice is parted paid, it could not be canceled
            $this->getPaidStatusInformation();
    
    
            if ($this->getAttribute('paid_status') == QUI\ERP\Constants::PAYMENT_STATUS_PART) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                throw new Exception([
    
                    'quiqqer/invoice',
                    'exception.parted.invoice.cant.be.canceled'
    
    Henning Leutz's avatar
    Henning Leutz committed
                ]);
    
            if ($this->getAttribute('paid_status') == QUI\ERP\Constants::PAYMENT_STATUS_CANCELED) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                throw new Exception([
    
                    'quiqqer/invoice',
                    'exception.canceled.invoice.cant.be.canceled'
    
    Henning Leutz's avatar
    Henning Leutz committed
                ]);
    
            $User = QUI::getUserBySession();
    
    
            QUI::getEvents()->fireEvent('quiqqerInvoiceReversal', [$this]);
    
            $this->addHistory(
                QUI::getLocale()->get(
                    'quiqqer/invoice',
    
                    'history.message.reversal',
    
                        'username' => $User->getName(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                        'uid' => $User->getUUID()
    
            $Reversal = $this->createReversal(
    
                QUI::getUsers()->getSystemUser(),
                $this->getGlobalProcessId()
            );
    
    
            //$CreditNote->setInvoiceType(Handler::TYPE_INVOICE_REVERSAL);
    
    
            // Cancellation invoice extra text
            $localeCode = QUI::getLocale()->getLocalesByLang(
                QUI::getLocale()->getCurrent()
            );
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Formatter = new IntlDateFormatter(
    
    Henning Leutz's avatar
    Henning Leutz committed
                IntlDateFormatter::SHORT,
                IntlDateFormatter::NONE
    
            );
    
            $currentDate = $this->getAttribute('date');
    
            if (!$currentDate) {
    
    Henning Leutz's avatar
    Henning Leutz committed
                $currentDate = time();
    
    Henning Leutz's avatar
    Henning Leutz committed
                $currentDate = strtotime($currentDate);
    
            }
    
            $message = $this->getCustomer()->getLocale()->get(
                'quiqqer/invoice',
                'message.invoice.cancellationInvoice.additionalInvoiceText',
                [
    
                    'id' => $this->getUUID(),
    
                    'date' => $Formatter->format($currentDate)
                ]
            );
    
            if (empty($message)) {
                $message = '';
            }
    
            // saving copy
    
            $Reversal->setAttribute('additional_invoice_text', $message);
    
            $Reversal->save(QUI::getUsers()->getSystemUser());
    
    
            try {
                Permission::checkPermission('quiqqer.invoice.canEditCancelInvoice', $PermissionUser);
    
            } catch (QUI\Exception) {
    
                $Reversal->post(QUI::getUsers()->getSystemUser());
    
            $this->addHistory(
                QUI::getLocale()->get(
                    'quiqqer/invoice',
                    'history.message.reversal.created',
    
                        'username' => $User->getName(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                        'uid' => $User->getUUID(),
    
                        'creditNoteId' => $Reversal->getUUID()
    
            // set the invoice status
    
            $this->type = QUI\ERP\Constants::TYPE_INVOICE_CANCEL;
    
            $Reversal = $Reversal->post(QUI::getUsers()->getSystemUser());
    
    Henning Leutz's avatar
    Henning Leutz committed
            $this->data['canceledId'] = $Reversal->getUUID();
    
            QUI::getDataBase()->update(
                Handler::getInstance()->invoiceTable(),
    
                    'type' => $this->type,
                    'data' => json_encode($this->data),
    
                    'paid_status' => QUI\ERP\Constants::PAYMENT_STATUS_CANCELED
    
    Henning Leutz's avatar
    Henning Leutz committed
                ],
    
    Henning Leutz's avatar
    Henning Leutz committed
                ['hash' => $this->getUUID()]
    
            $this->addComment($reason, QUI::getUsers()->getSystemUser());
    
    
            QUI::getEvents()->fireEvent(
    
                'quiqqerInvoiceReversalEnd',
    
                [$this, $Reversal]
    
         * Alias for reversal
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @param string $reason
         * @param null|QUI\Interfaces\Users\User $PermissionUser
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @return int|string - ID of the new
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\Permissions\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function cancellation(string $reason, QUI\Interfaces\Users\User $PermissionUser = null): int|string
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->reversal($reason, $PermissionUser)->getUUID();
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @param string $reason
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @param null|User $PermissionUser
         * @return int|string - ID of the new
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\Permissions\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function storno(string $reason, QUI\Interfaces\Users\User $PermissionUser = null): int|string
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->reversal($reason, $PermissionUser)->getUUID();
    
        }
    
        /**
         * Copy the invoice to a temporary invoice
         *
    
         * @param null|QUI\Interfaces\Users\User $PermissionUser
    
         * @param bool|string $globalProcessId
    
         * @return InvoiceTemporary
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\Permissions\Exception
    
        public function copy(
            QUI\Interfaces\Users\User $PermissionUser = null,
            bool|string $globalProcessId = false
        ): InvoiceTemporary {
    
            if ($PermissionUser === null) {
                $PermissionUser = QUI::getUserBySession();
            }
    
    
            Permission::checkPermission(
    
                'quiqqer.invoice.copy',
                $PermissionUser
            );
    
            $User = QUI::getUserBySession();
    
            $this->addHistory(
                QUI::getLocale()->get(
                    'quiqqer/invoice',
                    'history.message.copy',
    
                        'username' => $User->getName(),
    
                        'uid' => $User->getId()
    
            QUI::getEvents()->fireEvent('quiqqerInvoiceCopyBegin', [$this]);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Handler = Handler::getInstance();
            $Factory = Factory::getInstance();
    
            $New = $Factory->createInvoice($User);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $currentData = QUI::getDataBase()->fetch([
    
                'from' => $Handler->invoiceTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                'where' => [
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'hash' => $this->getUUID()
    
    Henning Leutz's avatar
    Henning Leutz committed
                ],
    
    Henning Leutz's avatar
    Henning Leutz committed
                'limit' => 1
    
    Henning Leutz's avatar
    Henning Leutz committed
            ]);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            $currentData = $currentData[0];
    
    
            QUI::getEvents()->fireEvent('quiqqerInvoiceCopy', [$this]);
    
            if (empty($globalProcessId)) {
    
                $globalProcessId = QUI\Utils\Uuid::get();
    
    Henning Leutz's avatar
    Henning Leutz committed
            // Invoice Address
            $invoiceAddressId = '';
    
            $invoiceAddress = '';
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            if ($this->getAttribute('invoice_address')) {
                try {
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $address = json_decode($this->getAttribute('invoice_address'), true);
    
    Henning Leutz's avatar
    Henning Leutz committed
                    $Address = new QUI\ERP\Address($address);
    
    
                    $invoiceAddressId = $Address->getUUID();
    
                    $invoiceAddress = $Address->toJSON();
    
    Henning Leutz's avatar
    Henning Leutz committed
                } catch (\Exception $Exception) {
                    QUI\System\Log::addDebug($Exception->getMessage());
                }
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            QUI::getDataBase()->update(
                $Handler->temporaryInvoiceTable(),
    
                    'global_process_id' => $globalProcessId,
    
                    'type' => QUI\ERP\Constants::TYPE_INVOICE_TEMPORARY,
    
                    'customer_id' => $currentData['customer_id'],
                    'contact_person' => $currentData['contact_person'],
                    'invoice_address_id' => $invoiceAddressId,
                    'invoice_address' => $invoiceAddress,
                    'delivery_address' => $currentData['delivery_address'],
                    'order_id' => $currentData['order_id'],
                    'project_name' => $currentData['project_name'],
                    'payment_method' => $currentData['payment_method'],
                    'payment_data' => '',
                    'payment_time' => $currentData['payment_time'],
                    'time_for_payment' => (int)Settings::getInstance()->get('invoice', 'time_for_payment'),
                    'paid_status' => QUI\ERP\Constants::PAYMENT_STATUS_OPEN,
                    'paid_date' => null,
                    'paid_data' => null,
                    'date' => date('Y-m-d H:i:s'),
                    'data' => $currentData['data'],
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'additional_invoice_text' => $currentData['additional_invoice_text'],
    
                    'articles' => $currentData['articles'],
                    'history' => '',
                    'comments' => '',
                    'customer_data' => $currentData['customer_data'],
                    'isbrutto' => $currentData['isbrutto'],
                    'currency_data' => $currentData['currency_data'],
                    'currency' => $currentData['currency'],
                    'nettosum' => $currentData['nettosum'],
                    'nettosubsum' => $currentData['nettosubsum'],
                    'subsum' => $currentData['subsum'],
                    'sum' => $currentData['sum'],
                    'vat_array' => $currentData['vat_array'],
                    'processing_status' => null
    
    Henning Leutz's avatar
    Henning Leutz committed
                ],
                ['id' => $New->getCleanId()]
    
            $NewTemporaryInvoice = $Handler->getTemporaryInvoice($New->getUUID());
    
            QUI::getEvents()->fireEvent('quiqqerInvoiceCopyEnd', [
                $this,
                $NewTemporaryInvoice
            ]);
    
    
            return $NewTemporaryInvoice;
    
         * Create a credit note, set the invoice to credit note
         * - Gutschrift
    
         *
         * @param null|QUI\Interfaces\Users\User $PermissionUser
    
         * @return InvoiceTemporary
    
    Henning Leutz's avatar
    Henning Leutz committed
         * @throws Exception
         * @throws QUI\Exception
         * @throws QUI\Permissions\Exception
    
        public function createCreditNote(
    
            QUI\Interfaces\Users\User $PermissionUser = null
    
        ): InvoiceTemporary {
    
            // a credit node cant create a credit note
    
            if ($this->getInvoiceType() === QUI\ERP\Constants::TYPE_INVOICE_CREDIT_NOTE) {
    
                throw new Exception([
                    'quiqqer/invoice',
                    'exception.credit.note.cant.create.credit.note'
                ]);
            }
    
    
            Permission::checkPermission(
    
                'quiqqer.invoice.createCreditNote',
                $PermissionUser
            );
    
    
            QUI::getEvents()->fireEvent(
                'quiqqerInvoiceCreateCreditNote',
    
    Henning Leutz's avatar
    Henning Leutz committed
                [$this]
    
            $Copy = $this->copy(QUI::getUsers()->getSystemUser(), $this->getGlobalProcessId());
    
            $articles = $Copy->getArticles()->getArticles();
    
            // change all prices
            $ArticleList = $Copy->getArticles();
            $ArticleList->clear();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $ArticleList->setCurrency($this->getCurrency());
    
            $priceKeyList = [
                'price',
                'basisPrice',
                'nettoPriceNotRounded',
                'sum',
                'nettoSum',
                'nettoSubSum',
                'nettoPrice',
                'nettoBasisPrice',
                'unitPrice',
            ];
    
    
            foreach ($articles as $Article) {
    
                $article = $Article->toArray();
    
                foreach ($priceKeyList as $priceKey) {
                    if (isset($article[$priceKey])) {
                        $article[$priceKey] = $article[$priceKey] * -1;
                    }
                }
    
                if (isset($article['calculated'])) {
                    foreach ($priceKeyList as $priceKey) {
                        if (isset($article['calculated'][$priceKey])) {
                            $article['calculated'][$priceKey] = $article['calculated'][$priceKey] * -1;
                        }
                    }
                }
    
                if (isset($article['calculated']['vatArray'])) {
                    $article['calculated']['vatArray']['sum'] = $article['calculated']['vatArray']['sum'] * -1;
                }
    
    
                $Clone = new QUI\ERP\Accounting\Article($article);
                $ArticleList->addArticle($Clone);
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $PriceFactors = $ArticleList->getPriceFactors();
    
            $Currency = $this->getCurrency();
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            /* @var $PriceFactor QUI\ERP\Accounting\PriceFactors\Factor */
            foreach ($PriceFactors as $PriceFactor) {
                $PriceFactor->setNettoSum($PriceFactor->getNettoSum() * -1);
                $PriceFactor->setSum($PriceFactor->getSum() * -1);
                $PriceFactor->setValue($PriceFactor->getValue() * -1);
    
                $PriceFactor->setNettoSumFormatted($Currency->format($PriceFactor->getNettoSum()));
                $PriceFactor->setSumFormatted($Currency->format($PriceFactor->getSum()));
                $PriceFactor->setValueText($Currency->format($PriceFactor->getValue()));
            }
    
    
            $Copy->addHistory(
    
    Henning Leutz's avatar
    Henning Leutz committed
                QUI::getLocale()->get('quiqqer/invoice', 'message.create.credit.from', [
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'invoiceParentId' => $this->getUUID(),
                    'invoiceId' => $this->getUUID()
    
    Henning Leutz's avatar
    Henning Leutz committed
                ])
    
            // credit note extra text
            $localeCode = QUI::getLocale()->getLocalesByLang(
                QUI::getLocale()->getCurrent()
            );
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Formatter = new IntlDateFormatter(
    
                $localeCode[0],
    
    Henning Leutz's avatar
    Henning Leutz committed
                IntlDateFormatter::SHORT,
                IntlDateFormatter::NONE
    
            );
    
            $currentDate = $this->getAttribute('date');