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:
@@ -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.'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user