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';
protected string $processId;
protected ?array $transactions = null;
protected ?Comments $History = null;

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 = [];
// invoices into the groups
if (
class_exists('QUI\ERP\Accounting\Invoice\Invoice')
&& class_exists('QUI\ERP\Accounting\Invoice\InvoiceTemporary')
) {
foreach ($entities as $Entity) {
if (

Henning Leutz
committed
!($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\Handler')) {
$salesOrder = $Entity->getPaymentData('salesOrder');
if ($salesOrder) {
try {
$groups[$uuid][] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['hash']);
} catch (QUI\Exception) {
}
}
}
}
}
if (empty($groups)) {
if (class_exists('QUI\ERP\Order\Order')) {
foreach ($entities as $Entity) {
if (!($Entity instanceof QUI\ERP\Order\Order)) {
continue;
}
$uuid = $Entity->getUUID();
$groups[$uuid][] = $Entity;
if (class_exists('QUI\ERP\SalesOrders\Handler')) {
$salesOrder = $Entity->getPaymentDataEntry('salesOrder');
if (empty($salesOrder)) {
$salesOrder = $Entity->getCustomDataEntry('salesOrder');
}
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
if ($salesOrder) {
try {
$groups[$uuid][] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['hash']);
} catch (QUI\Exception) {
}
}
}
}
}
}
if (empty($groups)) {
if (class_exists('QUI\ERP\SalesOrders\SalesOrder')) {
foreach ($entities as $Entity) {
if (!($Entity instanceof QUI\ERP\SalesOrders\SalesOrder)) {
continue;
}
$uuid = $Entity->getUUID();
$groups[$uuid][] = $Entity;
}
}
}
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
// 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
*/

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
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
// 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
*
*/

Henning Leutz
committed
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()
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
]),
$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;
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
//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 [];
}
if (!class_exists('QUI\ERP\SalesOrders\Handler')) {
return [];
}
$result = [];
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 [];
}
foreach ($salesOrders as $salesOrder) {
try {
$result[] = QUI\ERP\SalesOrders\Handler::getSalesOrder($salesOrder['id']);
} catch (\Exception) {
}
}
// drafts
try {
$salesOrderDrafts = QUI::getDatabase()->fetch([
'select' => 'id,hash,global_process_id,date',
'from' => QUI\ERP\SalesOrders\Handler::getTableSalesOrderDrafts(),
'where_or' => [
'global_process_id' => $this->processId,
'hash' => $this->processId
]
]);
} catch (\Exception) {
return [];
}
foreach ($salesOrderDrafts 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
}