Newer
Older
<?php
/**
* This file contains QUI\ERP\Process
*/
namespace QUI\ERP;
use QUI;
use function array_filter;
use function array_map;
use function array_merge;
use function class_exists;
use function is_callable;
/**
* Class Process

Henning Leutz
committed
* - represents a complete erp process
*
* @package QUI\ERP
*/
class Process
{
/**
* this date determines when the global process ids start to work.
* also the relationships.
*/

Henning Leutz
committed
const PROCESS_ACTIVE_DATE = '2024-08-01 00:00:00';
/**
* @var string
*/
/**
* @var null|array
*/

Henning Leutz
committed
/**
* @var null|QUI\ERP\Comments
*/

Henning Leutz
committed
/**
* Process constructor.
*
* @param string $processId - the global process id
*/
{
$this->processId = $processId;
}
/**

Henning Leutz
committed
* Return the db table name
*

Henning Leutz
committed
* @return string
*/
{

Henning Leutz
committed
return QUI::getDBTableName('process');
}
public function getUUID(): string
{
return $this->processId;
}
/**
* Return all entities which are connected to this process
*
*/
public function getEntities(): array
{
$entities = array_merge(
$this->getInvoices(),
$this->getOrders(),
$this->getOffers(),
$this->getBookings(),
$this->getPurchasing(),
$this->getSalesOrders()
);
return array_filter($entities);
}
/**
* This method is designed to organize and group ERP transaction entities that implement the ErpTransactionsInterface.
* It filters entities such as invoices, invoice drafts, orders,
* and other related items to identify and group together entities that are interconnected.
*
* For instance, if an order generates an invoice, this method will group them together.
* The primary function is to categorize these ERP entities based on their relationships and associations,
* facilitating easier management and retrieval of related transactional data within the ERP system.
*
* @param callable|null $filterEntityTypes - own filter function
public function getGroupedRelatedTransactionEntities(?callable $filterEntityTypes = null): array
{
$entities = $this->getEntities();
$entities = array_filter($entities, function ($obj) {
return $obj instanceof ErpTransactionsInterface;
});
if (is_callable($filterEntityTypes)) {
$entities = array_filter($entities, $filterEntityTypes);
}
$groups = [];
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
// invoices into the groups
if (
class_exists('QUI\ERP\Accounting\Invoice\Invoice')
&& class_exists('QUI\ERP\Accounting\Invoice\InvoiceTemporary')
) {
foreach ($entities as $Entity) {
if (
!($Entity instanceof QUI\ERP\Accounting\Invoice\Invoice
|| $Entity instanceof QUI\ERP\Accounting\Invoice\InvoiceTemporary)
) {
continue;
}
$uuid = $Entity->getUUID();
$groups[$uuid][] = $Entity;
if (class_exists('QUI\ERP\Order\Handler') && $Entity->getAttribute('order_id')) {
try {
$groups[$uuid][] = QUI\ERP\Order\Handler::getInstance()->get(
$Entity->getAttribute('order_id')
);
} catch (QUI\Exception) {
}
}
if (class_exists('QUI\ERP\SalesOrders\SalesOrder')) {
$salesOrder = $Entity->getPaymentData('salesOrder');
if ($salesOrder) {
try {
$groups[$uuid][] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['hash']);
} catch (QUI\Exception) {
}
}
}
}
}
// not group
$notGroup = [];
$isInGroups = function (ErpEntityInterface $Entity) use ($groups) {
foreach ($groups as $group) {
foreach ($group as $EntityInstance) {
if ($Entity->getUUID() === $EntityInstance->getUUID()) {
return true;
}
}
}
return false;
};
foreach ($entities as $Entity) {
if (!$isInGroups($Entity)) {
$notGroup[] = $Entity;
}
}
// resulting
$entitiesArray = array_map(function ($Entity) {
return $Entity->toArray();
}, $entities);
$notGroup = array_map(function ($Entity) {
return $Entity->toArray();
}, $notGroup);
$grouped = [];
foreach ($groups as $key => $entries) {
foreach ($entries as $entity) {
$grouped[$key][] = $entity->toArray();
}
}
return [
'entities' => $entitiesArray,
'grouped' => $grouped,
'notGroup' => $notGroup
];
}

Henning Leutz
committed
//region messages

Henning Leutz
committed
/**
* Add a comment to the history for the complete process
*
* @param string $message
* @param bool|int $time - optional, unix timestamp

Henning Leutz
committed
*/
public function addHistory(string $message, bool|int $time = false): void

Henning Leutz
committed
{
$this->getHistory()->addComment($message, $time);
try {
QUI::getDataBase()->update(
$this->table(),
['history' => $this->getHistory()->toJSON()],
['id' => $this->processId]
);
} catch (\QUI\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());
}
}
/**

Henning Leutz
committed
* Return the history of the process
* This history only contains the process history
*
* If you want the complete history of all process objects, use getCompleteHistory()
*
* @return QUI\ERP\Comments
*/
{

Henning Leutz
committed
if ($this->History === null) {
$history = '';
'where' => [
'id' => $this->processId
],
'limit' => 1
if (isset($result[0]['history'])) {
$history = $result[0]['history'];
QUI::getDataBase()->insert($this->table(), [
'id' => $this->processId
]);
}
} catch (\QUI\Exception $Exception) {
QUI\System\Log::addError($Exception->getMessage());

Henning Leutz
committed
}
$this->History = QUI\ERP\Comments::unserialize($history);
}

Henning Leutz
committed
return $this->History;
}

Henning Leutz
committed
/**
* Return a complete history of all process objects

Henning Leutz
committed
*
* @return Comments
*/

Henning Leutz
committed
{
$History = $this->getHistory();
$this->parseInvoices($History);
$this->parseOffers($History);
$this->parseSalesOrders($History);
$this->parseTransactions($History);

Henning Leutz
committed
try {
QUI::getEvents()->fireEvent('quiqqerErpGetCompleteHistory', [$this, $this->processId]);
} catch (\Exception $exception) {
QUI\System\Log::addError($exception->getMessage());
}
try {
QUI::getEvents()->fireEvent('quiqqerErpProcessHistory', [$this, $this->processId]);
} catch (\Exception $exception) {
QUI\System\Log::addError($exception->getMessage());
}

Henning Leutz
committed
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
// filter comments
/**
* this date determines when the global process ids start to work.
* also the relationships.
*/
$processDate = strtotime(self::PROCESS_ACTIVE_DATE);
$comments = $History->toArray();
$comments = array_filter($comments, function ($comment) use ($processDate) {
$createDate = $comment['time'];
if ($createDate > $processDate) {
return true;
}
return false;
});
$History = QUI\ERP\Comments::unserialize($comments);
if ($History->isEmpty()) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.empty.info'),
strtotime(self::PROCESS_ACTIVE_DATE),
'quiqqer/erp',
'fa fa-info'
);
}

Henning Leutz
committed
return $History;
}
//endregion
//region invoice
protected function parseInvoices(Comments $History): void
{
$invoices = $this->getInvoices();
foreach ($invoices as $Invoice) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.invoice.created', [

Henning Leutz
committed
'hash' => $Invoice->getPrefixedNumber()
]),
strtotime($Invoice->getAttribute('date')),
'quiqqer/invoice',
'fa fa-file-text-o',
false,
);
$history = $Invoice->getHistory()->toArray();
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/invoice';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-file-text-o';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
/**
* Return if the process has invoices or not
*
* @return bool
*/
{
$invoices = $this->getInvoices();
foreach ($invoices as $Invoice) {
if ($Invoice instanceof QUI\ERP\Accounting\Invoice\Invoice) {
return true;
}
}
return false;
}
/**
* Return if the process has temporary invoices or not
*
* @return bool
*/
{
$invoices = $this->getInvoices();
foreach ($invoices as $Invoice) {
if ($Invoice instanceof QUI\ERP\Accounting\Invoice\InvoiceTemporary) {
return true;
}
}
return false;
}
/**

Henning Leutz
committed
* @return Accounting\Invoice\Invoice[]|Accounting\Invoice\InvoiceTemporary[]
*/
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/invoice')) {
return [];
}

Henning Leutz
committed
return QUI\ERP\Accounting\Invoice\Handler::getInstance()->getInvoicesByGlobalProcessId(
}
//endregion
//region order
protected function parseOrders(Comments $History): void
{
// orders
$orders = $this->getOrders();
foreach ($orders as $Order) {
$history = $Order->getHistory()->toArray();
$hasCreateMessage = false;
$createMessage = QUI::getLocale()->get('quiqqer/erp', 'process.history.order.created', [

Henning Leutz
committed
'hash' => $Order->getPrefixedNumber()
]);
foreach ($history as $entry) {
if ($entry['message'] === $createMessage) {
$hasCreateMessage = true;
break;
}
}
if ($hasCreateMessage === false) {
$History->addComment(
$createMessage,
strtotime($Order->getCreateDate()),
'quiqqer/order',
'fa fa-shopping-basket'
);
}
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/order';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-shopping-basket';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
/**
* @return bool
*/
{
return !($this->getOrder() === null);
}
/**

Henning Leutz
committed
* Return the first order of the process
*
*/
public function getOrder(): Order\OrderInProcess|Order\Order|null
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/order')) {
return null;
}
$OrderHandler = QUI\ERP\Order\Handler::getInstance();
try {
return $OrderHandler->getOrderByGlobalProcessId($this->processId);
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
try {
return $OrderHandler->getOrderByHash($this->processId);
} catch (QUI\Exception $Exception) {
QUI\System\Log::writeDebugException($Exception);
}
return null;
}

Henning Leutz
committed
/**
* Return all orders from the process
*

Henning Leutz
committed
*/
public function getOrders(): array

Henning Leutz
committed
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/order')) {
return [];
}

Henning Leutz
committed
return QUI\ERP\Order\Handler::getInstance()->getOrdersByGlobalProcessId($this->processId);

Henning Leutz
committed
return [];
}
}
//endregion
//region offers
protected function parseOffers(Comments $History): void
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/offers')) {
return;
}
// orders
$offers = $this->getOffers();
foreach ($offers as $Offer) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.offer.created', [
'hash' => $Offer->getHash()
]),
strtotime($Offer->getAttribute('date')),
'quiqqer/offer',
false,
$Offer->getHash()
);
$history = $Offer->getHistory()->toArray();
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/offer';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-regular fa-handshake';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
$entry['id'],
$Offer->getHash()
);
}
}
}
/**
* @return QUI\ERP\Accounting\Offers\Offer[]
*/
public function getOffers(): array
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/offers')) {
return [];
}
try {
$offers = QUI::getDatabase()->fetch([
'select' => 'id,hash,global_process_id,date',
'from' => QUI\ERP\Accounting\Offers\Handler::getInstance()->offersTable(),
'where_or' => [
'global_process_id' => $this->processId,
'hash' => $this->processId
]
]);
} catch (\Exception) {
$Offers = QUI\ERP\Accounting\Offers\Handler::getInstance();
foreach ($offers as $offer) {
try {
$result[] = $Offers->getOffer($offer['id']);
} catch (\Exception) {
}
}
// temporary
try {
$temporaryOffers = QUI::getDatabase()->fetch([
'select' => 'id,hash,global_process_id,date',
'from' => QUI\ERP\Accounting\Offers\Handler::getInstance()->temporaryOffersTable(),
'where_or' => [
'global_process_id' => $this->processId,
'hash' => $this->processId
]
]);
} catch (\Exception) {
$temporaryOffers = [];
}
foreach ($temporaryOffers as $temporaryOffer) {
try {
$result[] = $Offers->getTemporaryOffer($temporaryOffer['id']);
} catch (\Exception) {
}
}

Henning Leutz
committed
return $result;
//region booking
protected function parseBookings(Comments $History): void
{
// orders
$bookings = $this->getBookings();
foreach ($bookings as $Booking) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.booking.created', [

Henning Leutz
committed
'hash' => $Booking->getPrefixedNumber()
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
]),
$Booking->getCreateDate()->getTimestamp(),
'quiqqer/booking',
'fa fa-ticket',
false,
$Booking->getUuid()
);
$history = $Booking->getHistory()->toArray();
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/booking';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-ticket';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
$entry['id'],
$Booking->getUuid()
);
}
}
}
/**
* @return array
*/
public function getBookings(): array
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/booking')) {
return [];
}
if (!class_exists('QUI\ERP\Booking\Repository\BookingRepository')) {
return [];
}
if (!class_exists('QUI\ERP\Booking\Table')) {
return [];
}
try {
$bookings = QUI::getDatabase()->fetch([
'select' => 'uuid,globalProcessId,createDate',
'from' => QUI\ERP\Booking\Table::BOOKINGS->tableName(),
'where_or' => [
'globalProcessId' => $this->processId,
'uuid' => $this->processId
]
]);
} catch (\Exception) {
return [];
}
$result = [];
$BookingRepository = new QUI\ERP\Booking\Repository\BookingRepository();
foreach ($bookings as $booking) {
try {
$result[] = $BookingRepository->getByUuid($booking['uuid']);
} catch (\Exception) {
}
}

Henning Leutz
committed
return $result;
//region purchase / Einkauf
protected function parsePurchasing(Comments $History): void
{
// orders
$purchasing = $this->getPurchasing();
foreach ($purchasing as $Purchasing) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.purchasing.created', [
'hash' => $Purchasing->getHash()
]),
strtotime($Purchasing->getAttribute('c_date')),
'quiqqer/purchasing',
'fa fa-cart-arrow-down',
false,
$Purchasing->getHash()
);
$history = $Purchasing->getHistory()->toArray();
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/purchasing';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-cart-arrow-down';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
$entry['id'],
$Purchasing->getHash()
*/
public function getPurchasing(): array
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/purchasing')) {
return [];
}
if (!class_exists('QUI\ERP\Purchasing\Processes\PurchasingProcess')) {
return [];
}
if (!class_exists('QUI\ERP\Purchasing\Processes\Handler')) {
return [];
}
try {
$purchasing = QUI::getDatabase()->fetch([
'select' => 'id,hash,global_process_id,date',
'from' => QUI\ERP\Purchasing\Processes\Handler::getTablePurchasingProcesses(),
'where_or' => [
'global_process_id' => $this->processId,
'hash' => $this->processId
]
]);
} catch (\Exception) {
return [];
}
$result = [];
foreach ($purchasing as $process) {
try {
$result[] = QUI\ERP\Purchasing\Processes\Handler::getPurchasingProcess($process['id']);

Henning Leutz
committed
return $result;
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
//region sales orders / Aufträge
protected function parseSalesOrders(Comments $History): void
{
// orders
$salesOrders = $this->getSalesOrders();
foreach ($salesOrders as $SalesOrder) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.salesorders.created', [
'hash' => $SalesOrder->getHash()
]),
strtotime($SalesOrder->getAttribute('c_date')),
'quiqqer/salesorders',
'fa fa-suitcase',
false,
$SalesOrder->getHash()
);
$history = $SalesOrder->getHistory()->toArray();
foreach ($history as $entry) {
if (empty($entry['source'])) {
$entry['source'] = 'quiqqer/salesorders';
}
if (empty($entry['sourceIcon'])) {
$entry['sourceIcon'] = 'fa fa-suitcase';
}
$History->addComment(
$entry['message'],
$entry['time'],
$entry['source'],
$entry['sourceIcon'],
$entry['id'],
$SalesOrder->getHash()
);
}
}
}
/**
*/
public function getSalesOrders(): array
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/salesorders')) {
return [];
}
try {
$salesOrders = QUI::getDatabase()->fetch([
'select' => 'id,hash,global_process_id,date',
'from' => QUI\ERP\SalesOrders\Handler::getTableSalesOrders(),
'where_or' => [
'global_process_id' => $this->processId,
'hash' => $this->processId
]
]);
} catch (\Exception) {
return [];
}
$result = [];
foreach ($salesOrders as $salesOrder) {
try {
$result[] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['id']);
} catch (\Exception) {
}
}

Henning Leutz
committed
return $result;
//region transactions
protected function parseTransactions(Comments $History): void
{
// orders
$transactions = $this->getTransactions();
foreach ($transactions as $Transaction) {
$History->addComment(
QUI::getLocale()->get('quiqqer/erp', 'process.history.transaction.created', [
'hash' => $Transaction->getHash(),
'amount' => $Transaction->getAmountFormatted()
]),
strtotime($Transaction->getDate()),
'quiqqer/payment-transaction',
'fa fa-money',
false,
$Transaction->getHash()
);
}
}
/**
* @return bool
*/
{
$transactions = $this->getTransactions();
}
/**
* Return all related transactions
*
* @return QUI\ERP\Accounting\Payments\Transactions\Transaction[];
*/
{
if (!QUI::getPackageManager()->isInstalled('quiqqer/payment-transactions')) {
return [];
}
if ($this->transactions !== null) {
return $this->transactions;
}
$Transactions = QUI\ERP\Accounting\Payments\Transactions\Handler::getInstance();

Henning Leutz
committed
return $Transactions->getTransactionsByProcessId($this->processId);
}
//endregion
}