Skip to content
Code-Schnipsel Gruppen Projekte
Invoice.php 42,4 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;
    
    use QUI;
    
    use QUI\Permissions\Permission;
    
    use QUI\ERP\Accounting\ArticleListUnique;
    
    use QUI\ERP\Accounting\Payments\Transactions\Transaction;
    
    use QUI\ERP\Accounting\Invoice\Utils\Invoice as InvoiceUtils;
    
    use QUI\ERP\Output\Output as ERPOutput;
    
    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
    {
    
        /* @deprecated */
        const PAYMENT_STATUS_OPEN = QUI\ERP\Constants::PAYMENT_STATUS_OPEN;
    
        /* @deprecated */
        const PAYMENT_STATUS_PAID = QUI\ERP\Constants::PAYMENT_STATUS_PAID;
    
        /* @deprecated */
        const PAYMENT_STATUS_PART = QUI\ERP\Constants::PAYMENT_STATUS_PART;
    
        /* @deprecated */
        const PAYMENT_STATUS_ERROR = QUI\ERP\Constants::PAYMENT_STATUS_ERROR;
    
        /* @deprecated */
        const PAYMENT_STATUS_CANCELED = QUI\ERP\Constants::PAYMENT_STATUS_CANCELED;
    
        /* @deprecated */
        const PAYMENT_STATUS_DEBIT = QUI\ERP\Constants::PAYMENT_STATUS_DEBIT;
    
        //    const PAYMENT_STATUS_CANCEL = 3;
        //    const PAYMENT_STATUS_STORNO = 3; // Alias for cancel
        //    const PAYMENT_STATUS_CREATE_CREDIT = 5;
    
    
        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
         */
        protected $type;
    
    
        /**
         * @var string
         */
    
        protected $prefix;
    
    
        /**
         * @var int
         */
        protected $id;
    
    
        protected $data = [];
    
    
        /**
         * variable data for developers
         *
         * @var array
         */
        protected $customData = [];
    
    
        /**
         * @var array
         */
        protected $paymentData = [];
    
        /**
         * @var null|integer
         */
        protected $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)
        {
            $this->setAttributes($Handler->getInvoiceData($id));
    
            $this->prefix = $this->getAttribute('id_prefix');
    
            if ($this->prefix === false) {
                $this->prefix = Settings::getInstance()->getInvoicePrefix();
            }
    
    
            $this->id   = (int)\str_replace($this->prefix, '', $id);
    
            $this->type = Handler::TYPE_INVOICE;
    
    
            switch ((int)$this->getAttribute('type')) {
                case Handler::TYPE_INVOICE:
                case Handler::TYPE_INVOICE_TEMPORARY:
                case Handler::TYPE_INVOICE_CREDIT_NOTE:
                case Handler::TYPE_INVOICE_REVERSAL:
    
                    $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);
            }
    
    
            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'));
    
                $paymentData = \json_decode($paymentData, true);
    
                if (\is_array($paymentData)) {
    
                    $this->paymentData = $paymentData;
                }
            }
    
    
            // shipping
            if ($this->getAttribute('shipping_id')) {
                $shippingData = $this->getAttribute('shipping_data');
                $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');
                $invoiceAddress = \json_decode($invoiceAddress, true);
    
                $invoiceAddress['contactPerson'] = $this->getAttribute('contact_person');
                $this->setAttribute('invoice_address', \json_encode($invoiceAddress));
            }
    
        }
    
        /**
         * Return the invoice id
         *
         * @return string
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getId(): string
    
            return $this->prefix.$this->id;
    
        /**
         * Return the hash
         * (Vorgangsnummer)
         *
         * @return string
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getHash(): string
    
        {
            return $this->getAttribute('hash');
        }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getGlobalProcessId(): string
    
        /**
         * Returns only the integer id
         *
         * @return int
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCleanId(): int
    
            return (int)\str_replace($this->prefix, '', $this->getId());
    
        /**
         * Return the invoice view
         *
         * @return InvoiceView
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws 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
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getArticles(): ArticleListUnique
    
            $articles = $this->getAttribute('articles');
    
    
            if (\is_string($articles)) {
                $articles = \json_decode($articles, true);
    
            try {
                $articles['calculations']['currencyData'] = $this->getCurrency()->toArray();
            } catch (QUI\Exception $Exception) {
                QUI\System\Log::writeDebugException($Exception);
            }
    
    
            $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']);
                }
            } catch (QUI\Exception $Exception) {
            }
    
    
        /**
         * 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();
    
            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();
    
            }
    
            return QUI\ERP\Currency\Handler::getCurrency($currency['code']);
        }
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUI\ERP\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getCustomer(): QUI\ERP\User
    
        {
            $invoiceAddress = $this->getAttribute('invoice_address');
            $customerData   = $this->getAttribute('customer_data');
    
    
            if (\is_string($customerData)) {
                $customerData = \json_decode($customerData, true);
    
            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');
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUI\ERP\Exception
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getEditor(): QUI\ERP\User
    
    Henning Leutz's avatar
    Henning Leutz committed
            return new QUI\ERP\User([
    
    Henning Leutz's avatar
    Henning Leutz committed
                'id'        => $this->getAttribute('editor_id'),
    
    Henning Leutz's avatar
    Henning Leutz committed
                'lastname'  => $this->getAttribute('editor_name'),
    
                'isCompany' => '',
                'isNetto'   => ''
    
    Henning Leutz's avatar
    Henning Leutz committed
            ]);
    
        /**
         * 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);
    
            // the status is another as calced, to we must update the invoice data
            if ($this->getAttribute('paid_status') !== $oldStatus) {
                $this->calculatePayments();
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($this->getInvoiceType() === Handler::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
         */
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function getPaymentDataEntry(string $key)
    
            if (\array_key_exists($key, $this->paymentData)) {
    
        /**
         * ALIAS for $this->getPaymentDataEntry to be consistent with InvoiceTemporary.
         *
         * @param string $key
         * @return mixed|null
         */
    
    Patrick Müller's avatar
    Patrick Müller committed
        public function getPaymentData(string $key)
        {
    
            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();
    
                if ($Payment->refundSupport()) {
                    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(
                    'Error with invoice '.$this->getId().'. No payment Data available'
                );
    
                return new Payment([]);
            }
    
    
            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()
        {
            return $this->Shipping;
        }
    
    
    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
    
        }
    
        /**
         * Cancel the invoice
         * (Reversal, Storno, Cancel)
         *
    
    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 - 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 reversal(string $reason, $PermissionUser = null): int
    
    Henning Leutz's avatar
    Henning Leutz committed
            // is cancelation / 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(),
                        'uid'      => $User->getId()
    
            $CreditNote = $this->createCreditNote(
                QUI::getUsers()->getSystemUser(),
                $this->getGlobalProcessId()
            );
    
    
            $CreditNote->setInvoiceType(Handler::TYPE_INVOICE_REVERSAL);
    
    
            // Cancellation invoice extra text
            $localeCode = QUI::getLocale()->getLocalesByLang(
                QUI::getLocale()->getCurrent()
            );
    
            $Formatter = new \IntlDateFormatter(
                $localeCode[0],
                \IntlDateFormatter::SHORT,
                \IntlDateFormatter::NONE
            );
    
            $currentDate = $this->getAttribute('date');
    
            if (!$currentDate) {
                $currentDate = \time();
            } else {
                $currentDate = \strtotime($currentDate);
            }
    
            $message = $this->getCustomer()->getLocale()->get(
                'quiqqer/invoice',
                'message.invoice.cancellationInvoice.additionalInvoiceText',
                [
                    'id'   => $this->getId(),
                    'date' => $Formatter->format($currentDate)
                ]
            );
    
            if (empty($message)) {
                $message = '';
            }
    
            // saving copy
            $CreditNote->setAttribute('additional_invoice_text', $message);
    
    
            $CreditNote->save(QUI::getUsers()->getSystemUser());
    
    
            try {
                Permission::checkPermission('quiqqer.invoice.canEditCancelInvoice', $PermissionUser);
            } catch (QUI\Exception $Exception) {
                $CreditNote->post(QUI::getUsers()->getSystemUser());
            }
    
            $this->addHistory(
                QUI::getLocale()->get(
                    'quiqqer/invoice',
                    'history.message.reversal.created',
    
                        'username'     => $User->getName(),
                        'uid'          => $User->getId(),
                        'creditNoteId' => $CreditNote->getId()
    
            // set the invoice status
            $this->type = Handler::TYPE_INVOICE_CANCEL;
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $CreditNote = $CreditNote->post(QUI::getUsers()->getSystemUser());
    
            $this->data['canceledId'] = $CreditNote->getCleanId();
    
            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
                ],
                ['id' => $this->getCleanId()]
    
            $this->addComment($reason, QUI::getUsers()->getSystemUser());
    
    
            QUI::getEvents()->fireEvent(
    
                'quiqqerInvoiceReversalEnd',
    
    Henning Leutz's avatar
    Henning Leutz committed
                [$this]
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $CreditNote->getCleanId();
    
         * Alias for reversal
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @param string $reason
         * @param null|QUI\Interfaces\Users\User $PermissionUser
         * @return int - 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, $PermissionUser = null): int
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->reversal($reason, $PermissionUser);
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @param string $reason
         * @param null|QUI\Interfaces\Users\User $PermissionUser
         * @return int - 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, $PermissionUser = null): int
    
    Henning Leutz's avatar
    Henning Leutz committed
            return $this->reversal($reason, $PermissionUser);
    
        }
    
        /**
         * Copy the invoice to a temporary invoice
         *
    
         * @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
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function copy($PermissionUser = null, $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([
    
    Henning Leutz's avatar
    Henning Leutz committed
                'from'  => $Handler->invoiceTable(),
    
    Henning Leutz's avatar
    Henning Leutz committed
                'where' => [
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'id' => $this->getCleanId()
    
    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 = $this->getHash();
            }
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            // Invoice Address
            $invoiceAddressId = '';
            $invoiceAddress   = '';
    
            if ($this->getAttribute('invoice_address')) {
                try {
                    $address = \json_decode($this->getAttribute('invoice_address'), true);
                    $Address = new QUI\ERP\Address($address);
    
                    $invoiceAddressId = $Address->getId();
                    $invoiceAddress   = $Address->toJSON();
                } 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'                    => Handler::TYPE_INVOICE_TEMPORARY,
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'customer_id'             => $currentData['customer_id'],
    
                    'contact_person'          => $currentData['contact_person'],
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'invoice_address_id'      => $invoiceAddressId,
                    'invoice_address'         => $invoiceAddress,
    
    Henning Leutz's avatar
    Henning Leutz committed
                    '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,
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'date'                    => date('Y-m-d H:i:s'),
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'data'                    => $currentData['data'],
                    'additional_invoice_text' => $currentData['additional_invoice_text'],
                    'articles'                => $currentData['articles'],
    
                    'history'                 => '',
                    'comments'                => '',
    
    Henning Leutz's avatar
    Henning Leutz committed
                    'customer_data'           => $currentData['customer_data'],
                    'isbrutto'                => $currentData['isbrutto'],
                    'currency_data'           => $currentData['currency_data'],
    
                    'currency'                => $currentData['currency'],
    
    Henning Leutz's avatar
    Henning Leutz committed
                    '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->getId());
    
    
            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
    
    Henning Leutz's avatar
    Henning Leutz committed
        public function createCreditNote($PermissionUser = null, $globalProcessId = false): InvoiceTemporary
    
            // a credit node cant create a credit note
            if ($this->getInvoiceType() === Handler::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(), $globalProcessId);
    
            $articles = $Copy->getArticles()->getArticles();
    
            // change all prices
            $ArticleList = $Copy->getArticles();
            $ArticleList->clear();
    
    Henning Leutz's avatar
    Henning Leutz committed
            $ArticleList->setCurrency($this->getCurrency());
    
    
            foreach ($articles as $Article) {
                $article              = $Article->toArray();
                $article['unitPrice'] = $article['unitPrice'] * -1;
    
                $Clone = new QUI\ERP\Accounting\Article($article);
                $ArticleList->addArticle($Clone);
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $PriceFactors = $ArticleList->getPriceFactors();
            $Currency     = $this->getCurrency();
    
            /* @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->getId(),
                    'invoiceId'       => $this->getId()
    
    Henning Leutz's avatar
    Henning Leutz committed
                ])
    
            // credit note extra text
            $localeCode = QUI::getLocale()->getLocalesByLang(
                QUI::getLocale()->getCurrent()
            );
    
            $Formatter = new \IntlDateFormatter(
                $localeCode[0],
                \IntlDateFormatter::SHORT,
                \IntlDateFormatter::NONE
            );
    
            $currentDate = $this->getAttribute('date');
    
            if (!$currentDate) {
    
                $currentDate = \time();
    
                $currentDate = \strtotime($currentDate);
    
            $message = $this->getCustomer()->getLocale()->get(
    
                'quiqqer/invoice',
                'message.invoice.creditNote.additionalInvoiceText',
    
                    'id'   => $this->getId(),
                    'date' => $Formatter->format($currentDate)
    
            );
    
            $additionalText = $Copy->getAttribute('additional_invoice_text');
    
            if (!empty($additionalText)) {
                $additionalText .= '<br />';
            }
    
            $additionalText .= $message;
    
            // saving copy
            $Copy->setData('originalId', $this->getCleanId());
    
            $Copy->setData('originalIdPrefixed', $this->getId());
    
    
            $Copy->setAttribute('date', \date('Y-m-d H:i:s'));
    
            $Copy->setAttribute('additional_invoice_text', $additionalText);
    
    Henning Leutz's avatar
    Henning Leutz committed
            $Copy->setAttribute('currency_data', $this->getAttribute('currency_data'));
    
            $Copy->setInvoiceType(Handler::TYPE_INVOICE_CREDIT_NOTE);
    
    Henning Leutz's avatar
    Henning Leutz committed
    
            if ($this->getAttribute('invoice_address')) {
                try {
                    $address = \json_decode($this->getAttribute('invoice_address'), true);
                    $Address = new QUI\ERP\Address($address);
    
                    $invoiceAddressId = $Address->getId();
                    $invoiceAddress   = $Address->toJSON();
    
                    $Copy->setAttribute('invoice_address_id', $invoiceAddressId);
                    $Copy->setAttribute('invoice_address', $invoiceAddress);
                } catch (\Exception $Exception) {
                    QUI\System\Log::addDebug($Exception->getMessage());
                }
            }
    
    
            $Copy->save(QUI::getUsers()->getSystemUser());
    
    
            $this->addHistory(
    
    Henning Leutz's avatar
    Henning Leutz committed
                QUI::getLocale()->get('quiqqer/invoice', 'message.create.credit', [
    
                    'invoiceParentId' => $this->getId(),
                    'invoiceId'       => $Copy->getId()
    
    Henning Leutz's avatar
    Henning Leutz committed
                ])
    
            $CreditNote = Handler::getInstance()->getTemporaryInvoice($Copy->getId());
    
            QUI::getEvents()->fireEvent(
                'quiqqerInvoiceCreateCreditNoteEnd',
                [$this, $CreditNote]
            );
    
            return $CreditNote;
    
        /**
         * @param Transaction $Transaction
    
    Henning Leutz's avatar
    Henning Leutz committed
         *
         * @throws QUI\Exception
    
         */
        public function addTransaction(Transaction $Transaction)
        {
            QUI\ERP\Debug::getInstance()->log('Invoice:: add transaction');
    
            if ($this->getHash() !== $Transaction->getHash()) {
                return;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $currentPaidStatus = $this->getAttribute('paid_status');
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            $this->calculatePayments();
    
    
            if ($this->getInvoiceType() == Handler::TYPE_INVOICE_REVERSAL
                || $this->getInvoiceType() == Handler::TYPE_INVOICE_CANCEL
                || $this->getInvoiceType() == Handler::TYPE_INVOICE_CREDIT_NOTE
            ) {
                return;
            }
    
    
    Henning Leutz's avatar
    Henning Leutz committed
            if ($currentPaidStatus === $this->getAttribute('paid_status')
                && ($this->getAttribute('paid_status') == QUI\ERP\Constants::PAYMENT_STATUS_PAID ||
                    $this->getAttribute('paid_status') == QUI\ERP\Constants::PAYMENT_STATUS_CANCELED)
    
            ) {
                return;
            }
    
            QUI\ERP\Debug::getInstance()->log('Order:: add transaction start');
    
            $User     = QUI::getUserBySession();
            $paidData = $this->getAttribute('paid_data');
            $amount   = Price::validatePrice($Transaction->getAmount());
            $date     = $Transaction->getDate();
    
            QUI::getEvents()->fireEvent(