Newer
Older
<?php
/**
* This file contains QUI\ERP\Order\AbstractOrder
*/
namespace QUI\ERP\Order;
use QUI;
use QUI\ERP\Accounting\ArticleList;
use QUI\ERP\Accounting\Payments\Payments;
use QUI\ERP\Accounting\Payments\Transactions\Handler as TransactionHandler;
use QUI\ERP\Accounting\Payments\Transactions\Transaction;
use QUI\ERP\ErpEntityInterface;
use QUI\ERP\ErpTransactionsInterface;
use QUI\ERP\Order\ProcessingStatus\Handler as ProcessingHandler;
use QUI\ERP\Order\ProcessingStatus\Status;
use QUI\ERP\Order\ProcessingStatus\StatusUnknown;
use QUI\ERP\Shipping\ShippingStatus\Handler as ShippingStatusHandler;
use QUI\ERP\User;
use QUI\ExceptionStack;
use function date;
use function is_array;
use function is_numeric;
use function is_string;
use function json_decode;
use function json_encode;
use function preg_replace;
use function round;
use function strip_tags;
use function strtotime;
use function time;
/**
* Class AbstractOrder
*
* Main parent class for order classes
* - Order
* - OrderProcess
*
* @package QUI\ERP\Order
*/
abstract class AbstractOrder extends QUI\QDOM implements OrderInterface, ErpEntityInterface, ErpTransactionsInterface

Patrick Müller
committed
/**
* Article types
*/
const ARTICLE_TYPE_PHYSICAL = 1;
const ARTICLE_TYPE_DIGITAL = 2;
const ARTICLE_TYPE_MIXED = 3;

Patrick Müller
committed
protected string $idStr = '';
/**
* @var ?string
*/
protected string $globalProcessId;
* @var Status|StatusUnknown|null
protected Status | StatusUnknown | null $Status = null;
/**
* @var null|QUI\ERP\Shipping\ShippingStatus\Status
*/
protected ?QUI\ERP\Shipping\ShippingStatus\Status $ShippingStatus = null;
protected string | int | bool | null $invoiceId = false;
protected null | int | string $customerId;
* @var integer|string
protected int | string $cUser;
protected ?QUI\ERP\Comments $FrontendMessage = null;
// payments
/**
/**
protected ?string $paymentMethod;
protected ?QUI\ERP\Currency\Currency $Currency = null;
//shipping
/**
* @var integer|null
*/
{
$needles = Factory::getInstance()->getOrderConstructNeedles();
foreach ($needles as $needle) {
if (!isset($data[$needle]) && $data[$needle] !== null) {
throw new Exception([
'quiqqer/order',
'exception.order.construct.needle.missing',
['needle' => $needle]
]);
$this->id = (int)$data['id'];
$this->hash = $data['hash'];
$this->cUser = $data['c_user'];
if (!empty($data['global_process_id'])) {
$this->globalProcessId = $data['global_process_id'];
} else {
$this->globalProcessId = $this->hash;
if (!empty($data['id_str'])) {
$this->idStr = $data['id_str'];
} else {
$this->idStr = $this->idPrefix . $this->id;
}
try {
QUI::getEvents()->fireEvent('quiqqerOrderInit', [$this]);
} catch (\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());
}
}
/**
* Set the db data to the order object
*
* @param array $data
protected function setDataBaseData(array $data): void
$this->addressDelivery = json_decode($data['addressDelivery'] ?? 'null', true);
$this->addressInvoice = json_decode($data['addressInvoice'] ?? 'null', true);
$this->data = json_decode($data['data'] ?? 'null', true);

Henning Leutz
committed
if (isset($data['status'])) {
$this->status = $data['status'];
}
if (isset($data['project_name'])) {
$this->setAttribute('project_name', $data['project_name']);
}
if (!empty($data['order_process_id'])) {
$this->setAttribute('order_process_id', $data['order_process_id']);
}
$this->customerId = $data['customerId'];
if (isset($data['customer'])) {
$this->customer = json_decode($data['customer'], true);
if (!isset($this->customer['id'])) {
$this->customer['id'] = $this->customerId;
$customerData = $this->customer;
if (!isset($customerData['address'])) {
$customerData['address'] = $this->addressInvoice;
}
if (!isset($customerData['isCompany']) && isset($this->customer['company'])) {
$customerData['isCompany'] = !empty($this->customer['company']);
}
if (!isset($customerData['country']) && isset($customerData['address']['country'])) {
$customerData['country'] = $customerData['address']['country'];
}
$this->setCustomer($customerData);
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeRecursive($this->customer);
QUI\System\Log::addWarning($Exception->getMessage());
}
if (isset($this->addressInvoice['id']) && $this->addressInvoice['id'] >= 0) {
$this->Customer->setAddress($this->getInvoiceAddress());
} elseif (isset($customerData['address']['id']) && $customerData['address']['id']) {
$this->Customer->setAddress($this->getInvoiceAddress());
} elseif (isset($customerData['quiqqer.erp.address'])) {
try {
$User = QUI::getUsers()->get($this->Customer->getUUID());
$Address = $User->getAddress($customerData['quiqqer.erp.address']);
$this->Customer->setAddress($Address);
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
}
// currency
if (!empty($data['currency_data'])) {
$currency = json_decode($data['currency_data'], true);
if (is_string($currency)) {
$currency = json_decode($currency, true);
}
if ($currency && isset($currency['code'])) {
try {
$this->Currency = QUI\ERP\Currency\Handler::getCurrency($currency['code']);
} catch (QUI\Exception $Exception) {
QUI\System\Log::addDebug($Exception->getMessage());
}
}
}
if ($this->Currency === null) {
$this->Currency = QUI\ERP\Defaults::getCurrency();
}
$this->Articles->setCurrency($this->Currency);
$articles = json_decode($data['articles'], true);
if ($articles) {
try {
$this->Articles = new ArticleList($articles);
$this->Articles->setCurrency($this->Currency);
QUI\System\Log::addError($Exception->getMessage());
}
}
}
$Customer = $this->getCustomer();
$Customer->setAddress($this->getDeliveryAddress());
$this->Articles->setUser($Customer);
// comments
$this->Comments = new QUI\ERP\Comments();
if (isset($data['comments'])) {
$this->Comments = QUI\ERP\Comments::unserialize($data['comments']);
// history
$this->History = new QUI\ERP\Comments();
if (isset($data['history'])) {
$this->History = QUI\ERP\Comments::unserialize($data['history']);
// frontend messages
$this->FrontendMessage = new QUI\ERP\Comments();
if (isset($data['frontendMessages'])) {
$this->FrontendMessage = QUI\ERP\Comments::unserialize($data['frontendMessages']);
}
// status mail
$this->StatusMails = new QUI\ERP\Comments();
if (isset($data['status_mails'])) {
$this->StatusMails = QUI\ERP\Comments::unserialize($data['status_mails']);
}
// payment
$this->successful = (int)$data['successful'];
if ($data['paid_data'] === null) {
$data['paid_data'] = '';
}
$this->setAttributes([
'paid_status' => (int)$data['paid_status'],
'paid_data' => json_decode($data['paid_data'], true),
'paid_date' => $data['paid_date'],
'temporary_invoice_id' => $data['temporary_invoice_id'],
if (isset($data['payment_data'])) {
$paymentData = QUI\Security\Encryption::decrypt($data['payment_data']);
if (is_array($paymentData)) {
$this->paymentData = $paymentData;
}
$this->shippingId = (int)$data['shipping_id'];
// validate shipping
// @phpstan-ignore-next-line
$this->validateShipping($this->getShipping());
} catch (QUI\Exception) {
try {
$this->Status = ProcessingHandler::getInstance()->getProcessingStatus($data['status']);
$this->status = (int)$data['status'];
} catch (QUI\ERP\Order\ProcessingStatus\Exception) {
// nothing
}
if (
QUI::getPackageManager()->isInstalled('quiqqer/shipping')
&& isset($data['shipping_status'])
&& class_exists('QUI\ERP\Shipping\ShippingStatus\Handler')
&& class_exists('QUI\ERP\Shipping\ShippingStatus\Exception')
) {
$this->ShippingStatus = ShippingStatusHandler::getInstance()->getShippingStatus(
$data['shipping_status']
);
} catch (QUI\ERP\Shipping\ShippingStatus\Exception $Exception) {
QUI\System\Log::addWarning($Exception->getMessage());
}
}
/**
* @param string $reason
* @param QUI\Interfaces\Users\User|null $PermissionUser
* @return ErpEntityInterface|null
*/
public function reversal(
string $reason = '',
null | QUI\Interfaces\Users\User $PermissionUser = null
): ?ErpEntityInterface {
$this->delete($PermissionUser);
return null;
}
* Set the successful status to the order
*
* @throws QUI\Exception
* @throws QUI\ExceptionStack
*/
public function setSuccessfulStatus(): void
{
if ($this->successful === 1) {
return;
}
$this->successful = 1;
try {
QUI::getEvents()->fireEvent('quiqqerOrderSuccessful', [$this]);
} catch (\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());
}
$this->addHistory(
QUI::getLocale()->get(
'quiqqer/order',
'order.history.set_successful'
)
);
/**
* Recalculate all article prices

Henning Leutz
committed
*
* @throws Basket\Exception
* @throws QUI\ERP\Exception
* @throws QUI\Exception
*/
public function recalculate($Basket = null): void
if ($this instanceof Order) {
$this->Articles->recalculate();
$this->save();
return;
}
if ($this instanceof OrderInProcess && $this->getOrderId()) {
// if an order exists for the order in process
// never recalculate it
return;
}
if ($this instanceof OrderInProcess && $this->isSuccessful()) {
// if the order is successful
// never recalculate it
return;
}
$Customer = $this->getCustomer();
$Basket = new QUI\ERP\Order\Basket\BasketOrder($this->getUUID(), $Customer);
$ArticleList = new ArticleList();
$ArticleList->setUser($Customer);
$ArticleList->setCurrency($this->getCurrency());
$ProductCalc = QUI\ERP\Products\Utils\Calc::getInstance();
$ProductCalc->setUser($Customer);
$Products->setUser($Customer);
$Products->calc($ProductCalc);
$products = $Products->getProducts();
foreach ($products as $Product) {
try {
/* @var QUI\ERP\Order\Basket\Product $Product */
$ArticleList->addArticle($Product->toArticle(null, false));
} catch (QUI\Exception) {
// @todo hinweis an benutzer, das artikel nicht mit aufgenommen werden konnte
}
}
$Products->getPriceFactors()->clear();
QUI::getEvents()->fireEvent(
'quiqqerOrderBasketToOrder',
[
$Basket,
$this,
$Products
]
QUI::getEvents()->fireEvent(
'quiqqerOrderBasketToOrderEnd',
[
$Basket,
$this,
$Products
]
$ArticleList->importPriceFactors(
$Products->getPriceFactors()->toErpPriceFactorList()
);
$ArticleList->calc();
$this->Articles = $ArticleList;
$this->update(QUI::getUsers()->getSystemUser());

Henning Leutz
committed
/**
* Clears the complete order
*
* @param QUI\Interfaces\Users\User|null $PermissionUser - optional, permission user, default = session user
*/
abstract public function clear(null | QUI\Interfaces\Users\User $PermissionUser = null);

Henning Leutz
committed
/**
* Refresh the order data
* fetch the data from the database
*/
abstract public function refresh();
/**
* Updates the order
*
* @param QUI\Interfaces\Users\User|null $PermissionUser - optional, permission user, default = session user
abstract public function update(null | QUI\Interfaces\Users\User $PermissionUser = null);
/**
* Delete the order
*
* @param QUI\Interfaces\Users\User|null $PermissionUser - optional, permission user, default = session user
*/
abstract public function delete(null | QUI\Interfaces\Users\User $PermissionUser = null);
/**
* Is the order posted / submitted
*
* @return bool
*/
/**
* Return the order as an array
*
* @return array
*/
$shippingStatus = false;

Henning Leutz
committed
$articles = $this->getArticles()->toArray();
$Payment = $this->getPayment();
$ProcessingStatus = $this->getProcessingStatus();
if ($Payment) {
$paymentId = $Payment->getId();
}
if ($ProcessingStatus) {
$status = $ProcessingStatus->getId();

Henning Leutz
committed
}
try {
$paidStatus = $this->getPaidStatusInformation();
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
if (class_exists('QUI\ERP\Shipping\ShippingStatus\Status') && $this->getShippingStatus()) {
$shippingStatus = $this->getShippingStatus()->getId();
}
if (class_exists('QUI\ERP\Shipping\Types\ShippingEntry') && $this->getShipping()) {
$shipping = $this->getShipping()->getId();
}
'uuid' => $this->getUUID(),
'hash' => $this->hash, // @deprecated
'entityType' => $this->getType(),
'globalProcessId' => $this->getGlobalProcessId(),
'prefixedId' => $this->getPrefixedNumber(),
'prefixedNumber' => $this->getPrefixedNumber(),
'cDate' => $this->cDate,
'cUser' => $this->cUser,
'cUsername' => $this->getCreateUser()->getName(),
'data' => $this->data,
'customerId' => $this->customerId,
'customer' => $this->getCustomer()->getAttributes(),
'comments' => $this->getComments()->toArray(),
'statusMails' => $this->getStatusMails()->toArray(),
'project_name' => $this->getAttribute('project_name'),
'articles' => $articles,
'hasDeliveryAddress' => $this->hasDeliveryAddress(),
'addressDelivery' => $this->getDeliveryAddress()->getAttributes(),
'addressInvoice' => $this->getInvoiceAddress()->getAttributes(),
'paymentId' => $paymentId,
'status' => $status,
'paidStatus' => $paidStatus,
'shippingStatus' => $shippingStatus,
'shipping' => $shipping,
'shippingTracking' => $this->getDataEntry('shippingTracking'),
'shippingConfirmation' => $this->getDataEntry('shippingConfirmation')
public function getIdPrefix(): string
{
if ($this->idPrefix !== null) {
return $this->idPrefix;
}
return QUI\ERP\Order\Utils\Utils::getOrderPrefix();
}
/**
* Return the real order id for the customer
*
* @return string
* @deprecated use getPrefixedNumber())
{
return $this->getPrefixedNumber();
}
/**
* @return string
*/
public function getPrefixedNumber(): string
/**
* Return the order id
* -> alias for getId(), this method is used in the calc classes
*
* @return integer
*/
{
return $this->getId();
}
public function getGlobalProcessId(): string
{
return $this->globalProcessId;
}
/**
* @return QUI\ERP\Accounting\Calculations

Henning Leutz
committed
*
* @throws QUI\ERP\Exception

Henning Leutz
committed
* @throws QUI\Exception
public function getPriceCalculation(): QUI\ERP\Accounting\Calculations
{
$this->Articles->calc();
return new QUI\ERP\Accounting\Calculations(
$this->Articles->getCalculations(),
$this->Articles->getArticles()
);
/**
* Is the order successful
* -> Ist der Bestellablauf erfolgreich abgeschlossen
*
* @return int
*/

Patrick Müller
committed
* OrderProcess was successful and payment process was successful

Patrick Müller
committed
try {
if (!$this->getPayment()) {
return false;
}
$isApproved = $this->getPayment()->getPaymentType()->isApproved($this->getUUID());
$isSuccessful = $this->isSuccessful();
return $isApproved && $isSuccessful;

Patrick Müller
committed
} catch (\Exception $Exception) {
QUI\System\Log::writeException($Exception);

Patrick Müller
committed
return false;
}
/**
* @return string
*/
public function getInvoiceType(): string
{
try {
return $this->getInvoice()->getType();
} catch (QUI\Exception) {
public function getInvoiceAddress(): QUI\ERP\Address
return new QUI\ERP\Address($this->addressInvoice, $this->getCustomer());
public function getDeliveryAddress(): QUI\ERP\Address
$delivery = $this->addressDelivery;
if (isset($delivery['id']) && $delivery['id'] === -1) { // quiqqer/order#156
return $this->getInvoiceAddress();
}
// quiqqer/order#156
// cleanup, to check the delivery address
if (is_array($delivery)) {
$delivery = array_filter($delivery);
}
if (isset($delivery['id'])) {
unset($delivery['id']);
}
if (empty($delivery)) {
return $this->getInvoiceAddress();
}
return new QUI\ERP\Address($this->addressDelivery, $this->getCustomer());
}
/**
* Return the order articles list
*
* @return ArticleList
*/

Henning Leutz
committed
if (!$this->Articles) {
$this->Articles = new ArticleList();
}
$this->Articles->setOrder($this);
$this->Articles->setUser($this->getCustomer());
$this->Articles->setCurrency($this->getCurrency());
/**
* Return the order create date
*
/**
* Return the order create date
*
* @return QUI\Interfaces\Users\User|null
public function getCreateUser(): ?QUI\Interfaces\Users\User
{
try {
return QUI::getUsers()->get($this->cUser);
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
return QUI::getUsers()->getSystemUser();
}
/**
* Return extra data array
*
* @return array
*/
/**
* Return a data entry
*
* @param string $key
* @return mixed|null
*/
public function getDataEntry(string $key): mixed
{
if (isset($this->data[$key])) {
return $this->data[$key];
}
return null;
}
/**
* @return string
* @deprecated use getUUID()
*/
public function getHash(): string
{
return $this->getUUID();
}
/**
* Return the hash
*
* @return string
*/
public function getUUID(): string
* Return the customer of the order
*
$Nobody = QUI\ERP\User::convertUserToErpUser(QUI::getUsers()->getNobody());
if (!$this->customerId && !$this->Customer) {
return $Nobody;
}
if ($this->Customer) {
$Address = $this->Customer->getStandardAddress();
if (!$Address->getUUID()) {
$this->Customer->setAddress(
new QUI\ERP\Address($this->addressInvoice, $this->Customer)
);
}
return $this->Customer;
}