Add Economic invoice overview and draft check functionalities

Introduce new endpoints for viewing Economic invoice summaries and running draft checks. Implement `economic_tasks` helper for managing draft validations, and enhance `collected_order_invoices_o` and SQL clauses to improve query flexibility, including handling "NOT NULL" filters.
This commit is contained in:
Jepp9350
2025-04-02 15:08:57 +02:00
parent 02b91b4c77
commit 8bc4252089
6 changed files with 279 additions and 1 deletions
+10
View File
@@ -21,6 +21,7 @@ use endpoints\economic_orders_endpoint;
use endpoints\economic_products_endpoint;
use helpers\economic_customer;
use helpers\economic_invoice_draft;
use helpers\economic_tasks;
use interfaces\economic_i;
class economic implements economic_i
@@ -99,4 +100,13 @@ class economic implements economic_i
{
return new $this->helpers->economic_invoice_draft($draft_invoice_number, $currency);
}
/**
* Get the tasks helper
* @return economic_tasks
*/
public function getTasks(): economic_tasks
{
return new $this->helpers->economic_tasks();
}
}
@@ -1,10 +1,12 @@
<?php
require_once WD . '/modules/economic/helpers/economic_customer.php';
require_once WD . '/modules/economic/helpers/economic_invoice_draft.php';
require_once WD . '/modules/economic/helpers/economic_tasks.php';
use helpers\economic_customer;
use helpers\economic_invoice_draft;
use helpers\economic_tasks;
class economic_helpers
{
@@ -18,4 +20,9 @@ class economic_helpers
* @var string $economic_invoice_draft
*/
public string $economic_invoice_draft = economic_invoice_draft::class;
/**
* The Economic tasks helper
* @var string $economic_tasks
*/
public string $economic_tasks = economic_tasks::class;
}
@@ -0,0 +1,106 @@
<?php
namespace helpers;
use classes\economic;
use Exception;
use objects\collected_order_invoices_o;
class economic_tasks
{
/**
* Run the check drafts task
* This task checks the existence of drafts, that should be in Economic
* This includes:
* - Checking if the drafts exist in Economic
* - Checking if the drafts are in the correct state (If it has been sent, it should be in the sent state)
* - Checking if the drafts are in the correct state (If it has been booked, it should have a booked invoice id)
*
* @return void
* @throws Exception If the task fails
*/
public function runCheckDrafts(): void
{
// Define the invoice object
$collected_order_invoices_o = new collected_order_invoices_o();
// Get the drafts
$drafts = $collected_order_invoices_o->getTotalInvoices(
$collected_order_invoices_o,
[
'booked_invoice_id' => null,
'external_id' => 'NOT NULL',
],
);
// Check if the drafts exist in Economic
$economic = new economic();
// Get the drafts from Economic
$economic_drafts = $economic->invoices->drafts->get([], [])->collection;
// Define the external ids
$external_ids = [];
// Loop through the economic drafts
foreach ( $economic_drafts as $draft ) {
// Get the external id
try {
$external_id = $draft?->references?->other ?? null;
} catch (Exception $e) {
// If the external id does not exist, set it to null
$external_id = null;
}
// Check if the external id exists in Economic
if (!empty($external_id)) {
// Add the external id to the array
$external_ids[] = $external_id;
}
}
// Define the missing drafts array
$missing_drafts = [];
// Loop through the drafts
foreach ( $drafts as $draft ) {
// Check if the external id exists in the drafts
if (!in_array($draft['external_id'], $external_ids)) {
// If the external id does not exist, add it to the missing drafts array
$invoice_id = $draft['id'];
$missing_drafts[$invoice_id] = $draft['external_id'];
}
}
// Define the errors array
$errors = [];
// Loop through the missing drafts, and check if they are booked
foreach ( $missing_drafts as $draft_id => $draft_external_id ) {
// Check if the draft has been booked
//echo 'Checking if draft ' . $draft_external_id . ' has been booked' . PHP_EOL;
try {
// Get the booked invoice
$booked_invoice_id = $economic->invoices->booked->get_from_external_id($draft_external_id);
} catch (Exception $e) {
// If the booked invoice does not exist, set it to null
//echo 'Was unable to find booked invoice for draft ' . $draft_external_id . PHP_EOL;
$booked_invoice_id = null;
}
// Get the invoice object
$invoice_object = (new collected_order_invoices_o())->select($draft_id);
// Check if the booked invoice exists
if ($booked_invoice_id !== null) {
//echo 'FOUND BOOKED INVOICE (' . $draft_id . ') FOR DRAFT ' . $draft_external_id . PHP_EOL;
// Check if the booked invoice id is null
if (!empty($invoice_object->booked_invoice_id->value())) {
// Something went wrong, the booked invoice id is not null
throw new Exception('Booked invoice id is not null, but should be null, for draft ' . $draft_external_id);
} else {
// If the booked invoice id is null, set it to the booked invoice id
$invoice_object->booked_invoice_id->set((int)$booked_invoice_id);
//echo 'Setting booked invoice id to ' . $booked_invoice_id . PHP_EOL;
}
} else {
// If the booked invoice does not exist, set the error
//echo 'DRAFT ' . $draft_external_id . ' HAS NOT BEEN BOOKED' . PHP_EOL;
$invoice_object->error_message->set('ECONOMIC_INVOICE_NOT_FOUND');
}
}
}
}
@@ -19,9 +19,16 @@ class collected_order_invoices_o extends db
public object_property $external_id;
public object_property $booked_invoice_id;
public object_property $error_message;
public object_property $created_at;
public object_property $updated_at;
public object_property $closed_at;
/**
* The processor types
*
* 1 = E-conomic, 2 = Stripe, 3 = Other (without tracking)
* @var array|string[]
*/
public array $processors = [
1 => 'E-conomic',
2 => 'Stripe',
@@ -70,6 +77,7 @@ class collected_order_invoices_o extends db
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
$this->closed_at = new object_property($this->table, $this->id, 'closed_at', 'string', false);
$this->booked_invoice_id = new object_property($this->table, $this->id, 'booked_invoice_id', 'int', false);
$this->error_message = new object_property($this->table, $this->id, 'error_message', 'string', false);
}
public function asArray(): array
@@ -678,4 +686,36 @@ class collected_order_invoices_o extends db
'invoiceAllOrdersIndividually'
]);
}
/**
* Get the total invoices using E-conomic as the processor, with the given restrictions
* @param $collected_order_invoices collected_order_invoices_o
* @param $restrictions array
* @param $view string The MySQL view to use for the query
* @param $page int The page number to return
* @param $limit int The number of results to return per page
* @param $processor int
* @return array The total invoices
* @throws Exception If the request was not successful
* @see processors for the processor types
*/
function getTotalInvoices(collected_order_invoices_o $collected_order_invoices, array $restrictions = [], string $view = 'invoices_with_completed_orders', int $page = 1, int $limit = 100000, int $processor = 1): array
{
// Set the view
$collected_order_invoices->setView($view);
// Get the total invoices
return $collected_order_invoices->listObjectsWithPagination(
$page,
$limit,
null,
[
'processor' => $processor,
...$restrictions,
],
null,
function ($collected_order_invoice) {
return $collected_order_invoice;
},
);
}
}
@@ -3,6 +3,7 @@
namespace routes;
use classes\authentication;
use classes\economic;
use classes\response;
use classes\router;
use objects\collected_order_invoices_o;
@@ -440,6 +441,115 @@ class orderInvoicesRoute
$response->error('Invalid session', 400);
}
});
$this->get('/collected-invoices/economic/overview', function () {
global $response;
self::requirePermission('list_collected_invoices_economic_overview');
$user = (new authentication())->get_user();
if ($user) {
// Get the economic module
$economic = new economic();
// Get the collected order invoices
$collected_order_invoices = new collected_order_invoices_o();
/**
* Get the total invoices using E-conomic as the processor, with the given restrictions
* @param $collected_order_invoices collected_order_invoices_o
* @param $restrictions array
* @param $view string The MySQL view to use for the query
* @param $page int The page number to return
* @param $limit int The number of results to return per page
* @return int
*/
function getTotalInvoices(collected_order_invoices_o $collected_order_invoices, array $restrictions = [], string $view = 'invoices_with_completed_orders', int $page = 1, int $limit = 100000): int
{
// Add the economic processor to the restrictions
$restrictions['processor'] = 1; // E-conomic
return count(
$collected_order_invoices->getTotalInvoices(
$collected_order_invoices,
$restrictions,
$view,
$page,
$limit,
1
)
);
}
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'LIST_COLLECTED_INVOICES_ECONOMIC_OVERVIEW', 'User accessed the list of collected order invoices economic overview');
// Define the result array
$result = [
'total' => getTotalInvoices($collected_order_invoices),
'paid' => 0,
'unpaid' => 0,
'overdue' => 0,
'booked' => getTotalInvoices(
$collected_order_invoices,
[
'booked_invoice_id' => 'NOT NULL',
'external_id' => 'NOT NULL',
],
'invoices_with_completed_orders'
),
'draft' => getTotalInvoices(
$collected_order_invoices,
[
'booked_invoice_id' => null,
'error_message' => null,
'external_id' => 'NOT NULL',
],
'invoices_with_completed_orders'
),
'sent' => 0,
'error' => getTotalInvoices(
$collected_order_invoices,
[
'booked_invoice_id' => null,
'external_id' => 'NOT NULL',
'error_message' => 'NOT NULL',
],
'invoices_with_completed_orders'
),
];
// Return the list of customers
$response->success($result);
} else {
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_ECONOMIC_OVERVIEW', 'User tried to access the list of collected order invoices economic overview without a valid session');
$response->error('Invalid session', 400);
}
},
[
'list_collected_invoices_economic_overview' => 'List ALL collected order invoices overview. This is a superuser-only route.'
]
);
$this->post('/collected-invoices/economic/run/check-drafts', function () {
global $response;
self::requirePermission('module_economic_run_check_drafts');
$user = (new authentication())->get_user();
if ($user) {
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'RUN_CHECK_DRAFTS', 'User ran the check drafts');
// Get the economic module
$economic = new economic();
try {
// Run the check drafts
$economic->getTasks()->runCheckDrafts();
} catch (\Exception $e) {
// If the task fails, log the error and return an error response
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'RUN_CHECK_DRAFTS', 'User tried to run the check drafts, but it failed: ' . $e->getMessage());
$response->error('Failed to run the check drafts: ' . $e->getMessage(), 500);
}
// Return the result
$response->success('Check drafts completed successfully');
} else {
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'RUN_CHECK_DRAFTS', 'User tried to run the check drafts without a valid session');
$response->error('Invalid session', 400);
}
},
[
'module_economic_run_check_drafts' => 'Run the check drafts. This is a superuser-only route.'
]
);
}
/**
+6 -1
View File
@@ -319,10 +319,15 @@ trait db_object_t
continue;
}
// If the value is null, add a where clause to check if the field is null
if ($value === null) {
if ($value === null || (is_string($value) && strtolower($value) === 'null')) {
$whereClauses[] = "$field IS NULL";
continue;
}
// If the value is "NOT NULL", add a where clause to check if the field is not null
if ($value === 'NOT NULL' || (is_string($value) && strtolower($value) === 'not null')) {
$whereClauses[] = "$field IS NOT NULL";
continue;
}
$whereClauses[] = "`$field` = ?";
$params[] = $value;
}