Merge pull request #14 from copenhagentruckwash/development
Refactor and enhance order invoices and data handling
This commit is contained in:
@@ -97,12 +97,15 @@ class authentication implements authentication_i
|
||||
{
|
||||
// Get the token from the headers
|
||||
$headers = getallheaders();
|
||||
if (!isset($headers['Authorization'])) {
|
||||
$tmp = json_decode(file_get_contents('php://input'), true);
|
||||
if (!isset($headers['Authorization']) && !isset($_GET['token']) && !isset($_POST['token']) && !isset($tmp['token'])) {
|
||||
return false;
|
||||
}
|
||||
$token = $headers['Authorization'];
|
||||
// Strip the Bearer prefix
|
||||
$token = str_replace('Bearer ', '', $token);
|
||||
$token = $_GET['token'] ?? $headers['Authorization'] ?? $tmp['token'] ?? $_POST['token'];
|
||||
// Strip the Bearer prefix (If the token is from the headers)
|
||||
if (isset($headers['Authorization'])) {
|
||||
$token = str_replace('Bearer ', '', $token);
|
||||
}
|
||||
// Get the token from the database
|
||||
$token = (new plate_scanners_o())->getPlateScannerByApiKey($token);
|
||||
// Check if the token exists
|
||||
|
||||
@@ -8,15 +8,19 @@ require_once WD . '/modules/economic/endpoints/economic_departments_endpoint.php
|
||||
require_once WD . '/modules/economic/endpoints/economic_layouts_endpoint.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_customers_endpoint.php';
|
||||
require_once WD . '/modules/economic/endpoints/economic_products_endpoint.php';
|
||||
require_once WD . '/modules/economic/economic_helpers.php';
|
||||
|
||||
|
||||
use economic_c;
|
||||
use economic_helpers;
|
||||
use endpoints\economic_customers_endpoint;
|
||||
use endpoints\economic_departments_endpoint;
|
||||
use endpoints\economic_invoices_endpoint;
|
||||
use endpoints\economic_layouts_endpoint;
|
||||
use endpoints\economic_orders_endpoint;
|
||||
use endpoints\economic_products_endpoint;
|
||||
use helpers\economic_customer;
|
||||
use helpers\economic_invoice_draft;
|
||||
use interfaces\economic_i;
|
||||
|
||||
class economic implements economic_i
|
||||
@@ -56,6 +60,11 @@ class economic implements economic_i
|
||||
* @var economic_products_endpoint
|
||||
*/
|
||||
public economic_products_endpoint $products;
|
||||
/**
|
||||
* Helper classes
|
||||
* @var economic_helpers
|
||||
*/
|
||||
protected economic_helpers $helpers;
|
||||
|
||||
|
||||
public function __construct()
|
||||
@@ -67,5 +76,26 @@ class economic implements economic_i
|
||||
$this->layouts = new economic_layouts_endpoint();
|
||||
$this->customers = new economic_customers_endpoint();
|
||||
$this->products = new economic_products_endpoint();
|
||||
$this->helpers = new economic_helpers();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a customer by their customer number
|
||||
* @param int $customer_number The Economic customer number
|
||||
* @return economic_customer
|
||||
*/
|
||||
public function getCustomer(int $customer_number): economic_customer
|
||||
{
|
||||
return new $this->helpers->economic_customer($customer_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a invoiceDraft (Helper) from the Economic system
|
||||
* @param int $draft_invoice_number The Economic draft invoice number
|
||||
* @return economic_invoice_draft
|
||||
*/
|
||||
public function getInvoiceDraft(int $draft_invoice_number): economic_invoice_draft
|
||||
{
|
||||
return new $this->helpers->economic_invoice_draft($draft_invoice_number);
|
||||
}
|
||||
}
|
||||
@@ -2,9 +2,27 @@
|
||||
|
||||
namespace classes;
|
||||
require_once WD . '/modules/email/email_c.php';
|
||||
require_once WD . '/modules/email/helpers/email_template.php';
|
||||
require_once WD . '/modules/email/templates/email_template_header.php';
|
||||
require_once WD . '/modules/email/templates/email_template_footer.php';
|
||||
require_once WD . '/modules/email/templates/email_template_head.php';
|
||||
require_once WD . '/modules/email/templates/email_template_stripe_invoice.php';
|
||||
|
||||
use email\email_c;
|
||||
use email\templates\email_template_footer;
|
||||
use email\templates\email_template_head;
|
||||
use email\templates\email_template_header;
|
||||
use email\templates\email_template_stripe_invoice;
|
||||
use Exception;
|
||||
use interfaces\email_i;
|
||||
use JsonException;
|
||||
use MailerSend\Exceptions\MailerSendAssertException;
|
||||
use MailerSend\Exceptions\MailerSendException;
|
||||
use MailerSend\Helpers\Builder\EmailParams;
|
||||
use MailerSend\Helpers\Builder\Header;
|
||||
use MailerSend\Helpers\Builder\Recipient;
|
||||
use MailerSend\MailerSend;
|
||||
use Psr\Http\Client\ClientExceptionInterface;
|
||||
|
||||
class email implements email_i
|
||||
{
|
||||
@@ -24,9 +42,9 @@ class email implements email_i
|
||||
{
|
||||
if ($test_recipient) {
|
||||
try {
|
||||
$this->sendEmail($test_recipient, 'Test email', 'This is a test email');
|
||||
$this->sendEmail($test_recipient, 'Test recipient', 'Test email', 'This is a test email');
|
||||
return 'Email sent successfully to ' . $test_recipient;
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
return 'Email error: ' . $e->getMessage();
|
||||
}
|
||||
} else {
|
||||
@@ -34,28 +52,121 @@ class email implements email_i
|
||||
}
|
||||
}
|
||||
|
||||
private function sendEmail($to, $subject, $message): void
|
||||
/**
|
||||
* Send an email using the preferred email service
|
||||
* @param string $to Email address to send the email to
|
||||
* @param string $recipient_name Name of the recipient
|
||||
* @param string $subject Subject of the email
|
||||
* @param string $message Message of the email
|
||||
* @throws Exception If an error occurs while sending the email
|
||||
*/
|
||||
public function sendEmail(string $to, string $recipient_name, string $subject, string $message, string $references = null): void
|
||||
{
|
||||
// Send POST request to email service
|
||||
$ch = curl_init();
|
||||
curl_setopt($ch, CURLOPT_URL, 'https://maintenancemode.cloud/mailer.php');
|
||||
curl_setopt($ch, CURLOPT_POST, 1);
|
||||
// Add the data to the request
|
||||
curl_setopt($ch, CURLOPT_POSTFIELDS, [
|
||||
'recipient' => $to,
|
||||
'subject' => $subject,
|
||||
'message' => $message,
|
||||
]);
|
||||
// Return the response instead of outputting it
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
|
||||
// Execute the POST request
|
||||
$response = curl_exec($ch);
|
||||
// Close cURL resource
|
||||
curl_close($ch);
|
||||
// Check for errors
|
||||
if ($response === false) {
|
||||
throw new \Exception('Curl error: ' . curl_error($ch));
|
||||
if ($this->config->mailersend_enabled->getVariableValue()) {
|
||||
try {
|
||||
// Generate HTML email
|
||||
$html = self::generateHtmlHeader();
|
||||
// Add email content
|
||||
$html .= $message;
|
||||
// Add email footer
|
||||
$html .= self::generateHtmlFooter();
|
||||
$this->sendEmailMailerSend($to, $recipient_name, $subject, $message, $html, $references);
|
||||
} catch (JsonException|MailerSendException|ClientExceptionInterface $e) {
|
||||
throw new Exception('Error sending email: ' . $e->getMessage());
|
||||
}
|
||||
} else {
|
||||
$this->sendEmailDefault($to, $subject, $message);
|
||||
}
|
||||
}
|
||||
|
||||
private static function generateHtmlHeader(): false|string
|
||||
{
|
||||
$email_template_head = (new email_template_head())->generate_html();
|
||||
$email_template_header = (new email_template_header())->generate_html();
|
||||
return "
|
||||
<!DOCTYPE html>
|
||||
<html lang='da'>
|
||||
<head>
|
||||
$email_template_head
|
||||
</head>
|
||||
<body>
|
||||
$email_template_header";
|
||||
}
|
||||
|
||||
private static function generateHtmlFooter(): string
|
||||
{
|
||||
$email_template_footer = (new email_template_footer())->generate_html();
|
||||
return "
|
||||
$email_template_footer
|
||||
</body>
|
||||
</html>";
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws JsonException
|
||||
* @throws MailerSendAssertException
|
||||
* @throws MailerSendException
|
||||
*/
|
||||
private function sendEmailMailerSend(string $to, string $recipient_name, string $subject, string $message, string $html = null, string $references = null): void
|
||||
{
|
||||
// Send POST request to email service
|
||||
$mailersend = new MailerSend(['api_key' => $this->config->mailersend_api_key->getVariableValue()]);
|
||||
|
||||
$recipients = [
|
||||
new Recipient($to, $recipient_name)
|
||||
];
|
||||
|
||||
$emailParams = (new EmailParams())
|
||||
->setFrom($this->config->smtp_from->getVariableValue())
|
||||
->setFromName($this->config->smtp_from_name->getVariableValue())
|
||||
->setRecipients($recipients)
|
||||
->setSubject($subject)
|
||||
->setHtml($html ?? $message)
|
||||
->setReplyTo($this->config->smtp_reply_to->getVariableValue())
|
||||
->setReplyToName($this->config->smtp_reply_to_name->getVariableValue());
|
||||
|
||||
if ($references) {
|
||||
$emailParams->setHeaders([
|
||||
new Header('References', $references)
|
||||
]);
|
||||
}
|
||||
$mailersend->email->send($emailParams);
|
||||
}
|
||||
|
||||
/**
|
||||
* Send an email using the default SMTP service
|
||||
* @param string $to Email address to send the email to
|
||||
* @param string $subject Subject of the email
|
||||
* @param string $message Message of the email
|
||||
* @throws Exception If an error occurs while sending the email
|
||||
*/
|
||||
private function sendEmailDefault(string $to, string $subject, string $message): void
|
||||
{
|
||||
// Send email using default SMTP service
|
||||
throw new Exception('Default SMTP service not implemented');
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws MailerSendException
|
||||
* @throws ClientExceptionInterface
|
||||
* @throws JsonException
|
||||
* @throws MailerSendAssertException
|
||||
*/
|
||||
public function sendStripeInvoiceEmail(string $to, string|null $recipient_name, string $payment_link, $order_id): void
|
||||
{
|
||||
$recipient_name = $recipient_name ?? 'Kunde';
|
||||
$recipient_name = ucfirst($recipient_name);
|
||||
// Generate HTML email
|
||||
$html = self::generateHtmlHeader();
|
||||
// Add email content
|
||||
$html .= (new email_template_stripe_invoice(
|
||||
$order_id,
|
||||
$payment_link,
|
||||
$recipient_name
|
||||
))->generate_html();
|
||||
// Add email footer
|
||||
$html .= self::generateHtmlFooter();
|
||||
$this->sendEmailMailerSend($to, $recipient_name, 'Betalingslink for bestilling #' . $order_id, '', $html);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
|
||||
namespace classes;
|
||||
|
||||
/** Require the form_t trait */
|
||||
require_once WD . '/traits/form_t.php';
|
||||
|
||||
/** Require the form_helper_c class */
|
||||
require_once WD . '/modules/forms/form_helper_c.php';
|
||||
|
||||
use Exception;
|
||||
use forms\book_wash_f;
|
||||
use forms\form_helper_c;
|
||||
use traits\form_t;
|
||||
|
||||
/** Require the forms */
|
||||
require_once WD . '/modules/forms/book_wash_f.php';
|
||||
|
||||
class form
|
||||
{
|
||||
/**
|
||||
* The BOOK_WASH form
|
||||
* @var book_wash_f $book_wash The BOOK_WASH form
|
||||
*/
|
||||
public book_wash_f $book_wash;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->book_wash = new book_wash_f();
|
||||
}
|
||||
|
||||
/**
|
||||
* Submit a form
|
||||
* @throws Exception If the form is not valid
|
||||
* @throws Exception If the form is not submitted
|
||||
* @throws Exception If the form is not found
|
||||
* @throws Exception If the form is not found in the form helper
|
||||
*/
|
||||
public function submitForm(object $form): void
|
||||
{
|
||||
/** @var form_t|object $form */
|
||||
$form->submit();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a form exists (by its identifier)
|
||||
* @param string $form_identifier The form identifier
|
||||
* @return bool True if the form exists, false if not
|
||||
*/
|
||||
public function doesFormExist(string $form_identifier): bool
|
||||
{
|
||||
// Check if there's any form with the given identifier
|
||||
$form_classes = get_declared_classes();
|
||||
foreach ( $form_classes as $form_class ) {
|
||||
if (is_subclass_of($form_class, form_helper_c::class)) {
|
||||
$form = new $form_class();
|
||||
// Check if the class is a subclass of form_helper_c, and has the form_t trait
|
||||
if (method_exists($form, 'getFormIdentifier') && $form->getFormIdentifier() === $form_identifier) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a form by its identifier
|
||||
* @param string $form_identifier The form identifier
|
||||
* @return form_t The form object
|
||||
* @throws Exception If the form is not found
|
||||
*/
|
||||
public function getForm(string $form_identifier): object
|
||||
{
|
||||
// Check if there's any form with the given identifier
|
||||
$form_classes = get_declared_classes();
|
||||
foreach ( $form_classes as $form_class ) {
|
||||
// Check if the class is a subclass of form_helper_c, and has the form_t trait
|
||||
if (is_subclass_of($form_class, form_helper_c::class) && trait_exists(form_t::class)) {
|
||||
// Create an instance of the form class (If it is a subclass of form_helper_c, and use the form_t trait)
|
||||
$form = new $form_class();
|
||||
if (method_exists($form, 'getFormIdentifier') && $form->getFormIdentifier() === $form_identifier) {
|
||||
return $form;
|
||||
}
|
||||
}
|
||||
}
|
||||
throw new Exception('The form was not found');
|
||||
}
|
||||
}
|
||||
@@ -3,9 +3,14 @@
|
||||
namespace classes;
|
||||
|
||||
require_once WD . '/modules/motorapi/motorapi_c.php';
|
||||
require_once WD . '/modules/motorapi/helpers/motorapi_vehicle_types.php';
|
||||
/** Actions */
|
||||
require_once WD . '/modules/motorapi/actions/license_plate_lookup_a.php';
|
||||
|
||||
use Exception;
|
||||
use interfaces\motorapi_i;
|
||||
use motorapi\actions\license_plate_lookup_a;
|
||||
use motorapi\helpers\motorapi_vehicle_types;
|
||||
use motorapi\motorapi_c;
|
||||
use objects\motorapi_lookups_o;
|
||||
|
||||
@@ -16,6 +21,11 @@ class motorapi implements motorapi_i
|
||||
* @var motorapi_c
|
||||
*/
|
||||
public motorapi_c $config;
|
||||
/**
|
||||
* Vehicle types
|
||||
* @var motorapi_vehicle_types
|
||||
*/
|
||||
public motorapi_vehicle_types $vehicle_types;
|
||||
|
||||
/**
|
||||
* API URL
|
||||
@@ -23,47 +33,49 @@ class motorapi implements motorapi_i
|
||||
*/
|
||||
private string $api_url = 'https://v1.motorapi.dk/';
|
||||
|
||||
/**
|
||||
* ACTION: LICENSE_PLATE_LOOKUP
|
||||
* @see license_plate_lookup_a
|
||||
* @notation This action is when a license plate lookup request is made, and logs the request in the database
|
||||
* @var license_plate_lookup_a
|
||||
*/
|
||||
private license_plate_lookup_a $license_plate_lookup;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new motorapi_c();
|
||||
$this->vehicle_types = new motorapi_vehicle_types();
|
||||
/** Actions */
|
||||
$this->license_plate_lookup = new license_plate_lookup_a();
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
|
||||
* Get the recommended products for a license plate
|
||||
* @param string $plate The license plate
|
||||
* @return array The recommended products
|
||||
* @throws Exception If the module is not enabled
|
||||
* @throws Exception If the license plate is invalid
|
||||
* @throws Exception If the daily limit is exceeded
|
||||
* @throws Exception If the secret key is invalid
|
||||
*/
|
||||
function getLicensePlateInformation(string $licensePlate): object
|
||||
public function getRecommendedProducts(string $plate): array
|
||||
{
|
||||
// Get the license plate information from the motorapi
|
||||
return $this->sendRequest($licensePlate, 'vehicles', [], 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
|
||||
*/
|
||||
function sendRequest(string $licensePlate, string $endpoint, array $data = [], string $method = 'GET'): object
|
||||
{
|
||||
// Validate the module is enabled
|
||||
self::requireModuleEnabled();
|
||||
// Validate the license plate
|
||||
self::requireValidLicensePlate($licensePlate);
|
||||
// Validate the daily limit
|
||||
self::requireDailyLimitNotExceeded();
|
||||
// Validate the secret key
|
||||
self::requireValidSecretKey();
|
||||
// Send the request
|
||||
$response = match ($method) {
|
||||
'GET' => self::sendGetRequest($licensePlate, $endpoint, $data),
|
||||
'POST' => self::sendPostRequest($licensePlate, $endpoint, $data),
|
||||
'PUT' => self::sendPutRequest($licensePlate, $endpoint, $data),
|
||||
'DELETE' => self::sendDeleteRequest($licensePlate, $endpoint, $data),
|
||||
default => throw new Exception('Invalid method'),
|
||||
self::requireValidLicensePlate($plate);
|
||||
$data = self::getLicensePlateInformation($plate, false);
|
||||
// Get the recommended products for the license plate
|
||||
return match ($data->type) {
|
||||
// TODO: Add recommended products for each vehicle type, and convert this into an object type.
|
||||
$this->vehicle_types->PLATE_TYPE_CAR => [
|
||||
1,
|
||||
2,
|
||||
],
|
||||
$this->vehicle_types->PLATE_TYPE_TRUCK => [
|
||||
3,
|
||||
4,
|
||||
],
|
||||
default => [],
|
||||
};
|
||||
// Add the request to the log
|
||||
self::addRequestToLog($licensePlate, $endpoint, $response);
|
||||
// Return the response
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -88,6 +100,84 @@ class motorapi implements motorapi_i
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
|
||||
*/
|
||||
function getLicensePlateInformation(string $licensePlate, bool $ignoreCache = true): object
|
||||
{
|
||||
// Check if the license plate information is cached
|
||||
if (!$ignoreCache && self::isCached($licensePlate)) {
|
||||
// Get the cached result
|
||||
return self::getCachedResult($licensePlate);
|
||||
}
|
||||
// Get the license plate information from the motorapi
|
||||
return $this->sendRequest($licensePlate, 'vehicles', [], 'GET');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function isCached(string $licensePlate): bool
|
||||
{
|
||||
// Check if the license plate response is stored in the log/local database/cache
|
||||
$motorapi_lookups = new motorapi_lookups_o();
|
||||
return $motorapi_lookups->isCached($licensePlate);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
function getCachedResult(string $licensePlate): object
|
||||
{
|
||||
global /** @var response $response */
|
||||
$response;
|
||||
// Get the cached result from the log/local database/cache
|
||||
$motorapi_lookups = new motorapi_lookups_o();
|
||||
// Add the cached value to the meta
|
||||
$response->add_meta('cached', true);
|
||||
return json_decode($motorapi_lookups->getCachedResult($licensePlate)->result->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module is not enabled, the license plate is invalid, the daily limit is exceeded, or the secret key is invalid
|
||||
*/
|
||||
function sendRequest(string $licensePlate, string $endpoint, array $data = [], string $method = 'GET'): object
|
||||
{
|
||||
// Validate the module is enabled
|
||||
self::requireModuleEnabled();
|
||||
// Validate the license plate
|
||||
self::requireValidLicensePlate($licensePlate);
|
||||
// Validate the daily limit
|
||||
self::requireDailyLimitNotExceeded();
|
||||
// Validate the secret key
|
||||
self::requireValidSecretKey();
|
||||
// Send the request
|
||||
$response = match ($method) {
|
||||
'GET' => self::sendGetRequest($licensePlate, $endpoint, $data),
|
||||
'POST' => self::sendPostRequest($licensePlate, $endpoint, $data),
|
||||
'PUT' => self::sendPutRequest($licensePlate, $endpoint, $data),
|
||||
'DELETE' => self::sendDeleteRequest($licensePlate, $endpoint, $data),
|
||||
default => self::exception(
|
||||
$licensePlate, [
|
||||
'method' => $method,
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => 400,
|
||||
'error' => 'Invalid request method',
|
||||
],
|
||||
500
|
||||
),
|
||||
};
|
||||
// Add the request to the log
|
||||
self::addRequestToLog($licensePlate, $endpoint, $response);
|
||||
// Return the response
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
@@ -117,10 +207,27 @@ class motorapi implements motorapi_i
|
||||
{
|
||||
// Check if the secret key is valid
|
||||
if ($this->config->secret_key->getVariableValue() === null) {
|
||||
throw new Exception('Invalid secret key');
|
||||
self::exception(
|
||||
'',
|
||||
[
|
||||
'status_code' => 500,
|
||||
'error' => 'Invalid secret key defined in the config (motorapi_secret_key_c)',
|
||||
],
|
||||
500
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
function exception(string $licensePlate, array $data = [], int $status_code = 500): exception
|
||||
{
|
||||
// Add the request to the log
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, $data, $status_code);
|
||||
return throw new Exception($data['error'] ?? 'An error occurred while processing the request, in ' . $this->config->getModuleName() . ' module');
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception
|
||||
@@ -148,11 +255,46 @@ class motorapi implements motorapi_i
|
||||
|
||||
// Check for errors
|
||||
if (curl_errno($ch)) {
|
||||
throw new Exception('cURL error: ' . curl_error($ch));
|
||||
self::exception(
|
||||
$licensePlate, [
|
||||
'method' => 'GET',
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => 500,
|
||||
'error' => curl_error($ch),
|
||||
],
|
||||
500
|
||||
);
|
||||
}
|
||||
|
||||
// Get the status code
|
||||
$status_code = curl_getinfo($ch, CURLINFO_HTTP_CODE);
|
||||
|
||||
curl_close($ch);
|
||||
// Decode and return JSON response
|
||||
// Check if the response is valid JSON
|
||||
if (!json_decode($output)) {
|
||||
$exception_message = match ($status_code) {
|
||||
401 => 'Unauthorized',
|
||||
404 => 'Not found',
|
||||
429 => 'Too many requests',
|
||||
default => 'Invalid response',
|
||||
};
|
||||
self::exception(
|
||||
$licensePlate, [
|
||||
'method' => 'GET',
|
||||
'endpoint' => $endpoint,
|
||||
'data' => $data,
|
||||
'license_plate' => $licensePlate,
|
||||
'response' => null,
|
||||
'status_code' => $status_code,
|
||||
'error' => $exception_message,
|
||||
],
|
||||
$status_code
|
||||
);
|
||||
}
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), $status_code);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -169,6 +311,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -185,6 +328,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
@@ -201,6 +345,7 @@ class motorapi implements motorapi_i
|
||||
curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
|
||||
$output = curl_exec($ch);
|
||||
curl_close($ch);
|
||||
$this->license_plate_lookup->license_plate_lookup($licensePlate, json_decode($output), 200);
|
||||
return json_decode($output);
|
||||
}
|
||||
|
||||
|
||||
@@ -20,7 +20,7 @@ class object_property
|
||||
$this->required = $required;
|
||||
$this->default = $default;
|
||||
}
|
||||
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
// Return the value of the field in the database table
|
||||
@@ -54,7 +54,10 @@ class object_property
|
||||
// If the value is null, set it to null
|
||||
if ($value === null) {
|
||||
$sql = "UPDATE $this->table SET $this->column = NULL WHERE id = $this->id";
|
||||
} // If the value is a string, escape it
|
||||
} // If the value is an integer, set it to the integer value
|
||||
elseif (is_int($value)) {
|
||||
$sql = "UPDATE $this->table SET $this->column = $value WHERE id = $this->id";
|
||||
} // If the value is a string, escape it
|
||||
else {
|
||||
$value = $db->escape_string($value);
|
||||
$sql = "UPDATE $this->table SET $this->column = '$value' WHERE id = $this->id";
|
||||
|
||||
@@ -2,8 +2,10 @@
|
||||
|
||||
namespace classes;
|
||||
|
||||
use Exception;
|
||||
use interfaces\response_i;
|
||||
use JetBrains\PhpStorm\NoReturn;
|
||||
use objects\users_o;
|
||||
|
||||
class response implements response_i
|
||||
{
|
||||
@@ -11,6 +13,7 @@ class response implements response_i
|
||||
private array $data = [];
|
||||
private array $meta = [];
|
||||
private array $includes = [];
|
||||
private users_o $users_o;
|
||||
|
||||
#[NoReturn] public function success(mixed $data, int $status = null): void
|
||||
{
|
||||
@@ -206,4 +209,19 @@ class response implements response_i
|
||||
error_reporting(0);
|
||||
ini_set('display_errors', '0');
|
||||
}
|
||||
|
||||
/**
|
||||
* This function gets the user object from the token
|
||||
* @throws Exception If the token is invalid, or the user is not found
|
||||
*/
|
||||
public function get_user(): users_o|false
|
||||
{
|
||||
// Check if the user is already set
|
||||
if (!isset($this->users_o)) {
|
||||
// Get the user object
|
||||
$this->users_o = (new authentication())->get_user();
|
||||
}
|
||||
// Return the user object
|
||||
return $this->users_o;
|
||||
}
|
||||
}
|
||||
@@ -17,9 +17,9 @@ class router
|
||||
$this->routeClasses = [];
|
||||
}
|
||||
|
||||
public function add($route, $method, $function): void
|
||||
public function add($route, $method, $function, array $permissions = []): void
|
||||
{
|
||||
$this->routes[] = ['route' => $route, 'method' => $method, 'function' => $function];
|
||||
$this->routes[] = ['route' => $route, 'method' => $method, 'function' => $function, 'permissions' => $permissions];
|
||||
}
|
||||
|
||||
public function auto_load_routes(string $path): void
|
||||
@@ -106,4 +106,23 @@ class router
|
||||
$response->internal_server_error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
public function countRoutes(): int
|
||||
{
|
||||
return count($this->routes);
|
||||
}
|
||||
|
||||
public function getPermissions(): array
|
||||
{
|
||||
$permissions = [];
|
||||
foreach ( $this->routes as $route ) {
|
||||
$permissions = array_merge($permissions, $route['permissions']);
|
||||
}
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
public function getRoutes(): array
|
||||
{
|
||||
return $this->routes;
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,8 @@ require_once WD . '/modules/stripe/endpoints/stripe_endpoint_customers.php';
|
||||
require_once WD . '/modules/stripe/endpoints/stripe_endpoint_payment_link.php';
|
||||
require_once WD . '/modules/stripe/endpoints/stripe_endpoint_product.php';
|
||||
require_once WD . '/modules/stripe/endpoints/stripe_endpoint_prices.php';
|
||||
require_once WD . '/modules/stripe/endpoints/stripe_endpoint_invoice.php';
|
||||
require_once WD . '/modules/stripe/endpoints/stripe_endpoint_readers.php';
|
||||
|
||||
|
||||
// Require all helper classes
|
||||
@@ -19,9 +21,11 @@ require_once WD . '/modules/stripe/helpers/stripe_price.php';
|
||||
use Exception;
|
||||
use interfaces\stripe_i;
|
||||
use stripe\endpoints\stripe_endpoint_customers;
|
||||
use stripe\endpoints\stripe_endpoint_invoice;
|
||||
use stripe\endpoints\stripe_endpoint_payment_link;
|
||||
use stripe\endpoints\stripe_endpoint_prices;
|
||||
use stripe\endpoints\stripe_endpoint_product;
|
||||
use stripe\endpoints\stripe_endpoint_readers;
|
||||
use stripe\stripe_c;
|
||||
use Stripe\StripeClient;
|
||||
|
||||
@@ -56,12 +60,23 @@ class stripe implements stripe_i
|
||||
* @var stripe_endpoint_prices
|
||||
*/
|
||||
public stripe_endpoint_prices $prices;
|
||||
/**
|
||||
* Invoice endpoint
|
||||
* @var stripe_endpoint_invoice
|
||||
*/
|
||||
public stripe_endpoint_invoice $invoice;
|
||||
/**
|
||||
* Readers endpoint
|
||||
* @var stripe_endpoint_readers
|
||||
*/
|
||||
public stripe_endpoint_readers $readers;
|
||||
/**
|
||||
* Stripe client
|
||||
* @var StripeClient
|
||||
*/
|
||||
protected StripeClient $client;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->config = new stripe_c();
|
||||
@@ -69,6 +84,8 @@ class stripe implements stripe_i
|
||||
$this->payment_link = new stripe_endpoint_payment_link();
|
||||
$this->product = new stripe_endpoint_product();
|
||||
$this->prices = new stripe_endpoint_prices();
|
||||
$this->invoice = new stripe_endpoint_invoice();
|
||||
$this->readers = new stripe_endpoint_readers();
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -10,6 +10,14 @@
|
||||
"aws/aws-sdk-php": "^3.0",
|
||||
"predis/predis": "*",
|
||||
"phpmailer/phpmailer": "^6.9.2",
|
||||
"stripe/stripe-php": "^16.5"
|
||||
"stripe/stripe-php": "^16.5",
|
||||
"php-http/guzzle7-adapter": "^1.1",
|
||||
"nyholm/psr7": "^1.8",
|
||||
"mailersend/mailersend": "^0.28.0"
|
||||
},
|
||||
"config": {
|
||||
"allow-plugins": {
|
||||
"php-http/discovery": true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Generated
+1111
-1
File diff suppressed because it is too large
Load Diff
@@ -1,6 +1,7 @@
|
||||
<?php
|
||||
// prevent direct access
|
||||
|
||||
use classes\backup_store;
|
||||
use objects\bookings_o;
|
||||
use objects\logs_o;
|
||||
use objects\users_o;
|
||||
@@ -39,7 +40,7 @@ $cron_tasks = [
|
||||
'function' => 'syncLogsToDatabase',
|
||||
],
|
||||
'SyncUserEconomicCustomerDiscounts' => [
|
||||
'interval' => 600, // 10 minutes
|
||||
'interval' => 60, // 1 minute
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'SyncUserEconomicCustomerDiscounts',
|
||||
@@ -50,10 +51,19 @@ $cron_tasks = [
|
||||
'next_run' => 0,
|
||||
'function' => 'SyncUserEconomicCustomerDetails',
|
||||
],
|
||||
'backup' => [
|
||||
'interval' => 43200, // 12 hours
|
||||
'last_run' => 0,
|
||||
'next_run' => 0,
|
||||
'function' => 'backup',
|
||||
],
|
||||
];
|
||||
|
||||
function checkUnfulfilledBookings(): void
|
||||
{
|
||||
// This is deactivated for now, as it is not wanted.
|
||||
// I'm saving this for later, as it is a good idea to have this in place.
|
||||
return;
|
||||
$bookings_o = new bookings_o();
|
||||
$bookings_o->checkUnfulfilledBookings();
|
||||
}
|
||||
@@ -70,6 +80,16 @@ function syncLogsToDatabase(): void
|
||||
$logs_o->syncLogsToDatabase();
|
||||
}
|
||||
|
||||
function backup(): void
|
||||
{
|
||||
try {
|
||||
$backup = new backup_store();
|
||||
$backup->createBackup();
|
||||
} catch (Exception $e) {
|
||||
warn('Backup failed: ' . $e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
function SyncUserEconomicCustomerDiscounts(): void
|
||||
{
|
||||
$users_o = new users_o();
|
||||
|
||||
@@ -60,6 +60,7 @@ require_once 'classes/email.php';
|
||||
require_once 'classes/backup_store.php';
|
||||
require_once 'classes/motorapi.php';
|
||||
require_once 'classes/stripe.php';
|
||||
require_once 'classes/form.php';
|
||||
|
||||
/**
|
||||
* Modules
|
||||
|
||||
@@ -2,14 +2,17 @@
|
||||
|
||||
namespace interfaces;
|
||||
|
||||
use Exception;
|
||||
|
||||
interface motorapi_i
|
||||
{
|
||||
/**
|
||||
* Get license plate information from the motorapi
|
||||
* @param string $licensePlate The license plate to get information about (e.g. "AB12345")
|
||||
* @param bool $ignoreCache Whether to ignore the cache or not. If true, the cache will be ignored and the request will be sent to the motorapi directly.
|
||||
* @return object The license plate information
|
||||
*/
|
||||
function getLicensePlateInformation(string $licensePlate): object;
|
||||
function getLicensePlateInformation(string $licensePlate, bool $ignoreCache = true): object;
|
||||
|
||||
/**
|
||||
* Get the daily request counter
|
||||
@@ -30,7 +33,7 @@ interface motorapi_i
|
||||
/**
|
||||
* Require the module to be enabled
|
||||
* @return void
|
||||
* @throws \Exception If the module is not enabled
|
||||
* @throws Exception If the module is not enabled
|
||||
*/
|
||||
function requireModuleEnabled(): void;
|
||||
|
||||
@@ -38,21 +41,21 @@ interface motorapi_i
|
||||
* Require the license plate to be valid
|
||||
* @param string $licensePlate The license plate to validate
|
||||
* @return void
|
||||
* @throws \Exception If the license plate is not valid
|
||||
* @throws Exception If the license plate is not valid
|
||||
*/
|
||||
function requireValidLicensePlate(string $licensePlate): void;
|
||||
|
||||
/**
|
||||
* Require the daily limit to not be exceeded
|
||||
* @return void
|
||||
* @throws \Exception If the daily limit is exceeded
|
||||
* @throws Exception If the daily limit is exceeded
|
||||
*/
|
||||
function requireDailyLimitNotExceeded(): void;
|
||||
|
||||
/**
|
||||
* Require the secret key to be valid
|
||||
* @return void
|
||||
* @throws \Exception If the secret key is not valid
|
||||
* @throws Exception If the secret key is not valid
|
||||
*/
|
||||
function requireValidSecretKey(): void;
|
||||
|
||||
@@ -100,4 +103,20 @@ interface motorapi_i
|
||||
* @return void
|
||||
*/
|
||||
function addRequestToLog(string $licensePlate, string $endpoint, object $response): void;
|
||||
|
||||
/**
|
||||
* Check if a license plate response is stored in the log/local database/cache
|
||||
* @param string $licensePlate The license plate to check
|
||||
* @return bool Whether the license plate response is stored in the log/local database/cache
|
||||
* @throws Exception If the license plate is not valid
|
||||
*/
|
||||
function isCached(string $licensePlate): bool;
|
||||
|
||||
/**
|
||||
* Get the cached response for a license plate
|
||||
* @param string $licensePlate The license plate to get the cached response for
|
||||
* @return object The (latest) cached response for the license plate
|
||||
* @throws Exception If the license plate is not valid or the response is not cached
|
||||
*/
|
||||
function getCachedResult(string $licensePlate): object;
|
||||
}
|
||||
@@ -0,0 +1,28 @@
|
||||
<?php
|
||||
|
||||
namespace config;
|
||||
|
||||
use traits\module_config_variable;
|
||||
|
||||
class economic_payment_terms_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'economic',
|
||||
'paymentTermsNumber',
|
||||
'int',
|
||||
true,
|
||||
null,
|
||||
'The payment terms number to use when creating invoices',
|
||||
'1',
|
||||
false,
|
||||
1
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -113,7 +113,7 @@ class economicCustomers extends economic_m
|
||||
// Define filterable property groups
|
||||
$likeSupported = [
|
||||
'zip', 'customerNumber', 'customerGroup.customerGroupNumber', 'name', 'address',
|
||||
'city', 'country', 'email', 'telephoneAndFaxNumber', 'website', 'mobilePhone'
|
||||
'city', 'country', 'email', 'telephoneAndFaxNumber', 'website', 'mobilePhone', 'corporateIdentificationNumber'
|
||||
];
|
||||
|
||||
// If a search term is present, build the filter expressions
|
||||
|
||||
@@ -1,7 +1,9 @@
|
||||
<?php
|
||||
require_once WD . '/modules/economic/config/economic_invoice_layout_c.php';
|
||||
require_once WD . '/modules/economic/config/economic_payment_terms_c.php';
|
||||
|
||||
use config\economic_invoice_layout_c;
|
||||
use config\economic_payment_terms_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
class economic_c
|
||||
@@ -9,13 +11,16 @@ class economic_c
|
||||
use module_config_t;
|
||||
|
||||
public economic_invoice_layout_c $invoice_layout;
|
||||
public economic_payment_terms_c $payment_terms;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
$this->setupConfig('economic');
|
||||
$this->allowUpdate([
|
||||
economic_invoice_layout_c::class
|
||||
economic_invoice_layout_c::class,
|
||||
economic_payment_terms_c::class
|
||||
]);
|
||||
$this->invoice_layout = new economic_invoice_layout_c();
|
||||
$this->payment_terms = new economic_payment_terms_c();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
require_once WD . '/modules/economic/helpers/economic_customer.php';
|
||||
require_once WD . '/modules/economic/helpers/economic_invoice_draft.php';
|
||||
|
||||
|
||||
use helpers\economic_customer;
|
||||
use helpers\economic_invoice_draft;
|
||||
|
||||
class economic_helpers
|
||||
{
|
||||
/**
|
||||
* The Economic customer helper
|
||||
* @var string $economic_customer
|
||||
*/
|
||||
public string $economic_customer = economic_customer::class;
|
||||
/**
|
||||
* The Economic invoice draft helper
|
||||
* @var string $economic_invoice_draft
|
||||
*/
|
||||
public string $economic_invoice_draft = economic_invoice_draft::class;
|
||||
}
|
||||
-1
@@ -36,5 +36,4 @@ class economic_customers_endpoint
|
||||
// Return true if the customer exists
|
||||
return isset($tmp->customerNumber);
|
||||
}
|
||||
|
||||
}
|
||||
+66
-1
@@ -2,6 +2,9 @@
|
||||
|
||||
namespace endpoints\orders;
|
||||
|
||||
use classes\economic;
|
||||
use Exception;
|
||||
use objects\orders_o;
|
||||
use traits\economic_endpoint_t;
|
||||
|
||||
class economic_invoices_draft_endpoint
|
||||
@@ -12,7 +15,7 @@ class economic_invoices_draft_endpoint
|
||||
* Get draft invoice
|
||||
* @param int $invoice_id Invoice id to get
|
||||
* @return object {invoice}
|
||||
* @throws \Exception If the request fails
|
||||
* @throws Exception If the request fails
|
||||
*/
|
||||
public function get(int $invoice_id): object
|
||||
{
|
||||
@@ -23,4 +26,66 @@ class economic_invoices_draft_endpoint
|
||||
// Return the response as an object
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Get draft invoice from external id
|
||||
* @param string $external_id External id to get
|
||||
* @return int Invoice id
|
||||
* @throws Exception If the request fails
|
||||
* @throws Exception If the invoice is not found
|
||||
*/
|
||||
public function get_from_external_id(string $external_id): int
|
||||
{
|
||||
$response = $this->send_request(
|
||||
'/invoices/drafts?filter=references.other$eq:' . $external_id,
|
||||
'GET'
|
||||
);
|
||||
// Return the response as an object
|
||||
$response = json_decode($response);
|
||||
//var_dump($response);
|
||||
if (isset($response->collection[0])) {
|
||||
return $response->collection[0]->draftInvoiceNumber;
|
||||
} else {
|
||||
throw new Exception('Invoice draft with external id (' . $external_id . ') not found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an order to a draft invoice
|
||||
* @param int $invoiceDraftId The invoice draft id to add the order to
|
||||
* @param orders_o $order The order to add
|
||||
* @return void
|
||||
* @throws Exception If the request fails
|
||||
*/
|
||||
public function add_order(int $invoiceDraftId, orders_o $order): void
|
||||
{
|
||||
$draftInvoice = (new economic())->getInvoiceDraft($invoiceDraftId);
|
||||
// Add the transaction header (Timestamp, department, etc.)
|
||||
$draftInvoice->addNewTransactionHeader($order);
|
||||
// Add the order lines
|
||||
$draftInvoice->addOrderItemLines($order);
|
||||
// Add an empty line, so the invoice is not empty
|
||||
$draftInvoice->addTextLine('');
|
||||
// Save the draft invoice lines
|
||||
$draftInvoice->addLines();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add lines to a draft invoice
|
||||
* @param int $draft_invoice_number The draft invoice number
|
||||
* @param array $draft_lines The draft lines to add
|
||||
* @return object {draftInvoiceNumber: number, lines: [invoice_line]}
|
||||
*/
|
||||
public function add_lines(int $draft_invoice_number, array $draft_lines): object
|
||||
{
|
||||
$response = $this->send_request(
|
||||
'/invoices/drafts/' . $draft_invoice_number . '/lines',
|
||||
'POST',
|
||||
json_encode(
|
||||
['lines' => $draft_lines]
|
||||
)
|
||||
);
|
||||
return json_decode($response);
|
||||
}
|
||||
}
|
||||
+24
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace endpoints\orders;
|
||||
|
||||
use Exception;
|
||||
use traits\economic_endpoint_t;
|
||||
|
||||
class economic_invoices_booked_endpoint
|
||||
@@ -42,4 +43,27 @@ class economic_invoices_booked_endpoint
|
||||
return $tmp_invoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get booked invoice from external id
|
||||
* @param string $external_id External id to get
|
||||
* @return int Invoice id
|
||||
* @throws Exception If the request fails
|
||||
* @throws Exception If the invoice is not found
|
||||
*/
|
||||
public function get_from_external_id(string $external_id): int
|
||||
{
|
||||
$response = $this->send_request(
|
||||
'/invoices/booked?filter=references.other$eq:' . $external_id,
|
||||
'GET'
|
||||
);
|
||||
// Return the response as an object
|
||||
$response = json_decode($response);
|
||||
//var_dump($response);
|
||||
if (isset($response->collection[0])) {
|
||||
return $response->collection[0]->bookedInvoiceNumber;
|
||||
} else {
|
||||
throw new Exception('Invoice booked with external id (' . $external_id . ') not found');
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
+86
@@ -2,6 +2,8 @@
|
||||
|
||||
namespace endpoints\orders;
|
||||
|
||||
use classes\economic;
|
||||
use Exception;
|
||||
use traits\economic_endpoint_t;
|
||||
|
||||
class economic_invoices_drafts_endpoint
|
||||
@@ -43,4 +45,88 @@ class economic_invoices_drafts_endpoint
|
||||
return $tmp_invoices;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new invoice
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @param string $external_id The external id of the invoice
|
||||
* @return object {id: number, getExternalId: string}
|
||||
* @throws Exception If the request fails
|
||||
*/
|
||||
public function add(int $customer_number, string $external_id = ''): object
|
||||
{
|
||||
// Get the layout number
|
||||
$layout_number = (int)(new economic())->config->invoice_layout->getVariableValue();
|
||||
|
||||
// Get the date
|
||||
$date = date('Y-m-d');
|
||||
// Get the customer object
|
||||
$customer = (new economic())->getCustomer($customer_number);
|
||||
|
||||
// Set the recipient details
|
||||
$customer_name = $customer->getName() ?? 'Ukendt';
|
||||
$customer_address = $customer->getAddress() ?? 'Ukendt';
|
||||
$customer_zip = $customer->getZipCode() ?? 'Ukendt';
|
||||
$customer_city = $customer->getCity() ?? 'Ukendt';
|
||||
|
||||
// Send the request
|
||||
$response = $this->send_request(
|
||||
'/invoices/drafts/',
|
||||
'POST',
|
||||
json_encode([
|
||||
// Set the layout number (This is defined in the E-conomic module settings)
|
||||
'layout' => [
|
||||
'layoutNumber' => $layout_number
|
||||
],
|
||||
|
||||
// Set the date to today
|
||||
'date' => $date,
|
||||
|
||||
// Set the payment terms to the default payment terms (This is defined in the E-conomic module settings)
|
||||
'paymentTerms' => [
|
||||
'paymentTermsNumber' => (int)$customer->getPaymentTermsNumber(),
|
||||
],
|
||||
|
||||
// Set the customer number
|
||||
'customer' => [
|
||||
'customerNumber' => $customer_number
|
||||
],
|
||||
|
||||
// Set the external id (This is used to link the invoice to the collected order invoice)
|
||||
'references' => [
|
||||
'other' => $external_id
|
||||
],
|
||||
|
||||
// Set the currency TODO: Make this dynamic
|
||||
'currency' => 'DKK',
|
||||
|
||||
// Set the recipient details
|
||||
'recipient' => [
|
||||
'name' => $customer_name,
|
||||
'address' => $customer_address,
|
||||
'zip' => $customer_zip,
|
||||
'city' => $customer_city,
|
||||
'vatZone' => [
|
||||
'vatZoneNumber' => 1
|
||||
],
|
||||
],
|
||||
])
|
||||
);
|
||||
// Return the response as an object
|
||||
return json_decode($response);
|
||||
}
|
||||
|
||||
public function exists(int $draft_invoice_number): bool
|
||||
{
|
||||
$response = $this->send_request(
|
||||
'/invoices/drafts/' . $draft_invoice_number,
|
||||
'GET'
|
||||
);
|
||||
// Return the response as an object
|
||||
try {
|
||||
return json_decode($response)->draftInvoiceNumber == $draft_invoice_number;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,207 @@
|
||||
<?php
|
||||
|
||||
namespace helpers;
|
||||
|
||||
use classes\economic;
|
||||
use Exception;
|
||||
|
||||
class economic_customer
|
||||
{
|
||||
/**
|
||||
* The Economic customerNumber, which is the unique identifier for a customer
|
||||
* @var int $customer_number
|
||||
*/
|
||||
protected int $customer_number;
|
||||
/**
|
||||
* The raw customer data from the Economic API
|
||||
* @var object $customer_data
|
||||
*/
|
||||
protected object $customer_data_object;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new Economic customer object
|
||||
* @throws Exception if the customer does not exist
|
||||
*/
|
||||
public function __construct(int $customer_number)
|
||||
{
|
||||
self::setCustomerNumber($customer_number);
|
||||
self::requireExists();
|
||||
self::fetchCustomerData();
|
||||
self::requireSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a customer exists
|
||||
* @param int $customer_number The Economic customer number to check for
|
||||
* @throws Exception if the customer does not exist
|
||||
*/
|
||||
protected function requireExists(): void
|
||||
{
|
||||
if (!self::exists()) {
|
||||
throw new Exception('The customer does not exist in the Economic system');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a customer exists in the Economic system
|
||||
* @return bool True if the customer exists, false if not
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
// Make sure the customer number is set
|
||||
self::requireCustomerNumber();
|
||||
// Check if the customer exists
|
||||
$economic = new economic();
|
||||
return $economic->customers->customers->exists(self::getCustomerNumber());
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the customer number is set
|
||||
* @throws Exception if the customer number is not set
|
||||
*/
|
||||
protected function requireCustomerNumber(): void
|
||||
{
|
||||
if (!isset($this->customer_number)) {
|
||||
throw new Exception('The customer number is not set');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer number
|
||||
* @return int The Economic customer number
|
||||
*/
|
||||
public function getCustomerNumber(): int
|
||||
{
|
||||
return $this->customer_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the customer number
|
||||
* @param int $customer_number The Economic customer number
|
||||
*/
|
||||
protected function setCustomerNumber(int $customer_number): void
|
||||
{
|
||||
|
||||
$this->customer_number = $customer_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the customer data from the Economic API and store it in the object property $customer_data_object
|
||||
* @throws Exception if the customer data could not be fetched
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
protected function fetchCustomerData(): void
|
||||
{
|
||||
// Get the customer data from the Economic API
|
||||
$economic = new economic();
|
||||
$tmp = $economic->customers->customers->get($this->customer_number);
|
||||
// Check if the customer data is invalid or empty
|
||||
if (!isset($tmp->customerNumber)) {
|
||||
throw new Exception('The customer data is invalid or empty');
|
||||
}
|
||||
// Store the customer data in the object property
|
||||
$this->customer_data_object = $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that a customer is selected, i.e. that the customer data is valid and not empty
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
protected function requireSelected(): void
|
||||
{
|
||||
if (!isset($this->customer_data_object->customerNumber)) {
|
||||
throw new Exception('The customer data is invalid or empty');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer data as an object
|
||||
* @return object The customer data as an object
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function asObject(): object
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer name
|
||||
* @return string The customer name
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getName(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer email
|
||||
* @return string The customer email
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getEmail(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->email;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer address
|
||||
* @return string The customer address
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getAddress(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->address;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer postal code
|
||||
* @return string The customer postal code
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getZipCode(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->zip;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer city
|
||||
* @return string The customer city
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getCity(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->city;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer country
|
||||
* @return string The customer country
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getCountry(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->country;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customers payment terms number
|
||||
* @return int The customers payment terms number
|
||||
* @throws Exception if the customer data is invalid or empty
|
||||
*/
|
||||
public function getPaymentTermsNumber(): int
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->customer_data_object->paymentTerms->paymentTermsNumber;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
|
||||
namespace helpers;
|
||||
|
||||
use classes\economic;
|
||||
use Exception;
|
||||
use objects\departments_o;
|
||||
use objects\orders_o;
|
||||
|
||||
class economic_invoice_draft
|
||||
{
|
||||
/**
|
||||
* The Economic draftInvoiceNumber
|
||||
* @var int $draft_invoice_number
|
||||
*/
|
||||
protected int $draft_invoice_number;
|
||||
|
||||
/**
|
||||
* The draft lines
|
||||
* @var array $draft_lines
|
||||
*/
|
||||
protected array $draft_lines = [];
|
||||
|
||||
/**
|
||||
* The raw draft invoice data
|
||||
* @var object $draft_invoice_data
|
||||
*/
|
||||
protected object $draft_invoice_data;
|
||||
|
||||
|
||||
/**
|
||||
* Construct a new Economic draft invoice object
|
||||
* @throws Exception if the invoice data is invalid or empty
|
||||
*/
|
||||
public function __construct(int $draft_invoice_number)
|
||||
{
|
||||
$this->setDraftInvoiceNumber($draft_invoice_number);
|
||||
$this->fetchDraftInvoiceData();
|
||||
$this->requireSelected();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the draft invoice number
|
||||
* @param int $draft_invoice_number
|
||||
* @return void
|
||||
*/
|
||||
private function setDraftInvoiceNumber(int $draft_invoice_number): void
|
||||
{
|
||||
$this->draft_invoice_number = $draft_invoice_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Fetch the draft invoice data from the Economic system
|
||||
* @throws Exception If the request fails
|
||||
* @throws Exception If the invoice is not found
|
||||
*/
|
||||
private function fetchDraftInvoiceData(): void
|
||||
{
|
||||
$economic = new economic();
|
||||
$this->draft_invoice_data = $economic->invoices->draft->get($this->draft_invoice_number);
|
||||
if (!isset($this->draft_invoice_data->draftInvoiceNumber)) {
|
||||
throw new Exception('Draft invoice not found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the draft invoice data is selected
|
||||
* @throws Exception if the draft invoice data is not set
|
||||
*/
|
||||
protected function requireSelected(): void
|
||||
{
|
||||
if (!isset($this->draft_invoice_data->draftInvoiceNumber)) {
|
||||
throw new Exception('The draft invoice data is not set');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the lines to the draft invoice
|
||||
* @return void
|
||||
*/
|
||||
public function addLines(): void
|
||||
{
|
||||
$economic = new economic();
|
||||
$economic->invoices->draft->add_lines($this->draft_invoice_number, $this->draft_lines);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the draft invoice number
|
||||
* @return int The draft invoice number
|
||||
*/
|
||||
public function getDraftInvoiceNumber(): int
|
||||
{
|
||||
return $this->draft_invoice_number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a new transaction header to the draft invoice
|
||||
* @note The lines won't be saved until the addLines() method is called.
|
||||
* @note This is the "[28/02/2025 18:29 Roskilde #685]" line in the invoice
|
||||
* @param orders_o $order The order to add
|
||||
* @return void
|
||||
*/
|
||||
public function addNewTransactionHeader(orders_o $order): void
|
||||
{
|
||||
// Get the department name
|
||||
$department_name = (new departments_o())->getDepartmentName((int)$order->department_id->value());
|
||||
// Parse the date of the transaction.
|
||||
$parsed_date = date('d/m/Y H:i', strtotime($order->created_at->value()));
|
||||
// Add the text line to the draft invoice
|
||||
self::addTextLine("[ " . $parsed_date . ' ' . $department_name . ' #' . $order->id . " ]");
|
||||
// If there's a reference, add it to the invoice
|
||||
if ($order->reference->value() !== '') {
|
||||
self::addTextLine('Reference:');
|
||||
// Add "# " in the beginning of each line (If there's more than one line, otherwise we just add the prefix once)
|
||||
if (str_contains($order->reference->value(), "\n")) {
|
||||
foreach ( explode("\n", $order->reference->value()) as $line ) {
|
||||
self::addTextLine('# ' . $line);
|
||||
}
|
||||
} else {
|
||||
self::addTextLine('# ' . $order->reference->value());
|
||||
}
|
||||
}
|
||||
// Add the registration numbers (if any)
|
||||
$line_reg = '';
|
||||
if ($order->reg_1->value() !== '')
|
||||
$line_reg .= 'Reg 1: ' . strtoupper($order->reg_1->value());
|
||||
if ($order->reg_2->value() !== '')
|
||||
$line_reg .= ', Reg 2: ' . strtoupper($order->reg_2->value());
|
||||
if ($order->reg_3->value() !== '')
|
||||
$line_reg .= ', Reg 3: ' . strtoupper($order->reg_3->value());
|
||||
// Add the line to the invoice (If there's any registration numbers)
|
||||
if ($line_reg !== '')
|
||||
self::addTextLine($line_reg);
|
||||
// If there's a note, add it to the invoice
|
||||
if ($order->notes->value() !== '') {
|
||||
self::addTextLine('Notat:');
|
||||
// Add "# " in the beginning of each line (If there's more than one line, otherwise we just add the prefix once)
|
||||
if (str_contains($order->notes->value(), "\n")) {
|
||||
foreach ( explode("\n", $order->notes->value()) as $line ) {
|
||||
self::addTextLine('# ' . $line);
|
||||
}
|
||||
} else {
|
||||
self::addTextLine('# ' . $order->notes->value());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a text line to the draft invoice
|
||||
* @note The lines won't be saved until the addLines() method is called.
|
||||
* @param string $text The text to add
|
||||
* @return void
|
||||
*/
|
||||
public function addTextLine(string $text): void
|
||||
{
|
||||
$this->draft_lines[] = [
|
||||
'description' => $text
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an order to the draft invoice
|
||||
* @note The lines won't be saved until the addLines() method is called.
|
||||
* @param orders_o $order The order to add
|
||||
* @return void
|
||||
* @throws Exception if the order is not found
|
||||
* @throws Exception if the order is not valid
|
||||
*/
|
||||
public function addOrderItemLines(orders_o $order): void
|
||||
{
|
||||
// Get the order items
|
||||
$order_items = $order->getOrderItems($order->id);
|
||||
// Apply the department pricing
|
||||
$order_items = $order->applyDepartmentPrices($order_items, $order->department_id->value());
|
||||
// Get the department
|
||||
$department = $order->getDepartmentByOrderId($order->id);
|
||||
// Loop through the order items
|
||||
foreach ( $order_items as $order_item ) {
|
||||
// Add the order item to the draft invoice
|
||||
self::addOrderItemLine($order_item, $department);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an order item line to the draft invoice
|
||||
* @note The lines won't be saved until the addLines() method is called.
|
||||
* @param array $order_item The order item to add
|
||||
* @param array $department The department to add
|
||||
* @return void
|
||||
* @throws Exception if the order item is not found
|
||||
* @throws Exception if the order item is not valid
|
||||
*/
|
||||
public function addOrderItemLine(array $order_item, array $department): void
|
||||
{
|
||||
// Check if the order item is valid
|
||||
if (!isset($order_item['id'])) {
|
||||
throw new Exception('The order item is not valid');
|
||||
}
|
||||
// Get the department id
|
||||
$economic_department_id = $department['economic_department_id'];
|
||||
// Get the dimension id
|
||||
$economic_dimension_id = $department['economic_dimension_id'] ?? 0;
|
||||
// Add the order item to the draft invoice
|
||||
self::addProductLine(
|
||||
(string)$order_item['product']['economic_product_id'],
|
||||
(string)$order_item['product']['name'],
|
||||
(int)$order_item['quantity'] ?? 1,
|
||||
(int)$order_item['price'],
|
||||
$economic_department_id,
|
||||
$economic_dimension_id
|
||||
);
|
||||
|
||||
// Calculate the discount percentage
|
||||
$discountPercentage = round((($order_item['product']['price'] - $order_item['price']) / $order_item['product']['price']) * 100, 0);
|
||||
|
||||
// If the price is different from the product price, add it to the line
|
||||
if ($order_item['price'] !== $order_item['product']['price'])
|
||||
self::addTextLine('Rabat: ' . ($order_item['price'] - $order_item['product']['price']) . ' DKK (' . $discountPercentage . '%)');
|
||||
|
||||
// If there's a reference, add it to the line
|
||||
if ($order_item['reference'] !== '') {
|
||||
self::addTextLine('Reference:');
|
||||
// Add "# " in the beginning of each line (If there's more than one line, otherwise we just add the prefix once)
|
||||
if (str_contains($order_item['reference'], "\n")) {
|
||||
foreach ( explode("\n", $order_item['reference']) as $line ) {
|
||||
self::addTextLine('# ' . $line);
|
||||
}
|
||||
} else {
|
||||
self::addTextLine('# ' . $order_item['reference']);
|
||||
}
|
||||
}
|
||||
|
||||
// If there's a note, add it to the line
|
||||
if (!empty($order_item['notes'])) {
|
||||
self::addTextLine('Notat:');
|
||||
// Add "# " in the beginning of each line (If there's more than one line, otherwise we just add the prefix once)
|
||||
if (str_contains($order_item['notes'], "\n")) {
|
||||
foreach ( explode("\n", $order_item['notes']) as $line ) {
|
||||
self::addTextLine('# ' . $line);
|
||||
}
|
||||
} else {
|
||||
self::addTextLine('# ' . $order_item['notes']);
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a product line to the draft invoice
|
||||
* @note The lines won't be saved until the addLines() method is called.
|
||||
*/
|
||||
public function addProductLine(string $productNumber, string $description, float $quantity, float $unitNetPrice, int $economic_department_id, int $dimension): void
|
||||
{
|
||||
// We then add a 0 in front of the product number to make sure it's the right one, made by FlexPOS.
|
||||
// Add a line to the invoice
|
||||
$line = [
|
||||
'product' => [
|
||||
'productNumber' => $productNumber,
|
||||
],
|
||||
'quantity' => $quantity,
|
||||
'unitNetPrice' => $unitNetPrice,
|
||||
'discountPercentage' => 0,
|
||||
'description' => $description,
|
||||
];
|
||||
// If the department is set, add it to the line
|
||||
if ($economic_department_id) {
|
||||
$line['departmentalDistribution'] = [
|
||||
'departmentalDistributionNumber' => $economic_department_id,
|
||||
'DistributionType' => 'Department',
|
||||
'dimension' => $dimension
|
||||
];
|
||||
}
|
||||
$this->draft_lines[] = $line;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a draft invoice exists in the Economic system
|
||||
* @throws Exception if the draft invoice does not exist
|
||||
*/
|
||||
protected function requireExists(): void
|
||||
{
|
||||
if (!self::exists()) {
|
||||
throw new Exception('The draft invoice does not exist');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a customer exists in the Economic system
|
||||
* @return bool True if the customer exists, false if not
|
||||
* @throws Exception
|
||||
*/
|
||||
public function exists(): bool
|
||||
{
|
||||
// Make sure the draft invoice number is set before calling
|
||||
self::requireDraftInvoiceNumber();
|
||||
// Check if the draft invoice exists
|
||||
$economic = new economic();
|
||||
return $economic->invoices->drafts->exists($this->draft_invoice_number);
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the draft invoice number is set
|
||||
* @throws Exception if the draft invoice number is not set
|
||||
*/
|
||||
protected function requireDraftInvoiceNumber(): void
|
||||
{
|
||||
if (!isset($this->draft_invoice_number)) {
|
||||
throw new Exception('The draft invoice number is not set');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Require that the draft invoice data is set
|
||||
* @throws Exception if the draft invoice data is not set
|
||||
*/
|
||||
protected function requireDraftInvoiceData(): void
|
||||
{
|
||||
if (!isset($this->draft_invoice_data)) {
|
||||
throw new Exception('The draft invoice data is not set');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_mailersend_api_key_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'mailersend_api_key',
|
||||
'string',
|
||||
false,
|
||||
null,
|
||||
'The API key for the MailerSend email service',
|
||||
'mlsn.7dd13651...',
|
||||
true,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_mailersend_enabled_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'mailersend_enabled',
|
||||
'bool',
|
||||
true,
|
||||
null,
|
||||
'Whether the email service should use MailerSend for sending emails',
|
||||
'1',
|
||||
false,
|
||||
'false'
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_smtp_reply_to_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'smtp_reply_to',
|
||||
'string',
|
||||
true,
|
||||
null,
|
||||
'The email address to reply to',
|
||||
'user@example.com',
|
||||
false,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace email\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class email_smtp_reply_to_name_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Email',
|
||||
'smtp_reply_to_name',
|
||||
'string',
|
||||
true,
|
||||
null,
|
||||
'The name to reply to',
|
||||
'Company Name Support',
|
||||
false,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -1,22 +1,34 @@
|
||||
<?php
|
||||
|
||||
namespace email;
|
||||
/** Universal */
|
||||
require_once WD . '/modules/email/config/email_enabled_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_name_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_reply_to_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_reply_to_name_c.php';
|
||||
|
||||
/** SMTP */
|
||||
require_once WD . '/modules/email/config/email_smtp_encryption_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_host_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_password_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_port_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_username_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_c.php';
|
||||
require_once WD . '/modules/email/config/email_smtp_from_name_c.php';
|
||||
/** Mailersend */
|
||||
require_once WD . '/modules/email/config/email_mailersend_enabled_c.php';
|
||||
require_once WD . '/modules/email/config/email_mailersend_api_key_c.php';
|
||||
|
||||
use email\config\email_enabled_c;
|
||||
use email\config\email_mailersend_api_key_c;
|
||||
use email\config\email_mailersend_enabled_c;
|
||||
use email\config\email_smtp_encryption_c;
|
||||
use email\config\email_smtp_from_c;
|
||||
use email\config\email_smtp_from_name_c;
|
||||
use email\config\email_smtp_host_c;
|
||||
use email\config\email_smtp_password_c;
|
||||
use email\config\email_smtp_port_c;
|
||||
use email\config\email_smtp_reply_to_c;
|
||||
use email\config\email_smtp_reply_to_name_c;
|
||||
use email\config\email_smtp_username_c;
|
||||
use traits\module_config_t;
|
||||
|
||||
@@ -72,6 +84,29 @@ class email_c
|
||||
*/
|
||||
public email_smtp_from_name_c $smtp_from_name;
|
||||
|
||||
/**
|
||||
* The status of Mailersend, whether it is enabled or not
|
||||
* @var email_mailersend_enabled_c
|
||||
*/
|
||||
public email_mailersend_enabled_c $mailersend_enabled;
|
||||
|
||||
/**
|
||||
* The API key for the Mailersend email service
|
||||
* @var email_mailersend_api_key_c
|
||||
*/
|
||||
public email_mailersend_api_key_c $mailersend_api_key;
|
||||
|
||||
/**
|
||||
* The email address to reply to
|
||||
* @var email_smtp_reply_to_c The email address to reply to
|
||||
*/
|
||||
public email_smtp_reply_to_c $smtp_reply_to;
|
||||
/**
|
||||
* The name to reply to
|
||||
* @var email_smtp_reply_to_name_c The name to reply to
|
||||
*/
|
||||
public email_smtp_reply_to_name_c $smtp_reply_to_name;
|
||||
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -84,7 +119,11 @@ class email_c
|
||||
email_smtp_password_c::class,
|
||||
email_smtp_encryption_c::class,
|
||||
email_smtp_from_c::class,
|
||||
email_smtp_from_name_c::class
|
||||
email_smtp_from_name_c::class,
|
||||
email_mailersend_enabled_c::class,
|
||||
email_mailersend_api_key_c::class,
|
||||
email_smtp_reply_to_c::class,
|
||||
email_smtp_reply_to_name_c::class
|
||||
]);
|
||||
$this->enabled = new email_enabled_c();
|
||||
$this->smtp_host = new email_smtp_host_c();
|
||||
@@ -94,6 +133,10 @@ class email_c
|
||||
$this->smtp_encryption = new email_smtp_encryption_c();
|
||||
$this->smtp_from = new email_smtp_from_c();
|
||||
$this->smtp_from_name = new email_smtp_from_name_c();
|
||||
$this->mailersend_enabled = new email_mailersend_enabled_c();
|
||||
$this->mailersend_api_key = new email_mailersend_api_key_c();
|
||||
$this->smtp_reply_to = new email_smtp_reply_to_c();
|
||||
$this->smtp_reply_to_name = new email_smtp_reply_to_name_c();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,12 @@
|
||||
<?php
|
||||
|
||||
namespace email\helpers;
|
||||
|
||||
trait email_template
|
||||
{
|
||||
protected string $subject;
|
||||
|
||||
abstract function generate_html(): string;
|
||||
|
||||
abstract function generate_text(): string;
|
||||
}
|
||||
@@ -0,0 +1,40 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_footer
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "Truckwash ApS | CVR: 41004355 | https://truckwash.dk | Send os en email på cph@truckwash.dk - Ring til os på (+45) 43 71 78 86";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Footer -->
|
||||
<br><br>
|
||||
<div style="max-width: 600px;">
|
||||
<img src="https://usercontent.one/wp/www.truckwash.dk/wp-content/uploads/2021/04/truckwash-banner-png.png"
|
||||
alt="Truck Wash logo" style="width: 25%; height: auto; display: block; margin: 0 auto;">
|
||||
<p style="text-align: center;"><a href="https://truckwash.dk/">Truckwash ApS</a> | <a
|
||||
href="https://datacvr.virk.dk/enhed/virksomhed/41004355"> CVR: 41004355</a> | <a
|
||||
href="https://truckwash.dk/">https://truckwash.dk</a></p>
|
||||
<p style="text-align: center;"><a href="mailto:cph@truckwash.dk"
|
||||
style="color: black; text-decoration: none;">Send os en email på
|
||||
cph@truckwash.dk</a> - <a href="tel:+4543717886" style="color: black; text-decoration: none;">Ring
|
||||
til os på (+45) 43 71 78 86</a></p>
|
||||
</div>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,45 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_head
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
<!-- Styles -->
|
||||
<style>
|
||||
.email-template {
|
||||
width: 100%;
|
||||
max-width: 600px;
|
||||
margin: 0 auto;
|
||||
padding: 20px;
|
||||
background-color: #f9f9f9;
|
||||
font-family: Arial, sans-serif;
|
||||
}
|
||||
|
||||
.email-template h1 {
|
||||
color: #333;
|
||||
}
|
||||
|
||||
.email-template p {
|
||||
color: #333;
|
||||
}
|
||||
</style>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_header
|
||||
{
|
||||
use email_template;
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Logo -->
|
||||
<div style="max-width: 600px;">
|
||||
<img src="https://usercontent.one/wp/www.truckwash.dk/wp-content/uploads/2021/04/truckwash-banner-png.png"
|
||||
alt="Truck Wash logo"
|
||||
style="width: 100%; max-width: 600px; height: auto; display: block; margin: 0 auto;">
|
||||
</div>
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace email\templates;
|
||||
|
||||
use email\helpers\email_template;
|
||||
|
||||
class email_template_stripe_invoice
|
||||
{
|
||||
use email_template;
|
||||
|
||||
protected int $order_id;
|
||||
protected string $stripe_payment_link;
|
||||
protected string $name;
|
||||
|
||||
public function __construct(int $order_id, string $stripe_payment_link, string $name)
|
||||
{
|
||||
$this->order_id = $order_id;
|
||||
$this->stripe_payment_link = $stripe_payment_link;
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
public function generate_text(): string
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
public function generate_html(): string
|
||||
{
|
||||
ob_start();
|
||||
# Start of the html
|
||||
?>
|
||||
|
||||
<!-- Email template -->
|
||||
<p>Kære <?= $this->name ?>,</p>
|
||||
<p>Tak for din bestilling hos Truck Wash. Vi har sendt dig en faktura på Stripe.
|
||||
Du kan betale fakturaen ved at klikke på linket nedenfor:</p>
|
||||
<p><a href="<?= $this->stripe_payment_link ?>">Betal faktura for ordre <?= $this->order_id ?></a></p>
|
||||
<!-- End of the email template -->
|
||||
|
||||
<?php
|
||||
# End of the html
|
||||
return ob_get_clean();
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
<?php
|
||||
|
||||
namespace forms;
|
||||
|
||||
use traits\form_t;
|
||||
|
||||
class book_wash_f extends form_helper_c
|
||||
{
|
||||
use form_t;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function sanitize(): void
|
||||
{
|
||||
foreach ( $this->form_unsanitized_data as $key => $value ) {
|
||||
// Sanitize the input TODO: Implement the sanitization logic
|
||||
$this->form_unsanitized_data[$key] = $value;
|
||||
}
|
||||
// Set the sanitized data
|
||||
$this->form_sanitized_data = $this->form_unsanitized_data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function validateInput(): void
|
||||
{
|
||||
// TODO: Implement validateInput() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function afterSubmit(): void
|
||||
{
|
||||
// TODO: Implement afterSubmit() method.
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function setup(): void
|
||||
{
|
||||
self::setFormIdentifier('BOOK_WASH');
|
||||
self::setFormName('Book a wash');
|
||||
self::setFormDescription('This form is used to book a wash for a vehicle.');
|
||||
// Set the form fields
|
||||
self::defineInputFields([
|
||||
'customer_number' => self::className() . '::validateCustomerNumber',
|
||||
'contact_email' => self::className() . '::validateEmail',
|
||||
'reference' => self::className() . '::validateString',
|
||||
'registration_number_tractor' => self::className() . '::validateRegistrationNumber',
|
||||
'registration_number_trailer' => self::className() . '::validateRegistrationNumber',
|
||||
'wants_wash_certificate' => self::className() . '::validateBoolean',
|
||||
'wants_wash_certificate_email' => self::className() . '::validateEmail',
|
||||
'date' => self::className() . '::validateDate',
|
||||
'department_id' => self::className() . '::validateInt',
|
||||
'wants_pickup' => self::className() . '::validateBoolean',
|
||||
'notes' => self::className() . '::validateString',
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,7 @@
|
||||
<?php
|
||||
|
||||
namespace forms;
|
||||
|
||||
abstract class form_helper_c
|
||||
{
|
||||
}
|
||||
@@ -0,0 +1,68 @@
|
||||
<?php
|
||||
|
||||
namespace motorapi\actions;
|
||||
|
||||
use Exception;
|
||||
use traits\module_action_t;
|
||||
|
||||
class license_plate_lookup_a
|
||||
{
|
||||
use module_action_t;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
* @throws Exception If the module name is invalid
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
self::set_module_name('MOTORAPI');
|
||||
|
||||
/** Add the action to the list of valid actions */
|
||||
// LICENSE_PLATE_LOOKUP
|
||||
self::add_action(
|
||||
'LICENSE_PLATE_LOOKUP',
|
||||
'This action is when a license plate lookup request is made',
|
||||
// Method to call
|
||||
self::class . '::license_plate_lookup',
|
||||
[
|
||||
'license_plate' => 'The license plate that was looked up',
|
||||
'data' => 'The data returned from the lookup (If any)',
|
||||
'status_code' => 'The status code of the action',
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* License plate lookup action
|
||||
* @param string $license_plate The license plate that was looked up
|
||||
* @param array|object $data The data returned from the lookup (If any)
|
||||
* @param int $status_code The status code of the action
|
||||
* @throws Exception If the action name is invalid
|
||||
* @throws Exception If the action data is invalid
|
||||
* @throws Exception If the action status code is invalid
|
||||
* @throws Exception If the action is not valid
|
||||
*/
|
||||
public function license_plate_lookup(string $license_plate, array|object $data = [], int $status_code = 0): void
|
||||
{
|
||||
self::set_action('LICENSE_PLATE_LOOKUP');
|
||||
// If the data is an object, convert it to an array
|
||||
if (is_object($data)) {
|
||||
$data = (array)$data;
|
||||
}
|
||||
// Validate the action data
|
||||
if (!is_array($data)) {
|
||||
throw new Exception('Action data is invalid');
|
||||
}
|
||||
// Validate the action status code
|
||||
self::set_data([
|
||||
'license_plate' => $license_plate,
|
||||
'data' => $data,
|
||||
]);
|
||||
self::set_status($status_code);
|
||||
// Add the action to the log
|
||||
self::add_action_log(
|
||||
self::get_action_name(),
|
||||
(int)self::get_status(),
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,17 @@
|
||||
<?php
|
||||
|
||||
namespace motorapi\helpers;
|
||||
|
||||
class motorapi_vehicle_types
|
||||
{
|
||||
/**
|
||||
* Personbil
|
||||
* @var string
|
||||
*/
|
||||
public string $PLATE_TYPE_CAR = 'Personbil';
|
||||
/**
|
||||
* Lastbil
|
||||
* @var string
|
||||
*/
|
||||
public string $PLATE_TYPE_TRUCK = 'Lastbil';
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
trait notification_type_t
|
||||
{
|
||||
/**
|
||||
* The name of the notification type
|
||||
* @var string
|
||||
*/
|
||||
public string $name;
|
||||
/**
|
||||
* The description of the notification type
|
||||
* @var string
|
||||
*/
|
||||
public string $description;
|
||||
/**
|
||||
* The type of the notification
|
||||
* @notation This is the identifier of the notification type, it is used to identify the notification type in the system.
|
||||
* @var string
|
||||
*/
|
||||
public string $type;
|
||||
|
||||
|
||||
/**
|
||||
* The constructor of the notification type
|
||||
* @throws Exception If the id is not set
|
||||
* @throws Exception If the name is not set
|
||||
* @throws Exception If the description is not set
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::run();
|
||||
self::validate();
|
||||
}
|
||||
|
||||
/**
|
||||
* The run method, to be implemented by the class using this trait
|
||||
* @notation This method should be implemented in the class using this trait, it is not meant to be called directly. It will be called when the notification type is triggered.
|
||||
* @throws Exception If type is not set
|
||||
* @throws Exception If name is not set
|
||||
* @throws Exception If description is not set
|
||||
*/
|
||||
abstract public function run(): void;
|
||||
|
||||
/**
|
||||
* Validate the notification type
|
||||
* @throws Exception If the type is not set
|
||||
* @throws Exception If the name is not set
|
||||
* @throws Exception If the description is not set
|
||||
*/
|
||||
public function validate(): void
|
||||
{
|
||||
if (!isset($this->type)) {
|
||||
throw new Exception('The type is not set');
|
||||
}
|
||||
if (empty($this->name)) {
|
||||
throw new Exception('The name is not set');
|
||||
}
|
||||
if (empty($this->description)) {
|
||||
throw new Exception('The description is not set');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the type of the notification
|
||||
* @param string $type
|
||||
* @throws Exception If the type is empty
|
||||
* @throws Exception If the type is not a string
|
||||
* @throws Exception If the type is not a valid format (e.g. "TYPE_NAME")
|
||||
*/
|
||||
public function set_type(string $type): void
|
||||
{
|
||||
if (empty($type)) {
|
||||
throw new Exception('The type is empty');
|
||||
}
|
||||
if (!preg_match('/^[A-Z_]+$/', $type)) {
|
||||
throw new Exception('The type is not a valid format (e.g. "TYPE_NAME")');
|
||||
}
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the notification type
|
||||
* @param string $name
|
||||
* @throws Exception If the name is empty
|
||||
*/
|
||||
public function set_name(string $name): void
|
||||
{
|
||||
if (empty($name)) {
|
||||
throw new Exception('The name is empty');
|
||||
}
|
||||
$this->name = $name;
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the description of the notification type
|
||||
* @param string $description
|
||||
* @throws Exception If the description is empty
|
||||
*/
|
||||
public function set_description(string $description): void
|
||||
{
|
||||
if (empty($description)) {
|
||||
throw new Exception('The description is empty');
|
||||
}
|
||||
$this->description = $description;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification type as an array
|
||||
* @return array
|
||||
*/
|
||||
public function as_array(): array
|
||||
{
|
||||
return [
|
||||
'type' => $this->type,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'data' => self::get_data(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the data of the notification type
|
||||
* @notation This takes all data_* properties and returns them as an array
|
||||
* @return array
|
||||
*/
|
||||
public function get_data(): array
|
||||
{
|
||||
// Get all the properties of the class
|
||||
$properties = get_object_vars($this);
|
||||
// Filter the properties to only include those that start with "data_"
|
||||
$data_properties = array_filter($properties, function ($key) {
|
||||
return str_starts_with($key, 'data_');
|
||||
}, ARRAY_FILTER_USE_KEY);
|
||||
// Remove the "data_" prefix from the keys
|
||||
// Return the data properties as an array
|
||||
return array_combine(
|
||||
array_map(function ($key) {
|
||||
return substr($key, 5);
|
||||
}, array_keys($data_properties)),
|
||||
array_values($data_properties)
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the notification type as an object
|
||||
* @return object
|
||||
*/
|
||||
public function as_object(): object
|
||||
{
|
||||
return (object)[
|
||||
'type' => $this->type,
|
||||
'name' => $this->name,
|
||||
'description' => $this->description,
|
||||
'data' => self::get_data(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace types;
|
||||
|
||||
use notification_type_t;
|
||||
|
||||
class notifications_type_new_booking_c
|
||||
{
|
||||
use notification_type_t;
|
||||
|
||||
/**
|
||||
* The id of the booking
|
||||
* @var int $data_booking_id The id of the booking
|
||||
*/
|
||||
public int $data_booking_id;
|
||||
|
||||
/**
|
||||
* @inheritDoc
|
||||
*/
|
||||
public function run(): void
|
||||
{
|
||||
self::set_type('NEW_BOOKING');
|
||||
self::set_description('This notification is sent when a new booking is created');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace stripe\config;
|
||||
|
||||
use Exception;
|
||||
use traits\module_config_variable;
|
||||
|
||||
class stripe_economic_customer_number_c
|
||||
{
|
||||
use module_config_variable;
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function __construct()
|
||||
{
|
||||
self::setupConfigVariable(
|
||||
'Stripe',
|
||||
'economic_customer_number',
|
||||
'int',
|
||||
true,
|
||||
null,
|
||||
'The Economic customer number, to be used for invoicing',
|
||||
'1',
|
||||
false,
|
||||
''
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -19,9 +19,11 @@ class stripe_endpoint_customers
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create(array $data): Customer
|
||||
public function create(string $email): Customer
|
||||
{
|
||||
return self::getClient()->customers->create($data);
|
||||
return self::getClient()->customers->create([
|
||||
'email' => $email
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -0,0 +1,99 @@
|
||||
<?php
|
||||
|
||||
namespace stripe\endpoints;
|
||||
|
||||
use Exception;
|
||||
use objects\orders_o;
|
||||
use Stripe\Exception\ApiErrorException;
|
||||
use stripe\helpers\stripe_line_item;
|
||||
use stripe\helpers\stripe_line_items;
|
||||
use Stripe\Invoice;
|
||||
use traits\stripe_endpoint_t;
|
||||
|
||||
class stripe_endpoint_invoice
|
||||
{
|
||||
use stripe_endpoint_t;
|
||||
|
||||
/**
|
||||
* Retrieve a payment link
|
||||
* @param string $id
|
||||
* @return Invoice
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function retrieve(string $id): Invoice
|
||||
{
|
||||
return self::getClient()->invoices->retrieve($id);
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function generate(int $order_id, string $stripe_customer_id): Invoice
|
||||
{
|
||||
$order = (new orders_o())->select($order_id);
|
||||
$order->requireSelected();
|
||||
// Get the order items
|
||||
$order_items = $order->getOrderItems($order_id);
|
||||
// Create a new line items object
|
||||
$line_items = new stripe_line_items('invoice');
|
||||
// Loop through the order items
|
||||
foreach ( $order_items as $order_item ) {
|
||||
// Add the order item to the line items
|
||||
$line_items->add(
|
||||
new stripe_line_item(
|
||||
$order_item['product_id'],
|
||||
$order_item['price'],
|
||||
$order_item['quantity']
|
||||
)
|
||||
);
|
||||
}
|
||||
// Create the payment link
|
||||
return $this->create(
|
||||
$line_items,
|
||||
$stripe_customer_id,
|
||||
[
|
||||
'order_id' => $order_id,
|
||||
'customer_id' => $stripe_customer_id
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new payment link
|
||||
* @param stripe_line_items $line_items
|
||||
* @param string $stripe_customer_id
|
||||
* @param array $metadata Additional metadata
|
||||
* @return Invoice
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function create(stripe_line_items $line_items, string $stripe_customer_id, array $metadata = []): Invoice
|
||||
{
|
||||
$invoice = self::getClient()->invoices->create([
|
||||
'customer' => $stripe_customer_id,
|
||||
'collection_method' => 'send_invoice',
|
||||
'days_until_due' => 30,
|
||||
'metadata' => $metadata,
|
||||
'auto_advance' => true,
|
||||
//'payment_settings' => [
|
||||
// 'payment_method_types' => [
|
||||
// 'card',
|
||||
// 'paypal'
|
||||
// ],
|
||||
//],
|
||||
]);
|
||||
// Add the line items to the invoice
|
||||
foreach ( $line_items->get() as $line_item ) {
|
||||
self::getClient()->invoiceItems->create([
|
||||
'customer' => $stripe_customer_id,
|
||||
'invoice' => $invoice->id,
|
||||
'price' => $line_item['price'],
|
||||
]);
|
||||
}
|
||||
// Finalize the invoice
|
||||
return $invoice->finalizeInvoice();
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,158 @@
|
||||
<?php
|
||||
|
||||
namespace stripe\endpoints;
|
||||
|
||||
use Exception;
|
||||
use Stripe\Collection;
|
||||
use Stripe\Exception\ApiErrorException;
|
||||
use Stripe\Terminal\Location;
|
||||
use Stripe\Terminal\Reader;
|
||||
use traits\stripe_endpoint_t;
|
||||
|
||||
class stripe_endpoint_readers
|
||||
{
|
||||
use stripe_endpoint_t;
|
||||
|
||||
/**
|
||||
* Get all readers
|
||||
* @return Collection
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function list(): Collection
|
||||
{
|
||||
return self::getClient()->terminal->readers->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all readers for a location
|
||||
* @throws ApiErrorException If the location is not set
|
||||
* @throws Exception If the location is not set
|
||||
*/
|
||||
public function listLocation(string $location_id): Collection
|
||||
{
|
||||
return self::getClient()->terminal->readers->all([
|
||||
'location' => $location_id
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a reader
|
||||
* @param string $label
|
||||
* @param string $location
|
||||
* @return Reader
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function register(string $label, string $location): Reader
|
||||
{
|
||||
return self::getClient()->terminal->readers->create([
|
||||
'label' => $label,
|
||||
'location' => $location
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all locations
|
||||
* @return Collection
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function listLocations(): Collection
|
||||
{
|
||||
return self::getClient()->terminal->locations->all();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a location
|
||||
* @param string $location_id
|
||||
* @return Location
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function retrieveLocation(string $location_id): Location
|
||||
{
|
||||
return self::getClient()->terminal->locations->retrieve($location_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a reader
|
||||
* @param string $reader_id
|
||||
* @return Reader
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function retrieve(string $reader_id): Reader
|
||||
{
|
||||
return self::getClient()->terminal->readers->retrieve($reader_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a location
|
||||
* @param string $label
|
||||
* @return Location
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function registerLocation(string $label): Location
|
||||
{
|
||||
return self::getClient()->terminal->locations->create([
|
||||
'label' => $label
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a location
|
||||
* @param string $location_id
|
||||
* @param string $label
|
||||
* @return Location
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function updateLocation(string $location_id, string $label): Location
|
||||
{
|
||||
return self::getClient()->terminal->locations->update($location_id, [
|
||||
'label' => $label
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Update a reader
|
||||
* @param string $reader_id
|
||||
* @param string $label
|
||||
* @return Reader
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function update(string $reader_id, string $label): Reader
|
||||
{
|
||||
return self::getClient()->terminal->readers->update($reader_id, [
|
||||
'label' => $label
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a location
|
||||
* @param string $location_id
|
||||
* @return Location
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function deleteLocation(string $location_id): Location
|
||||
{
|
||||
return self::getClient()->terminal->locations->delete($location_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a reader
|
||||
* @param string $reader_id
|
||||
* @return Reader
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function delete(string $reader_id): Reader
|
||||
{
|
||||
return self::getClient()->terminal->readers->delete($reader_id);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -98,8 +98,14 @@ class stripe_line_item
|
||||
);
|
||||
}
|
||||
|
||||
public function get(): array
|
||||
public function get($type = 'payment_link'): array
|
||||
{
|
||||
if ($type === 'invoice') {
|
||||
return [
|
||||
'price' => (string)$this->price_id,
|
||||
'amount' => (int)$this->quantity,
|
||||
];
|
||||
}
|
||||
return [
|
||||
//'product' => (int)$this->product_id,
|
||||
'price' => (string)$this->price_id,
|
||||
|
||||
@@ -8,6 +8,22 @@ class stripe_line_items
|
||||
* @var array $line_items
|
||||
*/
|
||||
protected array $line_items = [];
|
||||
protected array $types = [
|
||||
'invoice',
|
||||
'payment_link'
|
||||
];
|
||||
protected string $type;
|
||||
|
||||
/**
|
||||
* @throws \Exception
|
||||
*/
|
||||
public function __construct($type = 'payment_link')
|
||||
{
|
||||
if (!in_array($type, $this->types)) {
|
||||
throw new \Exception('Invalid type');
|
||||
}
|
||||
$this->type = $type;
|
||||
}
|
||||
|
||||
public function __toString(): string
|
||||
{
|
||||
@@ -20,7 +36,9 @@ class stripe_line_items
|
||||
$line_items = [];
|
||||
/** @var stripe_line_item|array $line_item */
|
||||
foreach ( $this->line_items as $line_item ) {
|
||||
$line_items[] = is_array($line_item) ? $line_item : $line_item->get();
|
||||
$line_items[] = is_array($line_item)
|
||||
? $line_item
|
||||
: $line_item->get($this->type);
|
||||
}
|
||||
return $line_items;
|
||||
}
|
||||
|
||||
@@ -4,7 +4,9 @@ namespace stripe;
|
||||
require_once WD . '/modules/stripe/config/stripe_enabled_c.php';
|
||||
require_once WD . '/modules/stripe/config/stripe_publishable_key_c.php';
|
||||
require_once WD . '/modules/stripe/config/stripe_secret_key_c.php';
|
||||
require_once WD . '/modules/stripe/config/stripe_economic_customer_number_c.php';
|
||||
|
||||
use stripe\config\stripe_economic_customer_number_c;
|
||||
use stripe\config\stripe_enabled_c;
|
||||
use stripe\config\stripe_publishable_key_c;
|
||||
use stripe\config\stripe_secret_key_c;
|
||||
@@ -29,6 +31,11 @@ class stripe_c
|
||||
* @var stripe_secret_key_c
|
||||
*/
|
||||
public stripe_secret_key_c $secret_key;
|
||||
/**
|
||||
* The economic customer number for stripe
|
||||
* @var stripe_economic_customer_number_c
|
||||
*/
|
||||
public stripe_economic_customer_number_c $economic_customer_number;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
@@ -36,10 +43,12 @@ class stripe_c
|
||||
$this->allowUpdate([
|
||||
stripe_enabled_c::class,
|
||||
stripe_publishable_key_c::class,
|
||||
stripe_secret_key_c::class
|
||||
stripe_secret_key_c::class,
|
||||
stripe_economic_customer_number_c::class
|
||||
]);
|
||||
$this->enabled = new stripe_enabled_c();
|
||||
$this->publishable_key = new stripe_publishable_key_c();
|
||||
$this->secret_key = new stripe_secret_key_c();
|
||||
$this->economic_customer_number = new stripe_economic_customer_number_c();
|
||||
}
|
||||
}
|
||||
@@ -269,6 +269,18 @@ class bookings_o extends db
|
||||
|
||||
public function checkUnfulfilledBookings(): void
|
||||
{
|
||||
$unfulfilled_bookings = [];
|
||||
function addUnfulfilledBooking(int $department, array $arr): array
|
||||
{
|
||||
// Check if the department has a count in the unfulfilled bookings array
|
||||
if (!isset($arr[$department])) {
|
||||
$arr[$department] = 0;
|
||||
}
|
||||
// Add the unfulfilled booking to the department count
|
||||
$arr[$department]++;
|
||||
return $arr;
|
||||
}
|
||||
|
||||
global $db;
|
||||
// Get all the unfulfilled bookings
|
||||
$bookings = $this->listObjectsWithPagination(1, 100000, null, ['status' => 'pending']);
|
||||
@@ -278,19 +290,26 @@ class bookings_o extends db
|
||||
echo "Booking with ID $booking[id] has been cancelled\n";
|
||||
continue;
|
||||
}
|
||||
// Check if the booking is scheduled for the future
|
||||
if (strtotime($booking['date']) > time()) {
|
||||
continue;
|
||||
}
|
||||
// Check if the booking has been fulfilled
|
||||
$fulfilled = $this->checkBookingFulfilled($booking['id']);
|
||||
if (!$fulfilled) {
|
||||
$unfulfilled_bookings = addUnfulfilledBooking($booking['department'], $unfulfilled_bookings);
|
||||
echo "Booking with ID $booking[id] has not been fulfilled\n";
|
||||
// Send a department webhook if the booking has not been fulfilled
|
||||
$slack = new slack();
|
||||
try {
|
||||
$slack->send_department_booking_notification($booking['department'], $slack->format_unfulfilled_booking($booking['id'], $booking['customer_number'], $booking['wash_type'], $booking['contact_email'], $booking['reference_number'], $booking['regNrTraekker'], $booking['regNrTrailer'], $booking['washCertificateEmail'], $booking['date'], $booking['department'], $booking['pickup_bool'], $booking['notes'], $booking['washCertificateStatus'], $booking['washCertificateUrl'], $booking['status']));
|
||||
} catch (\Exception $e) {
|
||||
// Log the error
|
||||
$logs = new logs_o();
|
||||
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_BOOKING_NOTIFICATION', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
// Send a department webhook if the booking has not been fulfilled
|
||||
foreach ( $unfulfilled_bookings as $department => $count ) {
|
||||
$slack = new slack();
|
||||
try {
|
||||
$slack->send_department_booking_notification($department, 'There are ' . $count . ' unfulfilled bookings');
|
||||
} catch (\Exception $e) {
|
||||
// Log the error
|
||||
$logs = new logs_o();
|
||||
$logs->add('slack', 0, 3, 0, 'SEND_DEPARTMENT_UNFULFILLED_BOOKINGS_NOTIFICATION', $e->getMessage());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,654 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\economic;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class collected_order_invoices_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $customer_number;
|
||||
public object_property $name;
|
||||
public object_property $notes;
|
||||
public object_property $processor;
|
||||
public object_property $external_id;
|
||||
|
||||
public object_property $booked_invoice_id;
|
||||
public object_property $created_at;
|
||||
public object_property $updated_at;
|
||||
public object_property $closed_at;
|
||||
public array $processors = [
|
||||
1 => 'E-conomic',
|
||||
2 => 'Stripe',
|
||||
3 => 'Other, without tracking',
|
||||
];
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('collected_order_invoices');
|
||||
}
|
||||
|
||||
/**
|
||||
* List all collected order invoices for a customer
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @return array The list of collected order invoices
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function getCustomerInvoiceCollections(int $customer_number): array
|
||||
{
|
||||
$collections = self::getFieldsWhere(
|
||||
[
|
||||
'customer_number' => $customer_number,
|
||||
'deleted_at' => null
|
||||
],
|
||||
['id', 'name', 'notes', 'processor', 'external_id', 'created_at', 'updated_at', 'closed_at']
|
||||
);
|
||||
// Parse the results
|
||||
$result = [];
|
||||
foreach ( $collections as $collection ) {
|
||||
$this->id = $collection['id'];
|
||||
self::getObjectProperties();
|
||||
self::requireSelected();
|
||||
$result[] = self::asArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->customer_number = new object_property($this->table, $this->id, 'customer_number', 'int', false);
|
||||
$this->name = new object_property($this->table, $this->id, 'name', 'string', false);
|
||||
$this->notes = new object_property($this->table, $this->id, 'notes', 'string', false);
|
||||
$this->processor = new object_property($this->table, $this->id, 'processor', 'int', false);
|
||||
$this->external_id = new object_property($this->table, $this->id, 'external_id', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
$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);
|
||||
}
|
||||
|
||||
public function asArray(): array
|
||||
{
|
||||
$tmp = [
|
||||
'id' => (int)$this->id,
|
||||
'customer_number' => (int)$this->customer_number->value(),
|
||||
'name' => (string)$this->name->value(),
|
||||
'notes' => (string)$this->notes->value(),
|
||||
'processor' => (int)$this->processor->value(),
|
||||
'external_id' => (string)$this->external_id->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
'updated_at' => (string)$this->updated_at->value(),
|
||||
'closed_at' => (string)$this->closed_at->value(),
|
||||
'orders' => $this->getOrders(),
|
||||
'economic_invoice_draft_id' => null, // This will be overwritten if the external id is set
|
||||
'economic_invoice_booked_id' => null, // This will be overwritten if the external id is set
|
||||
'total_net_amount' => self::getTotalAmount(),
|
||||
'user' => (array)(new users_o())->getUserByCustomerNumber($this->customer_number->value())->asArray(),
|
||||
];
|
||||
// If the external id is set, get the invoice draft id
|
||||
if (!empty($this->external_id->value())) {
|
||||
$tmp['economic_invoice_draft_id'] = self::isDraftExisting() ? self::getInvoiceDraftId() : null;
|
||||
$tmp['economic_invoice_booked_id'] = self::isBooked() ? self::getInvoiceBookedId() : null;
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the orders in the invoice collection
|
||||
* @param bool $count If the count of orders should be returned instead of the orders
|
||||
* @return array|int The list of orders in the invoice collection, or the count of orders if $count is true
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function getOrders(bool $count = false): array|int
|
||||
{
|
||||
$orders = new orders_o();
|
||||
$order_ids = $orders->getFieldsWhere(
|
||||
[
|
||||
'invoice_collection_id' => $this->id,
|
||||
'deleted_at' => null
|
||||
],
|
||||
['id']
|
||||
);
|
||||
if ($count) {
|
||||
return count($order_ids);
|
||||
}
|
||||
$result = [];
|
||||
foreach ( $order_ids as $order_id ) {
|
||||
$orders->select($order_id['id']);
|
||||
$orders->requireSelected();
|
||||
$result[] = $orders->asArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the net amount (sum) of the invoice collection
|
||||
* @return float The total amount of the invoice collection
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
*/
|
||||
public function getTotalAmount(): float
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Get the orders in the invoice collection
|
||||
$order_ids = self::getOrderIds();
|
||||
// Get the orders in the invoice collection
|
||||
$net_amount = 0;
|
||||
|
||||
foreach ( $order_ids as $order_id ) {
|
||||
$order = new orders_o();
|
||||
$order->select($order_id['id']);
|
||||
$order->requireSelected();
|
||||
// Get the net amount of the order
|
||||
$net_amount += $order->getNetAmount();
|
||||
}
|
||||
return $net_amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order ids in the invoice collection
|
||||
* @return array The list of order ids in the invoice collection
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function getOrderIds(): array
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Get the orders in the invoice collection
|
||||
$orders_o = new orders_o();
|
||||
return $orders_o->getFieldsWhere(
|
||||
[
|
||||
'invoice_collection_id' => $this->id,
|
||||
'deleted_at' => null
|
||||
],
|
||||
['id']
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the invoice draft is existing in E-conomic
|
||||
* @returns bool If the invoice draft is existing
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
*/
|
||||
public function isDraftExisting(): bool
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// If the external id is empty, the invoice draft does not exist
|
||||
if ($this->external_id->value() === null) {
|
||||
return false;
|
||||
}
|
||||
// Get the invoice draft id from the external id
|
||||
try {
|
||||
self::getInvoiceDraftId();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice draft id from the external id
|
||||
* @return int The invoice draft id
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice draft was not found
|
||||
*/
|
||||
public function getInvoiceDraftId(): int
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Check if the external id is set
|
||||
if ($this->external_id->value() === null) {
|
||||
throw new Exception('Invoice draft does not exist');
|
||||
}
|
||||
// Create an economic object
|
||||
$economic = new economic();
|
||||
// Get the invoice draft id from the external id
|
||||
$invoice_draft_id = $economic->invoices->draft->get_from_external_id($this->external_id->value());
|
||||
return (int)$invoice_draft_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the invoice is booked in E-conomic
|
||||
* @returns bool If the invoice is booked
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
*/
|
||||
public function isBooked(): bool
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Get the invoice booked id from the external id
|
||||
try {
|
||||
self::getInvoiceBookedId();
|
||||
return true;
|
||||
} catch (Exception $e) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice booked id from the external id
|
||||
* @return int The invoice booked id
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice booked was not found
|
||||
*/
|
||||
public function getInvoiceBookedId(): int
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Check if the invoice_booked_id is already set (We don't want to make a request to E-conomic if we already have the id - Since this is slow.)
|
||||
if (!empty($this->booked_invoice_id->value())) {
|
||||
return (int)$this->booked_invoice_id->value();
|
||||
}
|
||||
// If the external id is empty, the invoice booked does not exist
|
||||
if ($this->external_id->value() === null) {
|
||||
throw new Exception('Invoice booked does not exist');
|
||||
}
|
||||
// Create an economic object
|
||||
$economic = new economic();
|
||||
// Get the invoice booked id from the external id
|
||||
$invoice_booked_id = $economic->invoices->booked->get_from_external_id($this->external_id->value());
|
||||
$this->booked_invoice_id->set($invoice_booked_id);
|
||||
return (int)$invoice_booked_id;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a customer has an open invoice collection
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @return bool If the customer has an open invoice collection
|
||||
*/
|
||||
public function hasOpenInvoiceCollection(int $customer_number): bool
|
||||
{
|
||||
$collections = self::getFieldsWhere(
|
||||
[
|
||||
'customer_number' => $customer_number,
|
||||
'closed_at' => null,
|
||||
],
|
||||
['id']
|
||||
);
|
||||
return !empty($collections);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the open invoice collections for a customer
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @return array The open invoice collections
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function getOpenInvoiceCollections(int $customer_number): array
|
||||
{
|
||||
$collections = self::getFieldsWhere(
|
||||
[
|
||||
'customer_number' => $customer_number,
|
||||
'closed_at' => null,
|
||||
],
|
||||
['id', 'name', 'notes', 'processor', 'external_id', 'created_at', 'updated_at', 'closed_at']
|
||||
);
|
||||
// Parse the results
|
||||
$result = [];
|
||||
foreach ( $collections as $collection ) {
|
||||
$this->id = $collection['id'];
|
||||
self::getObjectProperties();
|
||||
self::requireSelected();
|
||||
$result[] = self::asArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @return self The latest open invoice collection
|
||||
* @throws Exception If no open invoice collections were found
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function getLatestOpenInvoiceCollection(int $customer_number): self
|
||||
{
|
||||
$collections = self::getFieldsWhere(
|
||||
[
|
||||
'customer_number' => $customer_number,
|
||||
'closed_at' => null,
|
||||
],
|
||||
['id', 'name', 'notes', 'processor', 'external_id', 'created_at', 'updated_at', 'closed_at'],
|
||||
);
|
||||
if (empty($collections)) {
|
||||
throw new Exception('No open invoice collections found');
|
||||
}
|
||||
// Parse the results
|
||||
$this->id = $collections[0]['id'];
|
||||
self::getObjectProperties();
|
||||
self::requireSelected();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the invoice collection to E-conomic
|
||||
* @param bool $ignore_closed If the function should ignore when the invoice collection is closed
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection was not found
|
||||
* @throws Exception If the customer number is not set
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
*/
|
||||
public function addToEconomic(bool $ignore_closed = false): self
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the customer number to be set
|
||||
if (empty($this->customer_number->value())) {
|
||||
throw new Exception('Customer number is not set');
|
||||
}
|
||||
if (!$ignore_closed) {
|
||||
// Require the invoice collection to be open
|
||||
self::requireOpen();
|
||||
}
|
||||
|
||||
// Create an economic draft
|
||||
self::createInvoiceDraft();
|
||||
|
||||
// Add the invoices to the invoice draft
|
||||
self::addInvoicesToDraft();
|
||||
|
||||
// Close the invoice collection
|
||||
// If the invoice collection is closed, we don't want to close it again
|
||||
if ($this->closed_at->value() === null) {
|
||||
self::closeCollection();
|
||||
}
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice collection to be open
|
||||
* @throws Exception If the invoice collection is closed
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public function requireOpen(): void
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice collection to not be closed
|
||||
if (!empty($this->closed_at->value())) {
|
||||
throw new Exception('Invoice collection is closed');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create an invoice draft in E-conomic
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
* @throws Exception If the invoice draft already exists
|
||||
*/
|
||||
public function createInvoiceDraft(): self
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Check if the invoice draft already exists
|
||||
if (self::isDraftExisting()) {
|
||||
throw new Exception('Invoice draft already exists');
|
||||
}
|
||||
// Require the invoice draft to not already exist
|
||||
self::requireInvoiceDraftDoesNotExist();
|
||||
// Create the invoice draft
|
||||
$economic = new economic();
|
||||
$response = $economic->invoices->drafts->add(
|
||||
$this->customer_number->value(),
|
||||
self::getExternalId(),
|
||||
);
|
||||
// Validate the response, by checking if the external id is set
|
||||
if (empty($response->references->other)) {
|
||||
throw new Exception('Invoice collection was not created successfully');
|
||||
}
|
||||
// Set the processor
|
||||
$this->processor->set(1);
|
||||
// Object changed
|
||||
self::objectChanged();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice draft to not already exist
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice draft already exists
|
||||
*/
|
||||
public function requireInvoiceDraftDoesNotExist(): void
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Try to get the invoice draft id from the external id
|
||||
try {
|
||||
self::getInvoiceDraftId();
|
||||
throw new Exception('Invoice draft already exists');
|
||||
} catch (Exception $e) {
|
||||
// Ignore the exception, as it is expected.
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new collected order invoice
|
||||
* @param int $customer_number The E-conomic customer number
|
||||
* @param string|null $name The name of the invoice (optional)
|
||||
* @param string|null $notes The notes for the invoice (optional)
|
||||
* @param int|null $processor The processor id (optional)
|
||||
* @return self The created object
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(int $customer_number, ?string $name = null, ?string $notes = null, ?int $processor = null): self
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$customer_number = $db->escape_string($customer_number);
|
||||
if (!empty($name)) {
|
||||
$name = $db->escape_string($name);
|
||||
}
|
||||
if (!empty($notes)) {
|
||||
$notes = $db->escape_string($notes);
|
||||
}
|
||||
if (!empty($processor)) {
|
||||
$processor = $db->escape_string($processor);
|
||||
}
|
||||
// Require the customer number to be of a valid customer
|
||||
self::requireValidCustomer($customer_number);
|
||||
// Add the object
|
||||
$tmp_id = self::add_object([
|
||||
'customer_number' => (int)$customer_number,
|
||||
'name' => $name,
|
||||
'notes' => $notes
|
||||
]);
|
||||
self::select((int)$tmp_id);
|
||||
self::requireSelected();
|
||||
// Set the processor
|
||||
if (!empty($processor)) {
|
||||
$this->processor->set($processor);
|
||||
}
|
||||
self::objectChanged();
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the E-conomic customer number to be a valid customer
|
||||
* @throws Exception If the customer number is not a valid customer
|
||||
*/
|
||||
private static function requireValidCustomer(string $customer_number): void
|
||||
{
|
||||
$customers = new users_o();
|
||||
$customers->select($customer_number);
|
||||
$customers->requireSelected();
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the external id of the invoice collection
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the UUID could not be generated
|
||||
* @throws Exception If the external id is not unique
|
||||
*/
|
||||
public function getExternalId(): string
|
||||
{
|
||||
if (empty($this->external_id->value())) {
|
||||
$this->external_id->set(self::generateExternalId());
|
||||
}
|
||||
return $this->external_id->value();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate a unique external id (UUID)
|
||||
* @return string The generated UUID
|
||||
* @throws Exception If the UUID could not be generated
|
||||
* @throws Exception If the request was not successful
|
||||
*/
|
||||
public static function generateExternalId(): string
|
||||
{
|
||||
$uuid = bin2hex(random_bytes(16));
|
||||
return substr($uuid, 0, 8) . '-' . substr($uuid, 8, 4) . '-' . substr($uuid, 12, 4) . '-' . substr($uuid, 16, 4) . '-' . substr($uuid, 20);
|
||||
}
|
||||
|
||||
/**
|
||||
* Add the invoices to the invoice draft
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
* @throws Exception If the invoice draft was not found
|
||||
*/
|
||||
public function addInvoicesToDraft(): self
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice collection to be open
|
||||
self::requireInvoiceIsNotBooked();
|
||||
// Get the orders in the invoice collection
|
||||
$orders = self::getOrders();
|
||||
// Check if there are any orders in the invoice collection
|
||||
if (empty($orders)) {
|
||||
throw new Exception('No orders in invoice collection');
|
||||
}
|
||||
// Require the invoice draft to be set (and exists)
|
||||
self::requireInvoiceDraft();
|
||||
|
||||
// Add the invoices to the invoice draft
|
||||
foreach ( $orders as $order ) {
|
||||
self::addInvoiceToDraft($order['id']);
|
||||
}
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice collection to not be booked
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
*/
|
||||
public function requireInvoiceIsNotBooked(): void
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice collection to not be booked
|
||||
if (!empty($this->booked_invoice_id->value())) {
|
||||
throw new Exception('Invoice collection is already booked');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice draft to be set
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice draft was not found
|
||||
*/
|
||||
public function requireInvoiceDraft(): void
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice draft to be set
|
||||
if (empty($this->external_id->value())) {
|
||||
throw new Exception('Invoice draft is not set');
|
||||
}
|
||||
|
||||
// Require the invoice draft to exist
|
||||
self::requireInvoiceDraftExists();
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the invoice draft to exist (in E-conomic)
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice draft was not found
|
||||
*/
|
||||
public function requireInvoiceDraftExists(): void
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Get the invoice draft id from the external id
|
||||
$invoice_draft_id = self::getInvoiceDraftId();
|
||||
// Check if the invoice draft id is set
|
||||
if (empty($invoice_draft_id)) {
|
||||
throw new Exception('Invoice draft not found');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add an invoice to the invoice draft
|
||||
* @param int $order_id The order id to add
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
* @throws Exception If the invoice draft was not found
|
||||
*/
|
||||
public function addInvoiceToDraft(int $order_id): self
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice collection to be open
|
||||
self::requireInvoiceIsNotBooked();
|
||||
// Get the order object
|
||||
$order = new orders_o();
|
||||
$order->select($order_id);
|
||||
$order->requireSelected();
|
||||
// Require the invoice draft to be set (and exists)
|
||||
self::requireInvoiceDraft();
|
||||
|
||||
// Add the invoice to the invoice draft
|
||||
$economic = new economic();
|
||||
$economic->invoices->draft->add_order(
|
||||
self::getInvoiceDraftId(),
|
||||
$order
|
||||
);
|
||||
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the invoice collection
|
||||
* @throws Exception If the request was not successful
|
||||
* @throws Exception If the invoice collection is not set
|
||||
* @throws Exception If the invoice collection is already closed
|
||||
*/
|
||||
public function closeCollection(): self
|
||||
{
|
||||
// Require the invoice collection to be selected
|
||||
self::requireSelected();
|
||||
// Require the invoice collection to be open
|
||||
self::requireOpen();
|
||||
// Close the invoice collection
|
||||
$this->closed_at->set(date('Y-m-d H:i:s'));
|
||||
self::objectChanged();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function listCustomersWithIndividualOrderInvoicing(): array
|
||||
{
|
||||
// Get all the customers with the "invoiceAllOrdersIndividually" attribute
|
||||
$users = new users_o();
|
||||
return $users->getCustomerNumbersWithAttributes([
|
||||
'invoiceAllOrdersIndividually'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,465 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class department_daily_reports_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
/**
|
||||
* The id of the department
|
||||
* @var object_property $department_id
|
||||
*/
|
||||
public object_property $department_id;
|
||||
/**
|
||||
* The cm3 of water used in the department today
|
||||
* @var object_property $water_usage
|
||||
*/
|
||||
public object_property $water_usage;
|
||||
/**
|
||||
* The cm3 of water used in the department today
|
||||
* @var object_property $water_usage_morning
|
||||
*/
|
||||
public object_property $water_usage_morning;
|
||||
|
||||
/**
|
||||
* Any notes for the report
|
||||
* @var object_property $notes
|
||||
*/
|
||||
public object_property $notes;
|
||||
|
||||
/**
|
||||
* The user (id) that filled the report
|
||||
* @var object_property $filled_by
|
||||
*/
|
||||
public object_property $filled_by;
|
||||
/**
|
||||
* The timestamp of when the object was created
|
||||
* @var object_property $created_at
|
||||
*/
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('department_daily_reports');
|
||||
}
|
||||
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'department_id' => (int)$this->department_id->value(),
|
||||
'water_usage' => (int)$this->water_usage->value(),
|
||||
'water_usage_morning' => (int)$this->water_usage_morning->value(),
|
||||
'notes' => (string)$this->notes->value(),
|
||||
'filled_by' => (int)$this->filled_by->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a department daily report
|
||||
* @param int $department_id The id of the department
|
||||
* @param int $water_usage The cm3 of water used in the department today
|
||||
* @param int $water_usage_morning The cm3 of water used in the department (Checked in the morning)
|
||||
* @param string $notes Any notes for the report
|
||||
* @param int $filled_by The user (id) that filled the report
|
||||
* @return department_daily_reports_o
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(
|
||||
int $department_id,
|
||||
int $water_usage,
|
||||
int $water_usage_morning,
|
||||
string $notes,
|
||||
int $filled_by,
|
||||
string $created_at = null
|
||||
): department_daily_reports_o
|
||||
{
|
||||
// Validate the created_at date, if provided
|
||||
if ($created_at !== null) {
|
||||
$dateTime = \DateTime::createFromFormat('Y-m-d', $created_at);
|
||||
if (!$dateTime || $dateTime->format('Y-m-d') !== $created_at) {
|
||||
throw new Exception('Invalid date format for created_at. Expected format: YYYY-MM-DD');
|
||||
}
|
||||
}
|
||||
$tmp_id = $this->add_object([
|
||||
'department_id' => (int)$department_id,
|
||||
'water_usage' => (int)$water_usage,
|
||||
'water_usage_morning' => (int)$water_usage_morning,
|
||||
'notes' => (string)$notes,
|
||||
'filled_by' => (int)$filled_by,
|
||||
'created_at' => $created_at ? $created_at : date('Y-m-d H:i:s'),
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
$this->getObjectProperties();
|
||||
$this->objectChanged();
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->department_id = new object_property($this->table, $this->id, 'department_id', 'int', false);
|
||||
$this->water_usage = new object_property($this->table, $this->id, 'water_usage', 'int', false);
|
||||
$this->water_usage_morning = new object_property($this->table, $this->id, 'water_usage_morning', 'int', false);
|
||||
$this->notes = new object_property($this->table, $this->id, 'notes', 'string', false);
|
||||
$this->filled_by = new object_property($this->table, $this->id, 'filled_by', 'int', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of products sold on a given date
|
||||
* @note This does not count products from removed orders, only products from orders that are still active
|
||||
* @param string $date The date to get the report for (YYYY-MM-DD)
|
||||
* @param int $department_id The id of the department
|
||||
* @param int $product_id The id of the product
|
||||
* @return int The amount of products sold on the given date (Not counting products from removed orders)
|
||||
*/
|
||||
public function getProductsSoldOnDate(string $date, int $department_id, int $product_id): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT SUM(oi.quantity) as amount FROM orders o
|
||||
JOIN order_items oi ON o.id = oi.order_id
|
||||
WHERE o.department_id = ? AND oi.product_id = ? AND DATE(o.created_at) = ? AND o.deleted_at IS NULL'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('iis', $department_id, $product_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of products sold, where the product would be applicable as an addon
|
||||
* E.g. if the product is "Cheese" this would return the amount of "Pizza" sold
|
||||
* @note This does not count products from removed orders, only products from orders that are still active
|
||||
* @param string $date The date to get the report for (YYYY-MM-DD)
|
||||
* @param int $department_id The id of the department
|
||||
* @param int $product_id The id of the product (the addon)
|
||||
* @return int The amount of products sold on the given date (Not counting products from removed orders)
|
||||
*/
|
||||
public function getProductsSoldWithAddonApplicable(string $date, int $department_id, int $product_id): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Get all the addons for the product
|
||||
$addons = (new product_options_o())->getOptionProducts($product_id);
|
||||
$addons = array_map(function ($addon) {
|
||||
return $addon['product_id'];
|
||||
}, $addons);
|
||||
$addons = implode(',', $addons);
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT SUM(oi.quantity) as amount FROM orders o
|
||||
JOIN order_items oi ON o.id = oi.order_id
|
||||
WHERE o.department_id = ? AND oi.product_id IN (' . $addons . ') AND DATE(o.created_at) = ? AND o.deleted_at IS NULL'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of products sold on a given date
|
||||
* @note This does not count products from removed orders, only products from orders that are still active
|
||||
* @param string $date The date to get the report for (YYYY-MM-DD)
|
||||
* @param int $department_id The id of the department
|
||||
* @return int The amount of products sold on the given date (Not counting products from removed orders)
|
||||
*/
|
||||
public function getTransactionProductsOnDateCount(string $date, int $department_id): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT SUM(oi.quantity) as amount FROM orders o
|
||||
JOIN order_items oi ON o.id = oi.order_id
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = ? AND o.deleted_at IS NULL'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the amount of transactions on a given date
|
||||
* @note This does not count products from removed orders, only products from orders that are still active
|
||||
* @param string $date The date to get the report for (YYYY-MM-DD)
|
||||
* @param int $department_id The id of the department
|
||||
* @return int The amount of transactions on the given date (Not counting products from removed orders)
|
||||
*/
|
||||
public function getTransactionsOnDateCount(string $date, int $department_id): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT COUNT(*) as amount FROM orders o
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = ? AND o.deleted_at IS NULL'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the department daily report for today
|
||||
* @param int $department_id The id of the department
|
||||
* @return department_daily_reports_o The department daily report
|
||||
* @throws Exception If a department daily report does not exist for today
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function selectDepartmentDailyReport(int $department_id): department_daily_reports_o
|
||||
{
|
||||
global $db;
|
||||
if (!$this->doesDepartmentDailyReportExist($department_id)) {
|
||||
throw new Exception('Department daily report does not exist');
|
||||
}
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT id FROM department_daily_reports o
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = CURDATE()'
|
||||
);
|
||||
// Check if the statement was prepared successfully
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('i', $department_id); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$id = $data['id'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
$this->select($id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a department daily report exists for today
|
||||
* @param int $department_id The id of the department
|
||||
* @param string $date The date to check for (YYYY-MM-DD)
|
||||
* @return bool True if the report exists, false otherwise
|
||||
*/
|
||||
public function doesDepartmentDailyReportExist(int $department_id, string $date = 'today'): bool
|
||||
{
|
||||
global $db;
|
||||
if ($date === 'today') {
|
||||
$date = date('Y-m-d');
|
||||
}
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT COUNT(*) as amount FROM department_daily_reports o
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = ?'
|
||||
);
|
||||
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
$amount = $data['amount'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the last department daily report for a department
|
||||
* @param int $department_id The id of the department
|
||||
* @return department_daily_reports_o The department daily report
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function selectLastDepartmentDailyReport(int $department_id): department_daily_reports_o
|
||||
{
|
||||
global $db;
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT id FROM department_daily_reports o
|
||||
WHERE o.department_id = ? ORDER BY o.created_at DESC LIMIT 1'
|
||||
);
|
||||
// Check if the statement was prepared successfully
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('i', $department_id); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "id" field
|
||||
if (!$data) {
|
||||
throw new Exception('Department daily report does not exist');
|
||||
}
|
||||
$id = $data['id'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
$this->select($id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function getTransactionsOnDateEarnings(string $date, int $department_id): int
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$conn = $db->conn();
|
||||
// Get all the product prices, in all the orders (Not counting removed orders), for the given date and department, and sum them
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT SUM(oi.price * oi.quantity) as amount FROM orders o
|
||||
JOIN order_items oi ON o.id = oi.order_id
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = ? AND o.deleted_at IS NULL'
|
||||
);
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
if (!$data) {
|
||||
// If there are no orders, set the amount to 0
|
||||
$amount = 0;
|
||||
} else {
|
||||
$amount = $data['amount'];
|
||||
}
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
return (int)$amount;
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a department daily report exists for today
|
||||
* @param int $department_id The id of the department
|
||||
* @return bool True if the report exists, false otherwise
|
||||
*/
|
||||
public function hasReportForToday(int $department_id): bool
|
||||
{
|
||||
return $this->doesDepartmentDailyReportExist($department_id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Select the department daily report for a given date
|
||||
* @param int $department_id The id of the department
|
||||
* @param string $date The date to get the report for (YYYY-MM-DD)
|
||||
* @return department_daily_reports_o The department daily report
|
||||
* @throws Exception If a department daily report does not exist for today
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function selectDepartmentReportByDate(int $department_id, string $date): department_daily_reports_o
|
||||
{
|
||||
global $db;
|
||||
if (!$this->doesDepartmentDailyReportExist($department_id, $date)) {
|
||||
throw new Exception('Department daily report does not exist');
|
||||
}
|
||||
$conn = $db->conn();
|
||||
$stmt = $conn->prepare(
|
||||
'SELECT id FROM department_daily_reports o
|
||||
WHERE o.department_id = ? AND DATE(o.created_at) = ?'
|
||||
);
|
||||
// Check if the statement was prepared successfully
|
||||
if ($stmt) {
|
||||
$stmt->bind_param('is', $department_id, $date); // Bind parameters (i = integer, s = string)
|
||||
$stmt->execute();
|
||||
$result = $stmt->get_result(); // Get the result set from the statement
|
||||
$data = $result->fetch_assoc(); // Fetch the result as an associative array
|
||||
|
||||
// Access the "amount" field
|
||||
if (!$data) {
|
||||
throw new Exception('Department daily report does not exist');
|
||||
}
|
||||
$id = $data['id'];
|
||||
|
||||
$stmt->close(); // Close the statement
|
||||
} else {
|
||||
// Handle query preparation error
|
||||
die('Query preparation failed: ' . $conn->error);
|
||||
}
|
||||
$this->select($id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
public function hasReport(int $department_id, string $date): bool
|
||||
{
|
||||
return $this->doesDepartmentDailyReportExist($department_id, $date);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,194 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class department_variables_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public int $department_id;
|
||||
|
||||
public object_property $variable;
|
||||
public object_property $value;
|
||||
public object_property $created_at;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('department_variables');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set a department variable
|
||||
* @param string $variable The variable name
|
||||
* @param string $value The variable value
|
||||
* @return void
|
||||
*
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function set(string $variable, mixed $value): void
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
// Check if the variable already exists
|
||||
$isAlreadyDefinedId = self::getFieldsWhere([
|
||||
'department_id' => $this->department_id,
|
||||
'variable' => $variable
|
||||
], ['id']);
|
||||
// Update the variable if it already exists
|
||||
if ($isAlreadyDefinedId) {
|
||||
$this->id = $isAlreadyDefinedId[0]['id'];
|
||||
$this->getObjectProperties();
|
||||
$this->value->set($value);
|
||||
return;
|
||||
}
|
||||
// Add the variable
|
||||
$tmp_id = self::add_object([
|
||||
'department_id' => $this->department_id,
|
||||
'variable' => $variable,
|
||||
'value' => $value
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
if (!$this->id) {
|
||||
throw new Exception('The variable was not created successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Require the department ID to be set, and throw an exception if it is not
|
||||
* @throws Exception If the department ID is not set.
|
||||
*/
|
||||
public function requireDepartmentId(): void
|
||||
{
|
||||
if (!$this->department_id) {
|
||||
throw new Exception('The department ID is not set.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the department variable by ID
|
||||
* @throws Exception If the department ID is not set
|
||||
*/
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
$this->variable = new object_property($this->table, $this->id, 'variable', 'string', false);
|
||||
$this->value = new object_property($this->table, $this->id, 'value', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* List all department variables
|
||||
* @throws Exception If the department ID is not set
|
||||
*/
|
||||
public function list(): array
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
$variables = self::getFieldsWhere([
|
||||
'department_id' => $this->department_id
|
||||
], ['id']);
|
||||
$result = [];
|
||||
foreach ( $variables as $variable ) {
|
||||
$tmp = new department_variables_o();
|
||||
$tmp->select($variable['id']);
|
||||
$result[] = $tmp->asArray();
|
||||
}
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the department variable by name
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
self::requireSelected();
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'department_id' => (int)$this->department_id,
|
||||
'variable' => (string)$this->variable->value(),
|
||||
'value' => (string)$this->value->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a department variable
|
||||
* @param string $variable The variable name
|
||||
* @return null If the variable is not set
|
||||
* @return mixed The variable value
|
||||
* @throws Exception If the department ID is not set
|
||||
*/
|
||||
public function getVariable(string $variable): mixed
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
$variable = self::getFieldsWhere([
|
||||
'department_id' => $this->department_id,
|
||||
'variable' => $variable
|
||||
], ['value']);
|
||||
if (!$variable) {
|
||||
return null;
|
||||
}
|
||||
return $variable[0]['value'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a department variable is set
|
||||
* @param string $variable The variable name
|
||||
* @return bool If the variable is set
|
||||
* @throws Exception If the department ID is not set
|
||||
*/
|
||||
public function isSet(string $variable): bool
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
$variable = self::getFieldsWhere([
|
||||
'department_id' => $this->department_id,
|
||||
'variable' => $variable
|
||||
], ['id']);
|
||||
return (bool)count($variable);
|
||||
}
|
||||
|
||||
/**
|
||||
* Nullify a department variable
|
||||
* @param string $variable The variable name
|
||||
* @return void If the variable was nullified
|
||||
* @throws Exception If the object was not selected
|
||||
* @throws Exception If the department ID is not set
|
||||
*/
|
||||
public function nullify(string $variable): void
|
||||
{
|
||||
self::requireDepartmentId();
|
||||
$variable = self::getFieldsWhere([
|
||||
'department_id' => $this->department_id,
|
||||
'variable' => $variable
|
||||
], ['id']);
|
||||
if ($variable) {
|
||||
$tmp = new department_variables_o();
|
||||
$tmp->select($variable[0]['id']);
|
||||
$tmp->requireSelected();
|
||||
$tmp->delete();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Select a department
|
||||
* @param int $id The department ID
|
||||
* @return self
|
||||
*/
|
||||
public function selectDepartment(int $id): self
|
||||
{
|
||||
$this->department_id = $id;
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,8 @@ namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use classes\stripe;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class departments_o extends db
|
||||
@@ -14,6 +16,10 @@ class departments_o extends db
|
||||
public object_property $description;
|
||||
public object_property $economic_department_id; // The id of the department in the economic system (Can be null)
|
||||
public object_property $slack_webhook; // The slack webhook for the department
|
||||
public department_variables_o $variables; // The department variables object
|
||||
public object_property $dimension; // The dimension of the department
|
||||
public object_property $created_at;
|
||||
public object_property $updated_at;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -26,6 +32,12 @@ class departments_o extends db
|
||||
redis->clear_departments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a department
|
||||
* @param string $name
|
||||
* @param string $description
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function create(string $name, string $description): void
|
||||
{
|
||||
global $db;
|
||||
@@ -46,12 +58,22 @@ class departments_o extends db
|
||||
redis->clear_departments();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object properties of the department
|
||||
* @throws Exception If the object is not selected
|
||||
*/
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
self::requireSelected();
|
||||
$this->name = new object_property($this->table, $this->id, 'name', 'string', true);
|
||||
$this->description = new object_property($this->table, $this->id, 'description', 'string', false);
|
||||
$this->economic_department_id = new object_property($this->table, $this->id, 'economic_department_id', 'int', false);
|
||||
$this->slack_webhook = new object_property($this->table, $this->id, 'slack_webhook', 'string', false);
|
||||
$this->variables = (new department_variables_o())->selectDepartment($this->id);
|
||||
$this->dimension = new object_property($this->table, $this->id, 'dimension', 'int', false);
|
||||
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
|
||||
}
|
||||
|
||||
public function edit(int $id, string $name, string $description, int $economic_department_id): void
|
||||
@@ -193,11 +215,92 @@ class departments_o extends db
|
||||
if (!empty($name)) {
|
||||
redis->cache_department_name($department, $name);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$name = 'Unable to get department name: ' . $department;
|
||||
}
|
||||
return $name;
|
||||
}
|
||||
return redis->get_department_name($department) ?? 'Unable to get department name: ' . $department;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Stripe terminal location department variable
|
||||
* @note This is a link to the department_variables_o::getVariable(stripe_terminal_location) method
|
||||
* @return string The Stripe terminal location id
|
||||
* @throws Exception If the department variable is not set
|
||||
* @throws Exception If the department is not selected
|
||||
*/
|
||||
public function getStripeTerminalLocation(): string
|
||||
{
|
||||
self::requireSelected();
|
||||
if (!$this->variables->isSet('stripe_terminal_location')) {
|
||||
throw new Exception('The Stripe terminal location is not set for the department.');
|
||||
}
|
||||
return $this->variables->getVariable('stripe_terminal_location');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the Stripe terminal location variable is set
|
||||
* @note This is a link to the department_variables_o::isSet(stripe_terminal_location) method
|
||||
* @return bool true If the Stripe terminal location is set
|
||||
* @throws Exception If the department is not selected
|
||||
*/
|
||||
public function isStripeTerminalLocationSet(): bool
|
||||
{
|
||||
self::requireSelected();
|
||||
return $this->variables->isSet('stripe_terminal_location');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the Stripe terminal location department variable
|
||||
* @note This is a link to the department_variables_o::set(stripe_terminal_location) method
|
||||
* @param string $location The Stripe terminal location id
|
||||
* @throws Exception If the department is not selected
|
||||
* @throws Exception If the department variable is not updated successfully
|
||||
*/
|
||||
public function setStripeTerminalLocation(string $location): void
|
||||
{
|
||||
self::requireSelected();
|
||||
$this->variables->set('stripe_terminal_location', $location);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Stripe terminal readers
|
||||
* @note This is a link to the stripe_endpoint_readers::listLocation method
|
||||
* @throws Exception If the department is not selected
|
||||
* @throws Exception If the Stripe terminal location is not set for the department
|
||||
*/
|
||||
public function getStripeTerminalReaders(): \Stripe\Collection
|
||||
{
|
||||
self::requireSelected();
|
||||
if (!$this->variables->isSet('stripe_terminal_location')) {
|
||||
throw new Exception('The Stripe terminal location is not set for the department.');
|
||||
}
|
||||
return (new stripe())->readers->listLocation($this->variables->getVariable('stripe_terminal_location'));
|
||||
}
|
||||
|
||||
/**
|
||||
* Convert the object to an array
|
||||
* @param array|null $options The options for the conversion (e.g. ['slack_webhook' => true])
|
||||
* @return array The object as an array
|
||||
* @throws Exception If the object is not selected
|
||||
*/
|
||||
public function asArray(array $options = null): array
|
||||
{
|
||||
self::requireSelected();
|
||||
$tmp = [
|
||||
'id' => (int)$this->id,
|
||||
'name' => (string)$this->name->value(),
|
||||
'description' => (string)$this->description->value(),
|
||||
'economic_department_id' => (int)$this->economic_department_id->value(),
|
||||
'dimension' => (int)$this->dimension->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
'updated_at' => (string)$this->updated_at->value(),
|
||||
];
|
||||
// Check if the webhook should be included
|
||||
if ($options && $options['slack_webhook']) {
|
||||
$tmp['slack_webhook'] = (string)$this->slack_webhook->value();
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,87 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class form_submissions_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $form_identifier;
|
||||
public object_property $data;
|
||||
public object_property $user_id;
|
||||
public object_property $department_id;
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('form_submissions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a form submission object, and set this object to the new object
|
||||
* @param string $form_identifier The form identifier
|
||||
* @param array $data The form data
|
||||
* @param int|null $user_id The user id (If applicable)
|
||||
* @param int|null $department_id The department id (If applicable)
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $form_identifier, array $data, ?int $user_id = null, ?int $department_id = null): void
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$form_identifier = $db->escape_string($form_identifier);
|
||||
$encoded_data = $db->escape_string(json_encode($data));
|
||||
// Add the object
|
||||
$tmp_arr = [
|
||||
'form_identifier' => $form_identifier,
|
||||
'data' => $encoded_data,
|
||||
];
|
||||
// Add the user id and department id if they are set
|
||||
if (!empty($user_id)) {
|
||||
$tmp_arr['user_id'] = (int)$user_id;
|
||||
}
|
||||
if (!empty($department_id)) {
|
||||
$tmp_arr['department_id'] = (int)$department_id;
|
||||
}
|
||||
$tmp_id = self::add_object($tmp_arr);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->form_identifier = new object_property($this->table, $this->id, 'form_identifier', 'string', false);
|
||||
$this->data = new object_property($this->table, $this->id, 'data', 'string', false);
|
||||
$this->user_id = new object_property($this->table, $this->id, 'user_id', 'int', false);
|
||||
$this->department_id = new object_property($this->table, $this->id, 'department_id', 'int', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'form_identifier' => (string)$this->form_identifier->value(),
|
||||
'data' => (string)$this->data->value(),
|
||||
'user_id' => (int)$this->user_id->value(),
|
||||
'department_id' => (int)$this->department_id->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class groups_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $name;
|
||||
public object_property $description;
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
self::setTable('groups');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group by name
|
||||
* @throws Exception If an object is not selected
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
self::requireSelected();
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'name' => (string)$this->name->value(),
|
||||
'description' => (string)$this->description->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
'permissions' => $this->getPermissions()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permissions for a group
|
||||
* @return array
|
||||
* @throws Exception If the group was not selected
|
||||
*/
|
||||
public function getPermissions(): array
|
||||
{
|
||||
self::requireSelected();
|
||||
return (new groups_permissions_o())->getGroupPermissions($this->id);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get department ids, that the group has permission (department_access_:group_id) to access
|
||||
* @return array An array of department ids e.g. [1, 2, 3]
|
||||
* @throws Exception If the group was not selected
|
||||
*/
|
||||
public function getDepartments(): array
|
||||
{
|
||||
self::requireSelected();
|
||||
$permissions = (new groups_permissions_o())->getGroupPermissionsMatching($this->id, '/^department_access_[0-9]+$/');
|
||||
$departments = [];
|
||||
foreach ( $permissions as $value ) {
|
||||
$tmp = explode('_', $value['permission']);
|
||||
$departments[] = (int)$tmp[2];
|
||||
}
|
||||
return $departments;
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a permission from a group
|
||||
*
|
||||
* @param string $permission_id
|
||||
* @return self $this
|
||||
* @throws Exception If the permission was not removed successfully
|
||||
*/
|
||||
public function removePermission(string $permission_id): self
|
||||
{
|
||||
self::requireSelected();
|
||||
(new groups_permissions_o())->remove($this->id, $permission_id);
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* Clone a group with all its permissions
|
||||
* @param string $name
|
||||
* @param string $description
|
||||
* @return void
|
||||
* @throws Exception
|
||||
*/
|
||||
public function clone(string $name, string $description): void
|
||||
{
|
||||
self::requireSelected();
|
||||
$group = new groups_o();
|
||||
$group->add($name, $description);
|
||||
$permissions = (new groups_permissions_o())->getGroupPermissions($this->id);
|
||||
foreach ( $permissions as $permission ) {
|
||||
$group->addPermission($permission);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a group
|
||||
* @param string $name
|
||||
* @param string $description
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $name, string $description): void
|
||||
{
|
||||
$tmp_id = self::add_object([
|
||||
'name' => $name,
|
||||
'description' => $description
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
if (!$this->id) {
|
||||
throw new Exception('The group was not created successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->name = new object_property($this->table, $this->id, 'name', 'string', false);
|
||||
$this->description = new object_property($this->table, $this->id, 'description', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a permission to a group
|
||||
*
|
||||
* @param string $permission_id
|
||||
* @return self $this
|
||||
* @throws Exception If the permission was not added successfully
|
||||
*/
|
||||
public function addPermission(string $permission_id): self
|
||||
{
|
||||
self::requireSelected();
|
||||
(new groups_permissions_o())->add($this->id, $permission_id);
|
||||
return $this;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,146 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class groups_permissions_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $group_id;
|
||||
public object_property $permission;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('groups_permissions');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a permission to a group
|
||||
* @param int $group_id
|
||||
* @param string $permission
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(int $group_id, string $permission): void
|
||||
{
|
||||
// Check if the group exists
|
||||
$group = new groups_o();
|
||||
$group->select($group_id);
|
||||
$group->requireSelected();
|
||||
// Check if the permission already exists for the group
|
||||
$isAlreadyDefined = self::getFieldsWhere([
|
||||
'group_id' => $group_id,
|
||||
'permission' => $permission
|
||||
], ['id']);
|
||||
// Throw an exception if the permission already exists for the group
|
||||
if ($isAlreadyDefined) {
|
||||
throw new Exception('The permission already exists for the group.');
|
||||
}
|
||||
// Add the permission
|
||||
$tmp_id = self::add_object([
|
||||
'group_id' => $group_id,
|
||||
'permission' => $permission
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
if (!$this->id) {
|
||||
throw new Exception('The permission was not created successfully.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->group_id = new object_property($this->table, $this->id, 'group_id', 'int', false);
|
||||
$this->permission = new object_property($this->table, $this->id, 'permission', 'string', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a permission from a group
|
||||
* @param int $group_id
|
||||
* @param string $permission
|
||||
* @return void
|
||||
* @throws Exception If the permission does not exist for the group
|
||||
* @throws Exception If the object was not deleted successfully
|
||||
* @throws Exception If the group does not exist
|
||||
*/
|
||||
public function remove(int $group_id, string $permission): void
|
||||
{
|
||||
// Check if the group exists
|
||||
$group = new groups_o();
|
||||
$group->select($group_id);
|
||||
$group->requireSelected();
|
||||
// Check if the permission exists for the group
|
||||
$isDefined = self::getFieldsWhere([
|
||||
'group_id' => $group_id,
|
||||
'permission' => $permission
|
||||
], ['id']);
|
||||
// Throw an exception if the permission does not exist for the group
|
||||
if (!$isDefined) {
|
||||
throw new Exception('The permission does not exist for the group.');
|
||||
}
|
||||
// Get the id of the permission entry in the database
|
||||
$id = $isDefined[0]['id'];
|
||||
// Remove the permission
|
||||
$tmp_id = new groups_permissions_o();
|
||||
$tmp_id->select((int)$id);
|
||||
$tmp_id->requireSelected();
|
||||
$tmp_id->delete();
|
||||
}
|
||||
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'group_id' => (int)$this->group_id->value(),
|
||||
'permission' => (string)$this->permission->value()
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permissions for a group
|
||||
* @param int $group_id
|
||||
* @return array
|
||||
*/
|
||||
public function getGroupPermissions(int $group_id): array
|
||||
{
|
||||
$raw_permissions = self::getFieldsWhere([
|
||||
'group_id' => $group_id
|
||||
], ['permission']);
|
||||
$permissions = [];
|
||||
foreach ( $raw_permissions as $permission ) {
|
||||
$permissions[] = $permission['permission'];
|
||||
}
|
||||
return $permissions;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all permissions for a group matching a regex
|
||||
* @throws Exception If the group does not exist
|
||||
*/
|
||||
public function getGroupPermissionsMatching(int $id, string $regex): array
|
||||
{
|
||||
// Check if the group exists
|
||||
$group = new groups_o();
|
||||
$group->select($id);
|
||||
$group->requireSelected();
|
||||
// Get the permissions
|
||||
$permissions = self::getFieldsWhere([
|
||||
'group_id' => $id
|
||||
], ['permission']);
|
||||
// Filter the permissions
|
||||
return array_filter($permissions, function ($permission) use ($regex) {
|
||||
return preg_match($regex, $permission['permission']);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,119 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class module_action_logs_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
/**
|
||||
* The module name
|
||||
* @var object_property $module The module name
|
||||
*/
|
||||
public object_property $module;
|
||||
/**
|
||||
* The action name
|
||||
* @var object_property $action The action name
|
||||
*/
|
||||
public object_property $action;
|
||||
/**
|
||||
* The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
* @var object_property $status_code The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
*/
|
||||
public object_property $status_code;
|
||||
/**
|
||||
* The action data
|
||||
* @var object_property $data The data JSON encoded
|
||||
*/
|
||||
public object_property $data;
|
||||
/**
|
||||
* The action created at
|
||||
* @var object_property $created_at The action created at
|
||||
*/
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('module_usage_logs');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a module action log
|
||||
* @param string $module The module name
|
||||
* @param string $action The action name
|
||||
* @param int $status_code The action status code (HTTP status code, e.g. 200, 404, 500)
|
||||
* @param array $data The action data
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $module, string $action, int $status_code, array $data): void
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$module = $db->escape_string($module);
|
||||
$action = $db->escape_string($action);
|
||||
$status_code = (int)$status_code;
|
||||
// JSON encode the data
|
||||
$encoded_data = $db->escape_string(json_encode($data));
|
||||
// Add the object
|
||||
$tmp_id = self::add_object([
|
||||
'module' => $module,
|
||||
'action' => $action,
|
||||
'status_code' => $status_code,
|
||||
'data' => $encoded_data,
|
||||
]);
|
||||
if (!$tmp_id) {
|
||||
throw new Exception('The object was not created successfully.');
|
||||
}
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->module = new object_property($this->table, $this->id, 'module', 'string', false);
|
||||
$this->action = new object_property($this->table, $this->id, 'action', 'string', false);
|
||||
$this->status_code = new object_property($this->table, $this->id, 'status_code', 'int', false);
|
||||
$this->data = new object_property($this->table, $this->id, 'data', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'datetime', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object as an array
|
||||
* @return array The object as an array
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'module' => (string)$this->module->value(),
|
||||
'action' => (string)$this->action->value(),
|
||||
'status_code' => (int)$this->status_code->value(),
|
||||
'data' => self::decodeData((string)$this->data->value()),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the data
|
||||
* @param string $data The data JSON encoded
|
||||
* @return array The data
|
||||
*/
|
||||
public static function decodeData(string $data): array
|
||||
{
|
||||
return json_decode($data, true);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,13 @@ class motorapi_lookups_o extends db
|
||||
*/
|
||||
public function add(string $license_plate, string $result, string $endpoint): void
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$license_plate = $db->escape_string($license_plate);
|
||||
$result = $db->escape_string($result);
|
||||
$endpoint = $db->escape_string($endpoint);
|
||||
// Add the object
|
||||
$tmp_id = self::add_object([
|
||||
'license_plate' => $license_plate,
|
||||
'result' => $result,
|
||||
@@ -79,4 +86,58 @@ class motorapi_lookups_o extends db
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Is the license plate in the cache?
|
||||
* @param string $license_plate
|
||||
* @return bool
|
||||
* @throws Exception If the license plate is not valid
|
||||
*/
|
||||
public function isCached(string $license_plate): bool
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
if (!self::validateLicensePlateFormat($license_plate)) {
|
||||
throw new Exception('The license plate is not valid.');
|
||||
}
|
||||
$sql = 'SELECT COUNT(*) FROM ' . $this->table . ' WHERE license_plate = "' . $db->escape_string($license_plate) . '"';
|
||||
$result = $db->query($sql);
|
||||
return (bool)$result->fetch_row()[0];
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate the format of a license plate
|
||||
* @note This simply checks if the license plate is in the format of two letters followed by four or five numbers.
|
||||
* @note This does not check if the license plate is actually valid.
|
||||
* @param string $license_plate
|
||||
* @return bool
|
||||
*/
|
||||
public static function validateLicensePlateFormat(string $license_plate): bool
|
||||
{
|
||||
return (bool)preg_match('/^[A-Z]{2}[0-9]{4,5}$/', $license_plate);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the (latest) cached result for a license plate
|
||||
* @param string $license_plate
|
||||
* @return object
|
||||
* @throws Exception If the license plate is not valid or the response is not cached
|
||||
*/
|
||||
public function getCachedResult(string $license_plate): object
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
if (!self::validateLicensePlateFormat($license_plate)) {
|
||||
throw new Exception('The license plate is not valid.');
|
||||
}
|
||||
$result = self::getFieldsWhere(['license_plate' => $license_plate], ['id', 'result', 'endpoint', 'created_at']);
|
||||
if (!$result) {
|
||||
throw new Exception('The response is not cached.');
|
||||
}
|
||||
// Get the latest result
|
||||
$latest = array_pop($result);
|
||||
$this->id = $latest['id'];
|
||||
self::getObjectProperties();
|
||||
return $this;
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class notifications_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
/**
|
||||
* The notification type
|
||||
* @var object_property $type The notification type
|
||||
*/
|
||||
public object_property $type;
|
||||
/**
|
||||
* The user id
|
||||
* @var object_property $user_id The user id
|
||||
*/
|
||||
public object_property $user_id;
|
||||
/**
|
||||
* The notification data
|
||||
* @var object_property $data The notification data (JSON encoded)
|
||||
*/
|
||||
public object_property $data;
|
||||
/**
|
||||
* The notification created at
|
||||
* @var object_property $created_at The notification created at
|
||||
*/
|
||||
public object_property $created_at;
|
||||
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('notifications');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a notification object, and set this object to the new object
|
||||
* @param string $type The notification type id
|
||||
* @param int $user_id The user id
|
||||
* @param array $data The notification data
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $type, int $user_id, array $data): void
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
// Sanitize the input
|
||||
$type = $db->escape_string($type);
|
||||
$user_id = (int)$user_id;
|
||||
// JSON encode the data
|
||||
$encoded_data = $db->escape_string(json_encode($data));
|
||||
// Add the object
|
||||
$tmp_id = self::add_object([
|
||||
'type' => $type,
|
||||
'user_id' => $user_id,
|
||||
'data' => $encoded_data,
|
||||
]);
|
||||
if (!$tmp_id) {
|
||||
throw new Exception('The object was not created successfully.');
|
||||
}
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object properties
|
||||
* @return void
|
||||
*/
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->type = new object_property($this->table, $this->id, 'type', 'string', false);
|
||||
$this->user_id = new object_property($this->table, $this->id, 'user_id', 'int', false);
|
||||
$this->data = new object_property($this->table, $this->id, 'data', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'datetime', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the object as an array
|
||||
* @return array The object as an array
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'type' => (string)$this->type->value(),
|
||||
'user_id' => (int)$this->user_id->value(),
|
||||
'data' => self::decodeData((string)$this->data->value()),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* Decode the data
|
||||
* @param string $data The data JSON encoded
|
||||
* @return array The data
|
||||
*/
|
||||
public static function decodeData(string $data): array
|
||||
{
|
||||
return json_decode($data, true);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,11 @@ class order_items_o extends db
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $quantity;
|
||||
/**
|
||||
* The id of the related item, if it exists
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $related_item_id;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -78,6 +83,7 @@ class order_items_o extends db
|
||||
$this->cashier_id = new object_property($this->table, $this->id, 'cashier_id', 'int', true);
|
||||
$this->price = new object_property($this->table, $this->id, 'price', 'int', true);
|
||||
$this->quantity = new object_property($this->table, $this->id, 'quantity', 'int', true);
|
||||
$this->related_item_id = new object_property($this->table, $this->id, 'related_item_id', 'int', false);
|
||||
}
|
||||
|
||||
public function add(int $order_id, int $product_id, string $reference, string $notes, int $cashier_id, int $price, int $quantity): void
|
||||
@@ -120,7 +126,7 @@ class order_items_o extends db
|
||||
}
|
||||
}
|
||||
|
||||
public function addItemToOrder(int $order_id, int $product_id, int $cashier_id, int $quantity): void
|
||||
public function addItemToOrder(int $order_id, int $product_id, int $cashier_id, int $quantity, $related_item_id = null, $notes = null): void
|
||||
{
|
||||
global $db, $response;
|
||||
try {
|
||||
@@ -143,6 +149,15 @@ class order_items_o extends db
|
||||
$this->id = $db->insert_id();
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
// Set the related item id, if it is set
|
||||
if ($related_item_id) {
|
||||
$this->related_item_id->set($related_item_id);
|
||||
}
|
||||
// Set the notes, if it is set
|
||||
if ($notes) {
|
||||
$this->notes->set($notes);
|
||||
}
|
||||
|
||||
} catch (\Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
@@ -154,7 +169,7 @@ class order_items_o extends db
|
||||
// TODO: Implement delete() method instead
|
||||
global $db;
|
||||
$this->id = $id;
|
||||
$sql = "DELETE FROM $this->table WHERE id = $this->id";
|
||||
$sql = "DELETE FROM $this->table WHERE id = $this->id or related_item_id = $this->id";
|
||||
$db->query($sql);
|
||||
}
|
||||
|
||||
@@ -169,6 +184,7 @@ class order_items_o extends db
|
||||
'cashier_id' => (int)$this->cashier_id->value(),
|
||||
'price' => (int)$this->price->value(),
|
||||
'quantity' => (int)$this->quantity->value(),
|
||||
'related_item_id' => (int)$this->related_item_id->value(),
|
||||
'product' => (array)(new products_o())->getProductById($this->product_id->value())->asArray(),
|
||||
'cashier' => (array)(new users_o())->getUserById($this->cashier_id->value())->asArray()
|
||||
];
|
||||
|
||||
@@ -3,8 +3,10 @@
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\motorapi;
|
||||
use classes\object_property;
|
||||
use classes\response;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class orders_o extends db
|
||||
@@ -23,6 +25,7 @@ class orders_o extends db
|
||||
public object_property $created_at;
|
||||
public object_property $deleted_at;
|
||||
public stripe_module_orders_o $stripe_module_orders;
|
||||
public object_property $invoice_collection_id;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -43,7 +46,7 @@ class orders_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
@@ -62,8 +65,10 @@ class orders_o extends db
|
||||
$this->economic_module_orders = (new economic_module_orders())->getByOrderId($this->id);
|
||||
$this->stripe_module_orders = (new stripe_module_orders_o())->select($this->id);
|
||||
$this->deleted_at = new object_property($this->table, $this->id, 'deleted_at', 'timestamp', false);
|
||||
$this->invoice_collection_id = new object_property($this->table, $this->id, 'invoice_collection_id', 'int', false);
|
||||
}
|
||||
|
||||
|
||||
public function includeIncludes(): orders_o
|
||||
{
|
||||
global /** @var response $response */
|
||||
@@ -137,19 +142,40 @@ class orders_o extends db
|
||||
{
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'customer_id' => $this->customer_id->value(),
|
||||
'cashier_id' => $this->cashier_id->value(),
|
||||
'customer_id' => (int)$this->customer_id->value(),
|
||||
'cashier_id' => (int)$this->cashier_id->value(),
|
||||
'reference' => $this->reference->value(),
|
||||
'notes' => $this->notes->value(),
|
||||
'department_id' => $this->department_id->value(),
|
||||
'department_id' => (int)$this->department_id->value(),
|
||||
'reg_1' => $this->reg_1->value(),
|
||||
'reg_2' => $this->reg_2->value(),
|
||||
'reg_3' => $this->reg_3->value(),
|
||||
'created_at' => $this->created_at->value(),
|
||||
'deleted_at' => $this->deleted_at->value(),
|
||||
'total_net_amount' => $this->getNetAmount(),
|
||||
'invoice_collection_id' => (int)$this->invoice_collection_id->value(),
|
||||
'closed_at' => (int)$this->invoice_collection_id->value() ? (new collected_order_invoices_o())->select((int)$this->invoice_collection_id->value())->closed_at->value() : null,
|
||||
];
|
||||
}
|
||||
|
||||
public function getNetAmount(): float
|
||||
{
|
||||
self::requireSelected();
|
||||
$net = 0;
|
||||
// Get the order items object
|
||||
$order_items = new order_items_o();
|
||||
// Get the price, quantity of the order items
|
||||
$items = $order_items->getAllItemsAsArray($this->id);
|
||||
// Loop through the items and get the net amount
|
||||
foreach ( $items as $item ) {
|
||||
$tmp_price = (int)$item['price'];
|
||||
$tmp_quantity = (int)$item['quantity'];
|
||||
// Add the price to the net amount
|
||||
$net += $tmp_price * $tmp_quantity;
|
||||
}
|
||||
return $net;
|
||||
}
|
||||
|
||||
public function exists(): bool
|
||||
{
|
||||
// Check if the id is greater than 0, and that the deleted_at property is null
|
||||
@@ -273,19 +299,6 @@ class orders_o extends db
|
||||
$this->{$data['field']}->set($data['value']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order history for a vehicle plate
|
||||
* @param string $plate The vehicle plate
|
||||
* @return array The order history
|
||||
*/
|
||||
public function get_vehicle_order_history(string $plate): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT * FROM $this->table WHERE reg_1 = '$plate' OR reg_2 = '$plate' OR reg_3 = '$plate' AND deleted_at IS NULL";
|
||||
$result = $db->query($sql);
|
||||
return $db->fetch_all($result);
|
||||
}
|
||||
|
||||
public function getOrderByInvoiceId(int $invoiceId): orders_o
|
||||
{
|
||||
global $db;
|
||||
@@ -295,17 +308,17 @@ class orders_o extends db
|
||||
$row = $result->fetch_assoc();
|
||||
return $this->getOrderById($row['id']);
|
||||
}
|
||||
throw new \Exception('Order not found');
|
||||
throw new Exception('Order not found');
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the stripe invoicing for an order
|
||||
* @throws \Exception
|
||||
* @throws Exception
|
||||
*/
|
||||
public function setStripeInvoicing(string $payment_link_id, string $email, string $url): void
|
||||
public function setStripeInvoicing(string $invoice_id, string $stripe_customer_id, string $url): void
|
||||
{
|
||||
self::requireSelected();
|
||||
$this->stripe_module_orders->add($this->id, $email, $payment_link_id, $url);
|
||||
$this->stripe_module_orders->add($this->id, $invoice_id, $stripe_customer_id, $url);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
@@ -328,16 +341,127 @@ class orders_o extends db
|
||||
|
||||
// Set the values of the object properties
|
||||
$this->getObjectProperties();
|
||||
self::requireSelected();
|
||||
self::assignToInvoiceCollection();
|
||||
return $this;
|
||||
} catch (\Exception $e) {
|
||||
} catch (Exception $e) {
|
||||
$response->error($e->getMessage());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Assign the order to an invoice collection
|
||||
* @param int|null $invoiceCollectionId The invoice collection id, if not set, the default invoice collection id will be used.
|
||||
* @throws Exception If the order is not selected
|
||||
*/
|
||||
public function assignToInvoiceCollection(int $invoiceCollectionId = null): void
|
||||
{
|
||||
// If the invoice collection id is not set, get the default invoice collection id
|
||||
self::requireSelected();
|
||||
// Get the customer
|
||||
$customer = new users_o();
|
||||
$customer->getUserByCustomerNumber($this->customer_id->value());
|
||||
$customer->requireSelected();
|
||||
// Get the invoice collection id
|
||||
$invoiceCollectionId = $invoiceCollectionId ?? $customer->getNewOrderInvoiceCollectionId();
|
||||
// Assign the order to the invoice collection
|
||||
$this->invoice_collection_id->set($invoiceCollectionId);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
// Since the orders object is not cached, there is no need to invalidate the cache
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the recommended order items, based on the order history, vehicle plate and department
|
||||
* @return array The recommended order items
|
||||
* @throws Exception If the order is not selected
|
||||
*/
|
||||
public function getRecommendedOrder(): array
|
||||
{
|
||||
self::requireSelected();
|
||||
$recommended = [
|
||||
'reg_1' => self::getRecommendedOrderPlate($this->reg_1->value()),
|
||||
'reg_2' => [],
|
||||
'reg_3' => [],
|
||||
];
|
||||
return $recommended;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception If the order is not selected
|
||||
*/
|
||||
public function getRecommendedOrderPlate(string $plate): array
|
||||
{
|
||||
self::requireSelected();
|
||||
$result = [
|
||||
'order_history' => self::get_vehicle_last_orders_items($plate),
|
||||
];
|
||||
|
||||
// If the MotorApi is enabled, get the recommended order items based on the vehicle plate
|
||||
$MotorApi = new motorapi();
|
||||
if ($MotorApi->config->enabled->isTrue()) {
|
||||
$MotorApi_data = $MotorApi->getRecommendedProducts($plate);
|
||||
if ($MotorApi_data) {
|
||||
// Get the recommended order items based on the vehicle plate
|
||||
$result['motorapi'] = $MotorApi_data;
|
||||
}
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the last orders item ids for a vehicle plate
|
||||
* @param string $plate The vehicle plate
|
||||
* @return array The last order item ids
|
||||
*/
|
||||
public function get_vehicle_last_orders_items(string $plate): array
|
||||
{
|
||||
global /** @var db $db */
|
||||
$db;
|
||||
$sql = "SELECT id FROM $this->table WHERE reg_1 = '$plate' OR reg_2 = '$plate' OR reg_3 = '$plate' AND deleted_at IS NULL ORDER BY id DESC LIMIT 5";
|
||||
$result = $db->query($sql);
|
||||
$orders = $db->fetch_all($result);
|
||||
$order_items = [
|
||||
1 => [],
|
||||
2 => [],
|
||||
3 => [],
|
||||
4 => [],
|
||||
5 => [],
|
||||
];
|
||||
// Get the order item (ids) from the last 5 orders
|
||||
$index = 0;
|
||||
foreach ( $orders as $order ) {
|
||||
$index++;
|
||||
$order_tmp = new orders_o();
|
||||
// Get the order items for the order
|
||||
$items_tmp = $order_tmp->getOrderItems($order['id']);
|
||||
// Add the items to the result
|
||||
foreach ( $items_tmp as $item ) {
|
||||
$order_items[$index][] = [
|
||||
'product_id' => $item['product_id'],
|
||||
'reference' => $item['reference'],
|
||||
'quantity' => $item['quantity'],
|
||||
'product' => $item['product'],
|
||||
];
|
||||
}
|
||||
}
|
||||
return $order_items;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the order history for a vehicle plate
|
||||
* @param string $plate The vehicle plate
|
||||
* @return array The order history
|
||||
*/
|
||||
public function get_vehicle_order_history(string $plate): array
|
||||
{
|
||||
global $db;
|
||||
$sql = "SELECT * FROM $this->table WHERE reg_1 = '$plate' OR reg_2 = '$plate' OR reg_3 = '$plate' AND deleted_at IS NULL ORDER BY id DESC LIMIT 5";
|
||||
$result = $db->query($sql);
|
||||
return $db->fetch_all($result);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,8 @@ class product_options_o extends db
|
||||
public object_property $product_id;
|
||||
public object_property $option_id;
|
||||
public object_property $name;
|
||||
public object_property $min;
|
||||
public object_property $max;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -43,6 +45,8 @@ class product_options_o extends db
|
||||
$this->product_id = new object_property($this->table, $this->id, 'product_id', 'int', false);
|
||||
$this->option_id = new object_property($this->table, $this->id, 'option_id', 'int', false);
|
||||
$this->name = new object_property($this->table, $this->id, 'name', 'string', false);
|
||||
$this->min = new object_property($this->table, $this->id, 'min', 'int', false);
|
||||
$this->max = new object_property($this->table, $this->id, 'max', 'int', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
@@ -50,6 +54,18 @@ class product_options_o extends db
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* There's no need to keep track of when a product option is deleted,
|
||||
* so we just forcefully delete it.
|
||||
* @throws Exception If the object was not selected
|
||||
* @throws Exception If the object was not deleted successfully
|
||||
*/
|
||||
public function delete(): void
|
||||
{
|
||||
self::requireSelected();
|
||||
self::deletePermanently();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the name of the product option
|
||||
* @param string $name
|
||||
@@ -58,10 +74,60 @@ class product_options_o extends db
|
||||
public function set_name(string $name): void
|
||||
{
|
||||
self::requireSelected();
|
||||
// If the string is empty, set it to null
|
||||
if (empty($name)) {
|
||||
$this->name->nullify();
|
||||
self::objectChanged();
|
||||
return;
|
||||
}
|
||||
$this->name->set($name);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the min value of the product option
|
||||
* @param int|null $min
|
||||
* @notation If the int is less than 1 or empty, set it to null
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function set_min(int|null $min): void
|
||||
{
|
||||
self::requireSelected();
|
||||
// If the int is empty, set it to null
|
||||
if (empty($min) || $min < 1) {
|
||||
$this->min->nullify();
|
||||
self::objectChanged();
|
||||
return;
|
||||
}
|
||||
$this->min->set($min);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Set the max value of the product option
|
||||
* @param int|null $max
|
||||
* @notation If the int is less than 1, or empty, it will be set to null
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function set_max(int|null $max): void
|
||||
{
|
||||
self::requireSelected();
|
||||
// If the int is empty, set it to null
|
||||
if (empty($max) || $max < 1) {
|
||||
$this->max->nullify();
|
||||
self::objectChanged();
|
||||
return;
|
||||
}
|
||||
$this->max->set($max);
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all options for a product
|
||||
* @param int $id The id of the product
|
||||
* @return array
|
||||
* @throws Exception If the object was not selected
|
||||
*/
|
||||
public function getProductOptions(int $id): array
|
||||
{
|
||||
$options = self::getFieldsWhere(['product_id' => $id],
|
||||
@@ -70,6 +136,8 @@ class product_options_o extends db
|
||||
'product_id',
|
||||
'option_id',
|
||||
'name',
|
||||
'min',
|
||||
'max',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
]
|
||||
@@ -82,6 +150,8 @@ class product_options_o extends db
|
||||
'product_id' => (int)$option['product_id'],
|
||||
'option_id' => (int)$option['option_id'],
|
||||
'name' => (string)$option['name'] === '' ? $tmp_product['name'] : (string)$option['name'],
|
||||
'min' => $option['min'] === null ? null : (int)$option['min'],
|
||||
'max' => $option['max'] === null ? null : (int)$option['max'],
|
||||
'created_at' => (string)$option['created_at'],
|
||||
'updated_at' => (string)$option['updated_at'],
|
||||
'product' => $tmp_product
|
||||
@@ -89,4 +159,14 @@ class product_options_o extends db
|
||||
}
|
||||
return $tmp;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all products with a specific option
|
||||
* @param int $product_id The id of the addon product
|
||||
* @return array
|
||||
*/
|
||||
public function getOptionProducts(int $product_id): array
|
||||
{
|
||||
return self::getFieldsWhere(['option_id' => $product_id], ['product_id']);
|
||||
}
|
||||
}
|
||||
@@ -45,6 +45,21 @@ class products_o extends db
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $apply_category_discount;
|
||||
/**
|
||||
* Whether the product requires a note
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $requires_note;
|
||||
/**
|
||||
* The timestamp of when the object was created
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $created_at;
|
||||
/**
|
||||
* The timestamp of when the object was last updated
|
||||
* @var object_property
|
||||
*/
|
||||
public object_property $updated_at;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -78,6 +93,9 @@ class products_o extends db
|
||||
$this->piktogram = new object_property($this->table, $this->id, 'piktogram', 'string', false);
|
||||
$this->economic_product_id = new object_property($this->table, $this->id, 'economic_product_id', 'int', false);
|
||||
$this->apply_category_discount = new object_property($this->table, $this->id, 'apply_category_discount', 'bool', false);
|
||||
$this->requires_note = new object_property($this->table, $this->id, 'requires_note', 'bool', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
|
||||
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
|
||||
}
|
||||
|
||||
public function add(string $name, string $description, int $price, string|bool $category = false, string|bool $piktogram = false, string|bool $economicProductId = false): void
|
||||
@@ -162,7 +180,10 @@ class products_o extends db
|
||||
'category' => $this->category->value(),
|
||||
'piktogram' => $this->piktogram->value(),
|
||||
'economic_product_id' => $this->economic_product_id->value(),
|
||||
'apply_category_discount' => (bool)$this->apply_category_discount->value()
|
||||
'apply_category_discount' => (bool)$this->apply_category_discount->value(),
|
||||
'requires_note' => (bool)$this->requires_note->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
'updated_at' => (string)$this->updated_at->value(),
|
||||
];
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<?php
|
||||
|
||||
namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use classes\stripe;
|
||||
use Exception;
|
||||
use Stripe\Exception\ApiErrorException;
|
||||
use traits\db_object_t;
|
||||
|
||||
class stripe_module_customers_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $email;
|
||||
|
||||
public object_property $customer_id;
|
||||
public object_property $created_at;
|
||||
private bool $paid;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
$this->setTable('stripe_module_customers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Add a customer to the database
|
||||
* @param string $email The customer's email address
|
||||
* @param string $customer_id The Stripe customer ID
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(string $email, string $customer_id): void
|
||||
{
|
||||
$tmp_id = self::add_object([
|
||||
'email' => $email,
|
||||
'customer_id' => $customer_id,
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
self::getObjectProperties();
|
||||
self::objectChanged();
|
||||
}
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->email = new object_property($this->table, $this->id, 'email', 'string', false);
|
||||
$this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false);
|
||||
}
|
||||
|
||||
public function objectChanged(): void
|
||||
{
|
||||
//TODO: Add cache invalidation
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiErrorException
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
$object = self::retrieveCustomer();
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'email' => $this->email->value(),
|
||||
'customer_id' => $this->customer_id->value(),
|
||||
'created_at' => $this->created_at->value(),
|
||||
'object' => $object
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws ApiErrorException
|
||||
* @throws Exception
|
||||
*/
|
||||
public function retrieveCustomer(): object
|
||||
{
|
||||
// Validate the object
|
||||
self::requireSelected();
|
||||
// Return the payment link
|
||||
return (new stripe())->customers->retrieve($this->customer_id->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a customer has an account
|
||||
* @param string $email
|
||||
* @return bool
|
||||
*/
|
||||
public function doesCustomerHaveAccount(string $email): bool
|
||||
{
|
||||
return (bool)self::getFieldsWhere(['email' => $email], ['id']);
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer ID from the email address
|
||||
* @param string $email
|
||||
* @return string
|
||||
*/
|
||||
public function getCustomerId(string $email): string
|
||||
{
|
||||
return self::getFieldsWhere(['email' => $email], ['customer_id'])[0]['customer_id'];
|
||||
}
|
||||
|
||||
}
|
||||
@@ -13,13 +13,13 @@ class stripe_module_orders_o extends db
|
||||
{
|
||||
use db_object_t;
|
||||
|
||||
public object_property $payment_link_id;
|
||||
public object_property $email;
|
||||
public object_property $invoice_id;
|
||||
|
||||
public object_property $customer_id;
|
||||
public object_property $email_sent;
|
||||
public object_property $url;
|
||||
|
||||
public object_property $created_at;
|
||||
|
||||
private bool $paid;
|
||||
|
||||
public function structure(): void
|
||||
{
|
||||
@@ -35,12 +35,12 @@ class stripe_module_orders_o extends db
|
||||
* @return void
|
||||
* @throws Exception If the object was not created successfully
|
||||
*/
|
||||
public function add(int $order_id, string $email, string $payment_link_id, string $url): void
|
||||
public function add(int $order_id, string $invoice_id, string $stripe_customer_id, string $url): void
|
||||
{
|
||||
$tmp_id = self::add_object([
|
||||
'id' => $order_id,
|
||||
'email' => $email,
|
||||
'payment_link_id' => $payment_link_id,
|
||||
'invoice_id' => $invoice_id,
|
||||
'customer_id' => $stripe_customer_id,
|
||||
'url' => $url,
|
||||
]);
|
||||
$this->id = $tmp_id;
|
||||
@@ -50,8 +50,8 @@ class stripe_module_orders_o extends db
|
||||
|
||||
public function getObjectProperties(): void
|
||||
{
|
||||
$this->payment_link_id = new object_property($this->table, $this->id, 'payment_link_id', 'string', false);
|
||||
$this->email = new object_property($this->table, $this->id, 'email', 'string', false);
|
||||
$this->invoice_id = new object_property($this->table, $this->id, 'invoice_id', 'string', false);
|
||||
$this->customer_id = new object_property($this->table, $this->id, 'customer_id', 'string', false);
|
||||
$this->email_sent = new object_property($this->table, $this->id, 'email_sent', 'timestamp', false);
|
||||
$this->url = new object_property($this->table, $this->id, 'url', 'string', false);
|
||||
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'timestamp', false);
|
||||
@@ -67,14 +67,17 @@ class stripe_module_orders_o extends db
|
||||
*/
|
||||
public function asArray(): array
|
||||
{
|
||||
$object = self::retrievePaymentLink();
|
||||
return [
|
||||
'id' => (int)$this->id,
|
||||
'payment_link_id' => (string)$this->payment_link_id->value(),
|
||||
'email' => (string)$this->email->value(),
|
||||
'email_sent' => $this->email_sent->value() ? (string)$this->email_sent->value() : null,
|
||||
'invoice_id' => (string)$this->invoice_id->value(),
|
||||
'customer_id' => (string)$this->customer_id->value(),
|
||||
'url' => (string)$this->url->value(),
|
||||
'created_at' => (string)$this->created_at->value(),
|
||||
'object' => self::retrievePaymentLink()
|
||||
'paid' => $object->paid,
|
||||
'status' => $object->status,
|
||||
'amount_due' => $object->amount_due,
|
||||
'amount_paid' => $object->amount_paid,
|
||||
];
|
||||
}
|
||||
|
||||
@@ -87,7 +90,7 @@ class stripe_module_orders_o extends db
|
||||
// Validate the object
|
||||
self::requireSelected();
|
||||
// Return the payment link
|
||||
return (new stripe())->payment_link->retrieve($this->payment_link_id->value());
|
||||
return (new stripe())->invoice->retrieve($this->invoice_id->value());
|
||||
}
|
||||
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace objects;
|
||||
|
||||
use classes\db;
|
||||
use classes\object_property;
|
||||
use Exception;
|
||||
use traits\db_object_t;
|
||||
|
||||
class user_key_value_pairs_o extends db
|
||||
@@ -39,6 +40,7 @@ class user_key_value_pairs_o extends db
|
||||
public function setValue($var, $val): user_key_value_pairs_o
|
||||
{
|
||||
global $db;
|
||||
self::requireSelected();
|
||||
// Avoid SQL injection
|
||||
$var = $db->escape_string($var);
|
||||
$val = $db->escape_string($val);
|
||||
@@ -54,9 +56,20 @@ class user_key_value_pairs_o extends db
|
||||
return $this;
|
||||
}
|
||||
|
||||
/**
|
||||
* @throws Exception
|
||||
*/
|
||||
public function requireSelected(): void
|
||||
{
|
||||
if (empty($this->user_id)) {
|
||||
throw new Exception('The user id is not set!.');
|
||||
}
|
||||
}
|
||||
|
||||
public function getValue($var): mixed
|
||||
{
|
||||
global $db;
|
||||
self::requireSelected();
|
||||
// Avoid SQL injection
|
||||
$var = $db->escape_string($var);
|
||||
// Get the record from the database
|
||||
@@ -71,6 +84,7 @@ class user_key_value_pairs_o extends db
|
||||
public function deleteValue($var): user_key_value_pairs_o
|
||||
{
|
||||
global $db;
|
||||
self::requireSelected();
|
||||
// Avoid SQL injection
|
||||
$var = $db->escape_string($var);
|
||||
// Create a new record in the database
|
||||
@@ -82,6 +96,7 @@ class user_key_value_pairs_o extends db
|
||||
public function getAllKeys(): array
|
||||
{
|
||||
global $db;
|
||||
self::requireSelected();
|
||||
// Get all the keys from the database
|
||||
$sql = "SELECT var, val FROM $this->table WHERE user_id = $this->user_id";
|
||||
$result = $db->query($sql);
|
||||
|
||||
@@ -147,17 +147,26 @@ class user_price_overrides_o extends db
|
||||
$prices = [];
|
||||
if ($result->num_rows > 0) {
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
// Parse the row
|
||||
$row['id'] = (int)$row['id'];
|
||||
$row['user_id'] = (int)$row['user_id'];
|
||||
$row['is_category'] = (bool)$row['is_category'];
|
||||
$row['product_or_category_id'] = (int)$row['product_or_category_id'];
|
||||
$row['percentage'] = (int)$row['percentage'];
|
||||
$row['created_at'] = (string)$row['created_at'];
|
||||
$row['updated_at'] = (string)$row['updated_at'];
|
||||
// Add the row to the list
|
||||
$prices[] = $row;
|
||||
}
|
||||
}
|
||||
// If the user has a global discount, add it to the list
|
||||
if ($economic_user_global_discount > 0) {
|
||||
$prices[] = [
|
||||
'id' => "999999",
|
||||
'user_id' => "" . $this->user_id,
|
||||
'is_category' => "1",
|
||||
'id' => (int)999999,
|
||||
'user_id' => (int)$this->user_id,
|
||||
'is_category' => true,
|
||||
'product_or_category_id' => "global",
|
||||
'percentage' => "" . $economic_user_global_discount,
|
||||
'percentage' => (int)$economic_user_global_discount,
|
||||
'created_at' => "2021-01-01 00:00:00",
|
||||
'updated_at' => "2021-01-01 00:00:00"
|
||||
];
|
||||
|
||||
@@ -8,6 +8,7 @@ use classes\object_property;
|
||||
use classes\response;
|
||||
use customers\economic_customer_mo;
|
||||
use customers\economicCustomers;
|
||||
use Exception;
|
||||
use languages\language_pack_en_us;
|
||||
use traits\db_object_t;
|
||||
|
||||
@@ -398,15 +399,6 @@ class users_o extends db
|
||||
return $this->doesUserHaveAttribute('requiresReferenceNumber');
|
||||
}
|
||||
|
||||
/**
|
||||
* If the customer should have an invoice per order (Otherwise, they will have a monthly invoice for all orders)
|
||||
* @return bool
|
||||
*/
|
||||
public function invoicePerOrder(): bool
|
||||
{
|
||||
return $this->doesUserHaveAttribute('invoiceAllOrdersIndividually');
|
||||
}
|
||||
|
||||
/**
|
||||
* If the customer is NOT allowed to purchase spot free washes
|
||||
* @return bool
|
||||
@@ -528,6 +520,19 @@ class users_o extends db
|
||||
$this->all_keys = $this->keys->setUser($this->id)->getAllKeys();
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the group of the user
|
||||
* @throws Exception If the user is not selected
|
||||
*/
|
||||
public function getGroup(): groups_o
|
||||
{
|
||||
self::requireSelected();
|
||||
// Get the group of the user
|
||||
$group = new groups_o();
|
||||
$group->select($this->group_id->value());
|
||||
return $group;
|
||||
}
|
||||
|
||||
public function getCode(): string|null
|
||||
{
|
||||
// Get the customer code
|
||||
@@ -858,4 +863,106 @@ class users_o extends db
|
||||
$user = self::getFieldsWhere(['customer_number' => $customerNumber], ['id']);
|
||||
return $user[0]['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the invoice collection ID, where the new order should be added to.
|
||||
* This is based on the user's settings. (If the user has the attribute 'invoiceAllOrdersIndividually', the new order should be added to a new invoice collection)
|
||||
* @return int The ID of the order invoice collection the new order should be added to.
|
||||
* @throws Exception
|
||||
*/
|
||||
public function getNewOrderInvoiceCollectionId(): int
|
||||
{
|
||||
// Check if the user has the attribute 'invoiceAllOrdersIndividually'
|
||||
$invoice_collection = new collected_order_invoices_o();
|
||||
if ($this->invoicePerOrder() || !self::hasOpenInvoiceCollection()) {
|
||||
// Require the user to have a customer number above 0
|
||||
if (is_null($this->customer_number->value()) || $this->customer_number->value() === 0) {
|
||||
throw new Exception('The user does not have a customer number');
|
||||
}
|
||||
// The user has the attribute 'invoiceAllOrdersIndividually', create a new invoice collection
|
||||
$invoice_collection->add((int)$this->customer_number->value());
|
||||
return $invoice_collection->id;
|
||||
}
|
||||
// The user does not have the attribute 'invoiceAllOrdersIndividually', get the ID of the last invoice collection
|
||||
return self::getOpenInvoiceCollection()->id;
|
||||
}
|
||||
|
||||
/**
|
||||
* If the customer should have an invoice per order (Otherwise, they will have a monthly invoice for all orders)
|
||||
* @return bool
|
||||
*/
|
||||
public function invoicePerOrder(): bool
|
||||
{
|
||||
return $this->doesUserHaveAttribute('invoiceAllOrdersIndividually');
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if the user has an open invoice collection
|
||||
* @return bool
|
||||
*/
|
||||
public function hasOpenInvoiceCollection(): bool
|
||||
{
|
||||
// Check if the user has an open invoice collection
|
||||
$invoice_collection = new collected_order_invoices_o();
|
||||
return $invoice_collection->hasOpenInvoiceCollection($this->customer_number->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the open invoice collection of the user
|
||||
* @return collected_order_invoices_o
|
||||
* @throws Exception If the user does not have an open invoice collection
|
||||
* @throws Exception If the user does not have a customer number
|
||||
*/
|
||||
public function getOpenInvoiceCollection(): collected_order_invoices_o
|
||||
{
|
||||
// Require the user to have a customer number above 0
|
||||
if (is_null($this->customer_number->value()) || $this->customer_number->value() === 0) {
|
||||
throw new Exception('The user does not have a customer number');
|
||||
}
|
||||
self::requireSelected();
|
||||
// Get the open invoice collection of the user
|
||||
$invoice_collection = new collected_order_invoices_o();
|
||||
return $invoice_collection->getLatestOpenInvoiceCollection($this->customer_number->value());
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all customers with the given attributes
|
||||
* @notation Retrieve all customers with ALL the given attributes
|
||||
* @param array $attributes The attributes to search for (e.g. ['attribute1', 'attribute2'])
|
||||
* @return array The e-conomic customer numbers with the given attributes (e.g. [123456, 654321])
|
||||
*/
|
||||
public function getCustomerNumbersWithAttributes(array $attributes): array
|
||||
{
|
||||
global $db;
|
||||
// Create an array to store the customer numbers
|
||||
$user_ids = [];
|
||||
$customer_numbers = [];
|
||||
// Loop through the attributes
|
||||
foreach ( $attributes as $attribute ) {
|
||||
// Get the customer numbers with the attribute
|
||||
$sql = "SELECT user_id FROM customer_attributes WHERE attribute = '$attribute'";
|
||||
$result = $db->query($sql);
|
||||
// Loop through the results
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
// Add the customer number to the array
|
||||
$user_ids[] = (int)$row['user_id'];
|
||||
}
|
||||
}
|
||||
// Remove duplicates from the array
|
||||
$user_ids = array_unique($user_ids);
|
||||
// Get the customer numbers from the user IDs
|
||||
foreach ( $user_ids as $user_id ) {
|
||||
// Get the customer number from the user ID
|
||||
$sql = "SELECT customer_number FROM $this->table WHERE id = $user_id";
|
||||
$result = $db->query($sql);
|
||||
// Loop through the results
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
// Add the customer number to the array
|
||||
$customer_numbers[] = (int)$row['customer_number'];
|
||||
}
|
||||
}
|
||||
// Remove duplicates from the array
|
||||
// Return the customer numbers
|
||||
return array_unique($customer_numbers);
|
||||
}
|
||||
}
|
||||
@@ -41,7 +41,12 @@ class bookingsRoute
|
||||
function ($booking) {
|
||||
$booking['department'] = (int)$booking['department'];
|
||||
return $booking;
|
||||
}
|
||||
},
|
||||
$bookings_o->forceRestrictFilters(
|
||||
[
|
||||
'department' => $user->getGroup()->getDepartments(),
|
||||
]
|
||||
)
|
||||
))
|
||||
);
|
||||
} else {
|
||||
@@ -50,7 +55,12 @@ class bookingsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_bookings' => 'List all bookings',
|
||||
'issue_wash_certificates' => 'When set, the response will include the wash certificate token for sending wash certificates'
|
||||
]
|
||||
);
|
||||
/** Own bookings */
|
||||
$this->get('/user/bookings', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -82,7 +92,11 @@ class bookingsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_own_bookings' => 'List all bookings for the logged in user'
|
||||
]
|
||||
);
|
||||
// Synchronize booking from the external system
|
||||
$this->post('/admin/bookings/sync', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -130,7 +144,11 @@ class bookingsRoute
|
||||
$response->success(
|
||||
['message' => 'Successfully synced booking']
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'sync_bookings' => 'Sync bookings from the external system NOTE: This permission is only required if the auth_key is not set'
|
||||
]
|
||||
);
|
||||
|
||||
// Get a departments unfulfilled bookings (count) for the day
|
||||
$this->get('/admin/bookings/department/count', function () {
|
||||
@@ -173,12 +191,17 @@ class bookingsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_department_bookings_count' => 'List the unfulfilled bookings count for a department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/user/bookings/washcertificate/download', function () {
|
||||
// Require the user to be logged in
|
||||
global /** @var response $response */
|
||||
$response;
|
||||
// Check if the user has access to the department
|
||||
$this->requirePermission('download_own_wash_certificate');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
@@ -206,7 +229,11 @@ class bookingsRoute
|
||||
$response->success(
|
||||
["link" => $wash_certificate_store->getWashCertificateDownload($id)]
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'download_own_wash_certificate' => 'Download the wash certificate for a booking'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/admin/bookings/delete', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -235,7 +262,11 @@ class bookingsRoute
|
||||
$response->success(
|
||||
["message" => "Booking deleted"]
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_booking' => 'Delete a booking'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/superuser/bookings/sync/all', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -256,7 +287,11 @@ class bookingsRoute
|
||||
$response->success(
|
||||
["message" => "All bookings synced"]
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'sync_all_bookings' => 'Sync all bookings from the external system'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/admin/bookings/completeWashWithoutWashCertificate', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -285,7 +320,11 @@ class bookingsRoute
|
||||
$response->success(
|
||||
["message" => "Wash completed without wash certificate"]
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'complete_wash_without_wash_certificate' => 'Complete a wash without a wash certificate'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/user/bookings/delete', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -314,6 +353,10 @@ class bookingsRoute
|
||||
$response->success(
|
||||
["message" => "Booking deleted"]
|
||||
);
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_own_booking' => 'Delete the users own booking'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -52,7 +52,11 @@ class categoriesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_categories' => 'List all categories'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/categories', function () {
|
||||
|
||||
@@ -85,7 +89,11 @@ class categoriesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_category' => 'Add a category'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/categories', function () {
|
||||
|
||||
@@ -127,6 +135,10 @@ class categoriesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_category' => 'Edit a category'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -43,6 +43,10 @@ class cronRoute
|
||||
'message' => 'All cron jobs ran successfully',
|
||||
'data' => $response_cron ?? []
|
||||
]);
|
||||
});
|
||||
},
|
||||
[
|
||||
'SUPERUSER_RUN_CRON' => 'Run cron jobs'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -47,7 +47,11 @@ class customerAttributes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_customer_attributes' => 'List all customer attributes'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/customer/attributes', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -78,7 +82,11 @@ class customerAttributes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_customer_attribute' => 'Add a customer attribute'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/customer/attributes', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -113,6 +121,10 @@ class customerAttributes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_customer_attribute' => 'Delete a customer attribute'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,7 +3,6 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\customer_notes_o;
|
||||
use objects\logs_o;
|
||||
use objects\users_o;
|
||||
use traits\route_t;
|
||||
@@ -25,7 +24,9 @@ class customerCodeDepartmentRoute
|
||||
// Get the query parameters from the URL
|
||||
$data = $_GET;
|
||||
// Check if the required fields are set
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id'])) { $response->error('User ID or Customer Number is required', 400); }
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id'])) {
|
||||
$response->error('User ID or Customer Number is required', 400);
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('customer_codes', 'global', 1, $user->id, 'GET_CUSTOMER_CODE', 'Successfully retrieved customer code');
|
||||
// Check if the user exists
|
||||
@@ -42,7 +43,11 @@ class customerCodeDepartmentRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'get_customer_code' => 'Get customer code'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/admin/customer/code', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -55,7 +60,9 @@ class customerCodeDepartmentRoute
|
||||
// Get the post data
|
||||
$data = json_decode(file_get_contents('php://input'), true);
|
||||
// Check if the required fields are set
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id']) && !isset($data['code'])) { $response->error('User ID, Customer Number, and Code are required', 400); }
|
||||
if (!isset($data['customer_number']) && !isset($data['user_id']) && !isset($data['code'])) {
|
||||
$response->error('User ID, Customer Number, and Code are required', 400);
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('customer_codes', 'global', 1, $user->id, 'ADD_CUSTOMER_CODE', 'Successfully added customer code');
|
||||
// Check if the user exists
|
||||
@@ -72,6 +79,10 @@ class customerCodeDepartmentRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_customer_code' => 'Add a customer code'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -45,7 +45,11 @@ class customerNotes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_customer_notes' => 'List all customer notes'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/customer/notes', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -81,7 +85,11 @@ class customerNotes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_customer_note' => 'Add a customer note'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/customer/notes', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -109,6 +117,10 @@ class customerNotes
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_customer_note' => 'Delete a customer note'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -14,6 +14,7 @@ class customerSearchRoute
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
//TODO: Remove this, this is deprecated in favor of the new search endpoint
|
||||
$this->post('/customers/search', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
@@ -47,12 +48,16 @@ class customerSearchRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'search_customers' => 'Search for customers'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/customers', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('list_customers');
|
||||
self::requirePermission('search_customers');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
@@ -100,7 +105,11 @@ class customerSearchRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'search_customers' => 'Search for customers, and list all customers if no search is provided'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
private static function parseFunction($collection, \Closure $param): array
|
||||
|
||||
@@ -0,0 +1,554 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\department_daily_reports_o;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class departmentDailyReportsRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->get('/departments/daily-reports', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_DAILY_REPORTS', 'Successfully listed departments daily reports');
|
||||
$department_daily_reports_o = new department_daily_reports_o();
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
$department_daily_reports_o
|
||||
->setSearchableFields([
|
||||
// The fields that can be searched. This would otherwise make it possible to get secret information from the database, simply by searching for it and getting the result count back
|
||||
'id',
|
||||
'water_usage',
|
||||
'water_usage_morning',
|
||||
'notes',
|
||||
'filled_by',
|
||||
'created_at',
|
||||
'department_id',
|
||||
])
|
||||
->listObjectsWithPaginationIfSet(
|
||||
function ($department_report) use ($user) {
|
||||
return [
|
||||
'id' => (int)$department_report['id'],
|
||||
'department_id' => (int)$department_report['department_id'],
|
||||
'water_usage' => (int)$department_report['water_usage'],
|
||||
'water_usage_morning' => (int)$department_report['water_usage_morning'],
|
||||
'notes' => (string)$department_report['notes'],
|
||||
'filled_by' => (int)$department_report['filled_by'],
|
||||
'created_at' => (string)$department_report['created_at'],
|
||||
];
|
||||
},
|
||||
// This makes sure that the user can only see reports from the departments they explicitly have access to
|
||||
$department_daily_reports_o->forceRestrictFilters(
|
||||
[
|
||||
// This makes sure that the user can only see orders from the departments they explicitly have access to
|
||||
'department_id' => $user->getGroup()->getDepartments(),
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_DAILY_REPORTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_daily_reports' => 'List the department daily reports, provided the user has access to the department',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/departments/daily-reports/get', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'id',
|
||||
'date'
|
||||
]
|
||||
);
|
||||
// Validate the department_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('id'),
|
||||
1
|
||||
);
|
||||
// Require the date to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'date',
|
||||
0
|
||||
);
|
||||
// Validate the date
|
||||
self::requireDateFormat(
|
||||
(string)self::getParameter('date'),
|
||||
self::FORMAT_DATE()
|
||||
);
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('id'));
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_DAILY_REPORTS', 'Successfully listed departments daily reports');
|
||||
// Return the list of departments
|
||||
$department_daily_reports_o = new department_daily_reports_o();
|
||||
try {
|
||||
$department_daily_report_latest = $department_daily_reports_o->selectDepartmentReportByDate(
|
||||
(int)self::getParameter('id'),
|
||||
(string)self::getParameter('date')
|
||||
);
|
||||
} catch (\Exception $e) {
|
||||
// Create a new department daily report if it does not exist
|
||||
$department_daily_report_latest = $department_daily_reports_o->add(
|
||||
(int)self::getParameter('id'),
|
||||
0,
|
||||
0,
|
||||
'',
|
||||
$user->id,
|
||||
(string)self::getParameter('date')
|
||||
);
|
||||
}
|
||||
$response->success(
|
||||
[
|
||||
'id' => (int)$department_daily_report_latest->id,
|
||||
'department_id' => (int)$department_daily_report_latest->department_id->value(),
|
||||
'water_usage' => (int)$department_daily_report_latest->water_usage->value(),
|
||||
'water_usage_morning' => (int)$department_daily_report_latest->water_usage_morning->value(),
|
||||
'notes' => (string)$department_daily_report_latest->notes->value(),
|
||||
'filled_by' => (int)$department_daily_report_latest->filled_by->value(),
|
||||
'created_at' => (string)$department_daily_report_latest->created_at->value(),
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_DAILY_REPORTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_daily_reports' => 'List the department daily reports, provided the user has access to the department',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/departments/daily-reports', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('create_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'department_id',
|
||||
'water_usage',
|
||||
'water_usage_morning',
|
||||
'notes',
|
||||
'date'
|
||||
]
|
||||
);
|
||||
// Validate the department_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('department_id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('department_id'),
|
||||
1
|
||||
);
|
||||
// Validate the water_usage
|
||||
self::requireType(
|
||||
(int)self::getParameter('water_usage'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the water_usage to be at least 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('water_usage'),
|
||||
0
|
||||
);
|
||||
// Validate the water_usage_morning
|
||||
self::requireType(
|
||||
(int)self::getParameter('water_usage_morning'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the water_usage_morning to be at least 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('water_usage_morning'),
|
||||
0
|
||||
);
|
||||
// Validate the notes
|
||||
self::requireType(
|
||||
(string)self::getParameter('notes'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the notes to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'notes',
|
||||
0
|
||||
);
|
||||
// Require the notes to be at most 4000 characters long
|
||||
self::requireMaxLength(
|
||||
'notes',
|
||||
4000
|
||||
);
|
||||
// Validate the date
|
||||
self::requireType(
|
||||
(string)self::getParameter('date'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the date to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'date',
|
||||
0
|
||||
);
|
||||
// Require the date to be at most 10 characters long
|
||||
self::requireMaxLength(
|
||||
'date',
|
||||
10
|
||||
);
|
||||
// Validate the date format (YYYY-MM-DD)
|
||||
self::requireDateFormat(
|
||||
(string)self::getParameter('date'),
|
||||
self::FORMAT_DATE()
|
||||
);
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('department_id'));
|
||||
// Check if there is already a report for today
|
||||
if ((new department_daily_reports_o())->hasReport((int)self::getParameter('department_id'), (string)self::getParameter('date'))) {
|
||||
$response->error('There is already a report for today', 400);
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'CREATE_DEPARTMENT_DAILY_REPORTS', 'Successfully created department daily report');
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
(new department_daily_reports_o())
|
||||
->add(
|
||||
(int)self::getParameter('department_id'),
|
||||
(int)self::getParameter('water_usage'),
|
||||
(int)self::getParameter('water_usage_morning'),
|
||||
(string)self::getParameter('notes'),
|
||||
$user->id
|
||||
)->asArray()
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'CREATE_DEPARTMENT_DAILY_REPORTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'create_department_daily_reports' => 'Create a new department daily report',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/departments/daily-reports', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('update_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'id',
|
||||
]
|
||||
);
|
||||
// Validate the id
|
||||
self::requireType(
|
||||
(int)self::getParameter('id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('id'),
|
||||
1
|
||||
);
|
||||
// Check which fields are set
|
||||
if (self::isParametersSet(['water_usage'])) {
|
||||
// Validate the water_usage
|
||||
self::requireType(
|
||||
(int)self::getParameter('water_usage'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the water_usage to be at least 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('water_usage'),
|
||||
0
|
||||
);
|
||||
}
|
||||
if (self::isParametersSet(['water_usage_morning'])) {
|
||||
// Validate the water_usage_morning
|
||||
self::requireType(
|
||||
(int)self::getParameter('water_usage_morning'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the water_usage_morning to be at least 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('water_usage_morning'),
|
||||
0
|
||||
);
|
||||
}
|
||||
if (self::isParametersSet(['notes'])) {
|
||||
// Validate the notes
|
||||
self::requireType(
|
||||
(string)self::getParameter('notes'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the notes to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
(string)self::getParameter('notes'),
|
||||
0
|
||||
);
|
||||
// Require the notes to be at most 4000 characters long
|
||||
self::requireMaxLength(
|
||||
(string)self::getParameter('notes'),
|
||||
4000
|
||||
);
|
||||
}
|
||||
// Check if the report exists
|
||||
// Update the department daily report
|
||||
$department_daily_reports_o = new department_daily_reports_o();
|
||||
$department_daily_report = $department_daily_reports_o->select((int)self::getParameter('id'));
|
||||
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)$department_daily_report->department_id->value());
|
||||
|
||||
// Check the parameters that are set
|
||||
if (self::isParametersSet(['water_usage'])) {
|
||||
$department_daily_report->water_usage->set((int)self::getParameter('water_usage'));
|
||||
}
|
||||
if (self::isParametersSet(['water_usage_morning'])) {
|
||||
$department_daily_report->water_usage_morning->set((int)self::getParameter('water_usage_morning'));
|
||||
}
|
||||
if (self::isParametersSet(['notes'])) {
|
||||
$department_daily_report->notes->set((string)self::getParameter('notes'));
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'UPDATE_DEPARTMENT_DAILY_REPORTS', 'Successfully updated department daily report');
|
||||
// Return the department daily report
|
||||
$response->success($department_daily_report->asArray());
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'UPDATE_DEPARTMENT_DAILY_REPORTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'update_department_daily_reports' => 'Update a department daily report',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/departments/daily-reports/product-count', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'date',
|
||||
'department_id',
|
||||
'product_id'
|
||||
]
|
||||
);
|
||||
// Validate the date
|
||||
self::requireType(
|
||||
(string)self::getParameter('date'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the date to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'date',
|
||||
0
|
||||
);
|
||||
// Require the date to be at most 10 characters long
|
||||
self::requireMaxLength(
|
||||
'date',
|
||||
10
|
||||
);
|
||||
// Validate the date format (YYYY-MM-DD)
|
||||
self::requireDateFormat(
|
||||
(string)self::getParameter('date'),
|
||||
'Y-m-d'
|
||||
);
|
||||
// Validate the department_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('department_id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('department_id'),
|
||||
1
|
||||
);
|
||||
// Validate the product_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('product_id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the product_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('product_id'),
|
||||
1
|
||||
);
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('department_id'));
|
||||
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'Successfully listed departments daily reports products');
|
||||
// Return the list of products sold on the selected date
|
||||
$response->success(
|
||||
[
|
||||
'quantity' =>
|
||||
(new department_daily_reports_o())
|
||||
->getProductsSoldOnDate(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id'),
|
||||
(int)self::getParameter('product_id')
|
||||
),
|
||||
'date' => (string)self::getParameter('date'),
|
||||
'department_id' => (int)self::getParameter('department_id'),
|
||||
'product_id' => (int)self::getParameter('product_id'),
|
||||
// This is the amount of products sold on the selected date, that this product could have been sold as a part of. (Addons)
|
||||
'out_of' => (int)(new department_daily_reports_o())->getProductsSoldWithAddonApplicable(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id'),
|
||||
(int)self::getParameter('product_id')
|
||||
)
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_daily_reports' => 'List the department daily reports, provided the user has access to the department',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/departments/daily-reports/transaction-count', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_department_daily_reports');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(
|
||||
[
|
||||
'date',
|
||||
'department_id'
|
||||
]
|
||||
);
|
||||
// Validate the date
|
||||
self::requireType(
|
||||
(string)self::getParameter('date'),
|
||||
self::type_string()
|
||||
);
|
||||
// Require the date to be at least 0 characters long
|
||||
self::requireMinLength(
|
||||
'date',
|
||||
0
|
||||
);
|
||||
// Require the date to be at most 10 characters long
|
||||
self::requireMaxLength(
|
||||
'date',
|
||||
10
|
||||
);
|
||||
// Validate the date format (YYYY-MM-DD)
|
||||
self::requireDateFormat(
|
||||
(string)self::getParameter('date'),
|
||||
'Y-m-d'
|
||||
);
|
||||
// Validate the department_id
|
||||
self::requireType(
|
||||
(int)self::getParameter('department_id'),
|
||||
self::type_int()
|
||||
);
|
||||
// Require the department_id to be above 0
|
||||
self::requireMinValue(
|
||||
(int)self::getParameter('department_id'),
|
||||
1
|
||||
);
|
||||
// Determine if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('department_id'));
|
||||
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'Successfully listed departments daily reports products');
|
||||
// Return the list of products sold on the selected date
|
||||
$response->success(
|
||||
[
|
||||
'quantity' =>
|
||||
(new department_daily_reports_o())
|
||||
->getTransactionsOnDateCount(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id')
|
||||
),
|
||||
'products' =>
|
||||
(new department_daily_reports_o())
|
||||
->getTransactionProductsOnDateCount(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id')
|
||||
),
|
||||
'earnings' =>
|
||||
(new department_daily_reports_o())
|
||||
->getTransactionsOnDateEarnings(
|
||||
(string)self::getParameter('date'),
|
||||
(int)self::getParameter('department_id')
|
||||
),
|
||||
'date' => (string)self::getParameter('date'),
|
||||
'department_id' => (int)self::getParameter('department_id')
|
||||
]
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_DAILY_REPORTS_PRODUCTS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_daily_reports' => 'List the department daily reports, provided the user has access to the department',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -7,6 +7,7 @@ use objects\categories_o;
|
||||
use objects\department_categories_o;
|
||||
use objects\departments_o;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use traits\route_t;
|
||||
|
||||
class departmentsRoute
|
||||
@@ -25,6 +26,15 @@ class departmentsRoute
|
||||
if ($user) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENTS', 'Successfully listed departments');
|
||||
// Check if the id is set in the request
|
||||
if (self::isParametersSet(['id'])) {
|
||||
// Return the department
|
||||
$response->success(
|
||||
(new departments_o())->select((int)self::getParameter('id'))->asArray([
|
||||
'slack_webhook' => $user->hasPermission('view_slack_webhook')
|
||||
])
|
||||
);
|
||||
}
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
(new departments_o())
|
||||
@@ -60,7 +70,12 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_departments' => 'List all departments',
|
||||
'view_slack_webhook' => 'View the slack webhook'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/departments', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -92,7 +107,11 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_department' => 'Add a department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/departments', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -128,7 +147,11 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_department' => 'Edit a department'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/departments/categories', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -176,7 +199,11 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_department_categories' => 'List all department categories'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/departments/categories', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -224,7 +251,11 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_department_category' => 'Add a department category'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/departments/categories', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -258,6 +289,46 @@ class departmentsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_department_category' => 'Delete a department category'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/departments/order/recommended', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('list_department_order_recommended');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::TYPE_INT());
|
||||
// Get the order
|
||||
$order = (new orders_o())->select((int)self::getParameter('id'));
|
||||
$order->requireSelected();
|
||||
// Check if the user is allowed to view the recommended order for the department
|
||||
self::requireDepartmentAccess($order->department_id->value());
|
||||
// Get the recommended order
|
||||
$recommended_order = $order->getRecommendedOrder();
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, $user->id, 'LIST_DEPARTMENT_ORDER_RECOMMENDED', 'Successfully listed the recommended department order');
|
||||
// Return the recommended order
|
||||
$response->success($recommended_order);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('departments', 'global', 1, 0, 'LIST_DEPARTMENT_ORDER_RECOMMENDED', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_order_recommended' => 'List the recommended department order',
|
||||
'order_access_:id' => 'Access the order',
|
||||
'department_access_:id' => 'Access the department'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -129,7 +129,9 @@ class economicInvoiceRoute
|
||||
(new logs_o())->add('economic_invoice_draft', 'global', 1, 0, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
'economic_invoice_draft_export' => 'Export an economic invoice draft'
|
||||
]);
|
||||
|
||||
$this->delete('/economic/invoice/draft/delete', function () {
|
||||
|
||||
@@ -177,7 +179,9 @@ class economicInvoiceRoute
|
||||
(new logs_o())->add('economic_invoice_draft', 'global', 1, 0, 'ECONOMIC_INVOICE_DRAFT_DELETE', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
'economic_invoice_draft_delete' => 'Delete an economic invoice draft'
|
||||
]);
|
||||
|
||||
$this->post('/economic/invoice/export', function () {
|
||||
global $response;
|
||||
@@ -237,7 +241,9 @@ class economicInvoiceRoute
|
||||
(new logs_o())->add('economic_invoice', 'global', 1, 0, 'ECONOMIC_INVOICE_EXPORT', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
'economic_invoice_export' => 'Export an economic invoice'
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -33,6 +33,10 @@ class economicLayoutsRoute
|
||||
(new logs_o())->add('economic_layouts', 'global', 1, 0, 'ECONOMIC_LAYOUTS', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_layouts' => 'Get economic layouts'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\form;
|
||||
use Exception;
|
||||
use traits\route_t;
|
||||
|
||||
class formRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->get('/form', function () {
|
||||
global $response;
|
||||
$form_identifier = $this->validateFormIdentifier();
|
||||
|
||||
$form = new form();
|
||||
|
||||
if (!$form->doesFormExist($form_identifier)) {
|
||||
$response->error('Form does not exist', 400);
|
||||
}
|
||||
|
||||
$response->success(
|
||||
$form->getForm($form_identifier)->asArray()
|
||||
);
|
||||
});
|
||||
|
||||
$this->post('/form', function () {
|
||||
global $response;
|
||||
$form_identifier = $this->validateFormIdentifier();
|
||||
|
||||
$form = new form();
|
||||
|
||||
if (!$form->doesFormExist($form_identifier)) {
|
||||
$response->error('Form does not exist', 400);
|
||||
}
|
||||
|
||||
$form->submitForm(
|
||||
$form->getForm($form_identifier)
|
||||
);
|
||||
|
||||
$response->success(
|
||||
'Form submitted successfully'
|
||||
);
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Validates the 'form_identifier' parameter and returns it in uppercase.
|
||||
* @return string Validated and transformed form identifier.
|
||||
* @throws Exception if validation fails.
|
||||
*/
|
||||
private function validateFormIdentifier(): string
|
||||
{
|
||||
self::requireParameters(['id']);
|
||||
|
||||
$form_identifier = self::getParameter('id');
|
||||
|
||||
self::requireType($form_identifier, self::type_string());
|
||||
self::requireMinLength('id', 1);
|
||||
self::requireMaxLength('id', 255);
|
||||
|
||||
return strtoupper($form_identifier);
|
||||
}
|
||||
}
|
||||
@@ -36,6 +36,10 @@ class intimidateRoute
|
||||
$token = (new authentication())->create_employee_token($data['user_id']);
|
||||
// Return the token
|
||||
$response->success(['token' => $token]);
|
||||
});
|
||||
},
|
||||
[
|
||||
'SUPERUSER_INTIMIDATE' => 'Intimidate a user'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -49,7 +49,11 @@ class invoicesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'get_invoice_draft' => 'Get invoice draft'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/invoices/draft/close', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -82,7 +86,11 @@ class invoicesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'close_invoice_draft' => 'Close invoice draft'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/invoices/pdf', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -123,6 +131,10 @@ class invoicesRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'get_invoice_pdf' => 'Get invoice pdf'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -34,7 +34,11 @@ class moduleBackupsRoute
|
||||
(new logs_o())->add('modules_backup', 'global', 1, 0, 'MODULES_BACKUP', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_backup_list' => 'List all backup modules'
|
||||
]
|
||||
);
|
||||
|
||||
/** Modules > Backups > POST */
|
||||
$this->post('/modules/backup/backups', function () {
|
||||
@@ -54,6 +58,10 @@ class moduleBackupsRoute
|
||||
(new logs_o())->add('modules_backup', 'global', 1, 0, 'MODULES_BACKUP', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_backup_create' => 'Create a backup module'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -39,7 +39,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('economic_config', 'global', 1, 0, 'ECONOMIC_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_config' => 'Get economic config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Economic config > POST */
|
||||
$this->post('/economic/config', function () {
|
||||
@@ -55,7 +59,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('economic_config', 'global', 1, 0, 'ECONOMIC_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_config' => 'Update economic config'
|
||||
]
|
||||
);
|
||||
|
||||
/** reCAPTCHA config > GET */
|
||||
$this->get('/reCAPTCHA/config', function () {
|
||||
@@ -71,7 +79,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, 0, 'RECAPTCHA_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'recaptcha_config' => 'Get recaptcha config'
|
||||
]
|
||||
);
|
||||
|
||||
/** reCAPTCHA config > POST */
|
||||
$this->post('/reCAPTCHA/config', function () {
|
||||
@@ -87,7 +99,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('recaptcha_config', 'global', 1, 0, 'RECAPTCHA_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'recaptcha_config' => 'Update recaptcha config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Email config > GET */
|
||||
$this->get('/email/config', function () {
|
||||
@@ -103,7 +119,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('email_config', 'global', 1, 0, 'EMAIL_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'email_config' => 'Get email config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Email config > POST */
|
||||
$this->post('/email/config', function () {
|
||||
@@ -119,7 +139,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('email_config', 'global', 1, 0, 'EMAIL_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'email_config' => 'Update email config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Email config > TEST */
|
||||
$this->post('/email/config/test', function () {
|
||||
@@ -146,7 +170,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('email_config', 'global', 1, 0, 'EMAIL_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'email_config' => 'Test email config'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/backups/config', function () {
|
||||
global $response;
|
||||
@@ -161,7 +189,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('backups_config', 'global', 1, 0, 'BACKUPS_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'backups_config' => 'Get backups config'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/backups/config', function () {
|
||||
global $response;
|
||||
@@ -176,7 +208,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('backups_config', 'global', 1, 0, 'BACKUPS_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'backups_config' => 'Update backups config'
|
||||
]
|
||||
);
|
||||
|
||||
/** MotorAPI config > GET */
|
||||
$this->get('/motorapi/config', function () {
|
||||
@@ -192,7 +228,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('motorapi_config', 'global', 1, 0, 'MOTORAPI_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'motorapi_config' => 'Get motorapi config'
|
||||
]
|
||||
);
|
||||
|
||||
/** MotorAPI config > POST */
|
||||
$this->post('/motorapi/config', function () {
|
||||
@@ -208,7 +248,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('motorapi_config', 'global', 1, 0, 'MOTORAPI_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'motorapi_config' => 'Update motorapi config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Stripe config > GET */
|
||||
$this->get('/stripe/config', function () {
|
||||
@@ -224,7 +268,11 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('stripe_config', 'global', 1, 0, 'STRIPE_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'stripe_config' => 'Get stripe config'
|
||||
]
|
||||
);
|
||||
|
||||
/** Stripe config > POST */
|
||||
$this->post('/stripe/config', function () {
|
||||
@@ -240,6 +288,10 @@ class moduleConfigRoute
|
||||
(new logs_o())->add('stripe_config', 'global', 1, 0, 'STRIPE_CONFIG', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'stripe_config' => 'Update stripe config'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,47 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\economic;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class moduleEconomicCustomerRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
/** @var router $router */
|
||||
$router, $response;
|
||||
|
||||
|
||||
/** Modules > Economic > Customer > Get customer */
|
||||
$this->get('/modules/economic/customer', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_economic_customer_get');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
self::requireParameters(['customer_number']);
|
||||
self::requireType('customer_number', self::type_int());
|
||||
self::requireMinLength('customer_number', 1);
|
||||
self::requireMaxLength('customer_number', 10);
|
||||
(new logs_o())->add('modules_economic', 'global', 1, 0, 'MODULES_ECONOMIC', 'User accessed the customer');
|
||||
$result = (new economic())->getCustomer((int)$_GET['customer_number']);
|
||||
$response->success((object)$result);
|
||||
} else {
|
||||
(new logs_o())->add('modules_economic', 'global', 0, 0, 'MODULES_ECONOMIC', 'User tried to access the customer without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_economic_customer_get' => 'Get customer'
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -57,7 +57,11 @@ class moduleEconomicRoute
|
||||
(new logs_o())->add('economic', 'global', 1, 0, 'ECONOMIC_IMPORT_CUSTOMER', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_import_customer' => 'Import customer from economic'
|
||||
]
|
||||
);
|
||||
|
||||
/** Economic > Departments > GET */
|
||||
self::get('/economic/departments', function () {
|
||||
@@ -89,7 +93,11 @@ class moduleEconomicRoute
|
||||
// Return the error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_departments_get' => 'Get departments from economic'
|
||||
]
|
||||
);
|
||||
|
||||
/** Economic > Products > GET */
|
||||
self::get('/economic/products', function () {
|
||||
@@ -124,6 +132,10 @@ class moduleEconomicRoute
|
||||
// Return the error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'economic_products_get' => 'Get products from economic'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -31,13 +31,17 @@ class moduleMotorAPIRoute
|
||||
self::requireMinLength('license_plate', 1);
|
||||
self::requireMaxLength('license_plate', 10);
|
||||
(new logs_o())->add('modules_motorapi', 'global', 1, $user->id, 'MODULES_MOTORAPI', 'Successfully looked up license plate information');
|
||||
$result = (new motorapi())->getLicensePlateInformation($this->fromRequest('license_plate'));
|
||||
$result = (new motorapi())->getLicensePlateInformation($this->fromRequest('license_plate'), false);
|
||||
$response->success((object)$result);
|
||||
} else {
|
||||
(new logs_o())->add('modules_motorapi', 'global', 1, 0, 'MODULES_MOTORAPI', 'No user found, or invalid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
|
||||
},
|
||||
[
|
||||
'modules_motorapi_lookup' => 'Lookup license plate information'
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -3,11 +3,14 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\email;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use classes\stripe;
|
||||
use objects\departments_o;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use objects\stripe_module_customers_o;
|
||||
use traits\route_t;
|
||||
|
||||
class moduleStripeRoute
|
||||
@@ -34,7 +37,11 @@ class moduleStripeRoute
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the customers list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_stripe_customers_list' => 'List all customers'
|
||||
]
|
||||
);
|
||||
|
||||
/** Modules > Stripe > Products > List */
|
||||
$this->get('/modules/stripe/products', function () {
|
||||
@@ -49,7 +56,11 @@ class moduleStripeRoute
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the products list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_stripe_products_list' => 'List all products'
|
||||
]
|
||||
);
|
||||
|
||||
/** Modules > Stripe > Prices > List */
|
||||
$this->get('/modules/stripe/prices', function () {
|
||||
@@ -64,7 +75,11 @@ class moduleStripeRoute
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the prices list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_stripe_prices_list' => 'List all prices'
|
||||
]
|
||||
);
|
||||
|
||||
/** Modules > Stripe > Send Invoice */
|
||||
$this->post('/modules/stripe/invoice', function () {
|
||||
@@ -88,18 +103,188 @@ class moduleStripeRoute
|
||||
$order->requireSelected();
|
||||
// Log the action
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, $user->id, 'MODULES_STRIPE', 'User sent an invoice');
|
||||
$result = (new stripe())->payment_link->generate(
|
||||
(int)self::fromRequest('order_id'),
|
||||
(string)self::fromRequest('email')
|
||||
);
|
||||
// Create a customer account, if it doesn't exist
|
||||
$hasCustomerAccount = (new stripe_module_customers_o())->doesCustomerHaveAccount((string)self::fromRequest('email'));
|
||||
if (!$hasCustomerAccount) {
|
||||
$customer = (new stripe())->customers->create((string)self::fromRequest('email'));
|
||||
(new stripe_module_customers_o())->add((string)self::fromRequest('email'), $customer->id);
|
||||
} else {
|
||||
// Get the customer account by email
|
||||
$customer = (new stripe())->customers->retrieve(
|
||||
// Get the customer ID
|
||||
(new stripe_module_customers_o())
|
||||
->getCustomerId(
|
||||
(string)self::fromRequest('email')
|
||||
)
|
||||
);
|
||||
}
|
||||
// Create an invoice
|
||||
$invoice = (new stripe())->invoice->generate((int)self::fromRequest('order_id'), $customer->id);
|
||||
// Set the order stripe invoice details
|
||||
$order->setStripeInvoicing($result->id, (string)self::fromRequest('email'), $result->url);
|
||||
$order->setStripeInvoicing($invoice->id, $customer->id, $invoice->hosted_invoice_url);
|
||||
$email = new email();
|
||||
$email->sendStripeInvoiceEmail(
|
||||
(string)self::fromRequest('email'),
|
||||
null,
|
||||
$invoice->hosted_invoice_url,
|
||||
(int)self::fromRequest('order_id')
|
||||
);
|
||||
// Return the result
|
||||
$response->success((object)$result);
|
||||
$response->success((object)$invoice);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to send an invoice without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'modules_stripe_invoice_send' => 'Send invoice'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/modules/stripe/terminal/readers', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_stripe_terminal_readers_list');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the readers list');
|
||||
$result = (new stripe())->readers->list();
|
||||
$response->success((object)$result);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the readers list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_stripe_terminal_readers_list' => 'List all Stripe terminal readers'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/modules/stripe/terminal/locations', function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_stripe_terminal_locations_list');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the terminal locations list');
|
||||
$result = (new stripe())->readers->listLocations();
|
||||
$response->success((object)$result);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the terminal locations list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_stripe_terminal_locations_list' => 'List all Stripe terminal locations'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/modules/stripe/department/terminal/location',
|
||||
function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_stripe_department_terminal_location_list');
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
|
||||
// Require the id to be above 0
|
||||
if ((int)self::fromRequest('id') < 1) {
|
||||
$response->error('Invalid department ID', 400);
|
||||
}
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
// Make sure the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::fromRequest('id'));
|
||||
// Make sure the department exists
|
||||
$department = (new departments_o())->select((int)self::fromRequest('id'));
|
||||
$department->requireSelected();
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the department terminal location');
|
||||
// Get the department terminal location
|
||||
$isSet = $department->isStripeTerminalLocationSet();
|
||||
// Return the result if the department terminal location is set, otherwise return null
|
||||
$response->success([
|
||||
'id' => (
|
||||
$isSet
|
||||
? $department->getStripeTerminalLocation()
|
||||
: null
|
||||
)
|
||||
]);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the department terminal location without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_stripe_department_terminal_location_list' => 'List all department terminal location',
|
||||
'department_access_:id' => 'Access department. - :id'
|
||||
]
|
||||
);
|
||||
|
||||
self::post('/modules/stripe/department/terminal/location',
|
||||
function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_stripe_department_terminal_location_set');
|
||||
self::requireParameters(['id', 'location']);
|
||||
self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
|
||||
self::requireType((string)self::fromRequest('location'), 'string');
|
||||
self::requireMinLength('location', 1);
|
||||
self::requireMaxLength('location', 255);
|
||||
// Require the id to be above 0
|
||||
if ((int)self::fromRequest('id') < 1) {
|
||||
$response->error('Invalid department ID', 400);
|
||||
}
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
// Make sure the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::fromRequest('id'));
|
||||
// Make sure the department exists
|
||||
$department = (new departments_o())->select((int)self::fromRequest('id'));
|
||||
$department->requireSelected();
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User set the department terminal location');
|
||||
// Set the department terminal location
|
||||
$department->setStripeTerminalLocation((string)self::fromRequest('location'));
|
||||
// Return the result
|
||||
$response->success([
|
||||
'id' => $department->getStripeTerminalLocation()
|
||||
]);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to set the department terminal location without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_stripe_department_terminal_location_set' => 'Set department terminal location',
|
||||
'department_access_:id' => 'Access department. - :id'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/modules/stripe/department/terminal/readers',
|
||||
function () {
|
||||
global $response;
|
||||
self::requirePermission('modules_stripe_department_terminal_readers_list');
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::fromRequest('id'), self::TYPE_INT());
|
||||
// Require the id to be above 0
|
||||
if ((int)self::fromRequest('id') < 1) {
|
||||
$response->error('Invalid department ID', 400);
|
||||
}
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
// Make sure the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::fromRequest('id'));
|
||||
// Make sure the department exists
|
||||
$department = (new departments_o())->select((int)self::fromRequest('id'));
|
||||
$department->requireSelected();
|
||||
(new logs_o())->add('modules_stripe', 'global', 1, 0, 'MODULES_STRIPE', 'User accessed the department terminal readers');
|
||||
// Get the department terminal readers
|
||||
$readers = $department->getStripeTerminalReaders();
|
||||
// Return the result
|
||||
$response->success($readers);
|
||||
} else {
|
||||
(new logs_o())->add('modules_stripe', 'global', 0, 0, 'MODULES_STRIPE', 'User tried to access the department terminal readers without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'modules_stripe_department_terminal_readers_list' => 'List all department terminal readers',
|
||||
'department_access_:id' => 'Access department. - :id'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,178 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\logs_o;
|
||||
use objects\notifications_o;
|
||||
use traits\route_t;
|
||||
|
||||
class notificationsRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
$this->get('/notifications', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('list_notifications');
|
||||
// Check if the user has permission to list all notifications
|
||||
if (self::hasPermission('list_all_notifications')) {
|
||||
$this->requirePermission('list_all_notifications');
|
||||
} else {
|
||||
$this->requirePermission('list_own_notifications');
|
||||
}
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, $user->id, 'LIST_OWN_NOTIFICATIONS', 'User accessed the list of notifications');
|
||||
$notifications = new notifications_o();
|
||||
// Return the list of notifications
|
||||
$response->success(
|
||||
$notifications
|
||||
->setSearchableFields([
|
||||
// The fields that can be searched. This would otherwise make it possible to get secret information from the database, simply by searching for it and getting the result count back
|
||||
'id',
|
||||
'type',
|
||||
'user_id',
|
||||
'data',
|
||||
'created_at',
|
||||
'deleted_at',
|
||||
])
|
||||
->listObjectsWithPaginationIfSet(
|
||||
function ($notification) use ($notifications, $user) {
|
||||
$tmp_notification = [
|
||||
'id' => (int)$notification['id'],
|
||||
'type' => (string)$notification['type'],
|
||||
'user_id' => (int)$notification['user_id'],
|
||||
'data' => $notification['data'] ? $notifications->decodeData($notification['data']) : null,
|
||||
'created_at' => (string)$notification['created_at'],
|
||||
'deleted_at' => $notification['deleted_at'] ? (string)$notification['deleted_at'] : null,
|
||||
];
|
||||
return $tmp_notification;
|
||||
},
|
||||
$notifications->forceRestrictFilters(
|
||||
[
|
||||
// This makes sure that the user can only see their own notifications
|
||||
'user_id' => $user->id,
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, 0, 'LIST_OWN_NOTIFICATIONS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_notifications' => 'List notifications, provided the user has either list_all_notifications, or list_own_notifications permission',
|
||||
'list_own_notifications' => 'List all notifications for the logged in user',
|
||||
'list_all_notifications' => 'List all notifications for all users (superuser only)',
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/notifications', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('add_notification');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Get the post data
|
||||
$data = [];
|
||||
// Check if the required fields are set
|
||||
self::requireParameters(['type', 'user_id']);
|
||||
self::requireType((string)self::getParameter('type'), self::TYPE_STRING());
|
||||
self::requireType((int)self::getParameter('user_id'), self::TYPE_INT());
|
||||
// If the data is set, check if it is an array
|
||||
if (self::isParametersSet(['data'])) {
|
||||
self::requireTypeIn(
|
||||
(array)self::getParameter('data'),
|
||||
[
|
||||
self::TYPE_ARRAY(),
|
||||
self::TYPE_NULL()
|
||||
]
|
||||
);
|
||||
// Check if the data is an array
|
||||
if (self::getParameter('data') !== null) {
|
||||
// JSON decode the data
|
||||
$data = json_decode(self::getParameter('data'), true);
|
||||
}
|
||||
}
|
||||
// Check if the user_id is set
|
||||
// Add the notification
|
||||
(new notifications_o())->add(
|
||||
(string)self::getParameter('type'),
|
||||
(int)self::getParameter('user_id'),
|
||||
(array)$data
|
||||
);
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, $user->id, 'ADD_NOTIFICATION', 'User added a notification');
|
||||
// Return the list of departments
|
||||
$response->success(['message' => 'Notification added successfully']);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, 0, 'ADD_NOTIFICATION', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'add_notification' => 'Add a notification'
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->delete('/notifications', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('delete_own_notifications');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Require the parameters
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::TYPE_INT());
|
||||
// Get the department category object
|
||||
$notification = (new notifications_o())->select(self::getParameter('id'));
|
||||
// Validate the department category object
|
||||
if (!$notification->exists()) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, $user->id, 'DELETE_OWN_NOTIFICATIONS', 'User tried to delete a notification that does not exist');
|
||||
// Return an error
|
||||
$response->error('Notification does not exist', 400);
|
||||
}
|
||||
// Check if the user is the owner of the notification
|
||||
if ((int)$notification->user_id->value() !== (int)$user->id) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, $user->id, 'DELETE_OWN_NOTIFICATIONS', 'User tried to delete a notification that does not belong to them');
|
||||
// Return an error
|
||||
$response->error('You do not have permission to delete this notification', 403);
|
||||
}
|
||||
// Delete the department category
|
||||
$notification->delete();
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, $user->id, 'DELETE_OWN_NOTIFICATIONS', 'User deleted a notification');
|
||||
// Return the list of departments
|
||||
$response->success(['message' => 'Notification deleted successfully']);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('notifications', 'global', 1, 0, 'DELETE_OWN_NOTIFICATIONS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'delete_own_notifications' => 'Delete a notification'
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,224 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use objects\collected_order_invoices_o;
|
||||
use objects\logs_o;
|
||||
use objects\users_o;
|
||||
use traits\route_t;
|
||||
|
||||
class orderInvoicesRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
/** @var router $router */
|
||||
$router, $response;
|
||||
|
||||
/** Collected order invoices > GET */
|
||||
$this->get('/collected-invoices', function () {
|
||||
global $response;
|
||||
self::requirePermission('list_collected_invoices');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'LIST_COLLECTED_INVOICES', 'User accessed the list of collected order invoices');
|
||||
$collected_order_invoices = new collected_order_invoices_o();
|
||||
// Check if the request contains an ID
|
||||
if (self::isParametersSet(['id'])) {
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
$collected_order_invoices->select((int)self::getParameter('id'));
|
||||
$collected_order_invoices->requireSelected();
|
||||
$response->success($collected_order_invoices->asArray());
|
||||
}
|
||||
// Define the users
|
||||
$users = new users_o();
|
||||
// Define the collected order invoices
|
||||
$tmp_collected_order_invoices = new collected_order_invoices_o();
|
||||
// Return the list of collected order invoices
|
||||
$response->success($collected_order_invoices->listObjectsWithPaginationIfSet(
|
||||
function ($collected_order_invoice) use ($tmp_collected_order_invoices, $users) {
|
||||
// Select the orders for each collected order invoice
|
||||
$tmp_collected_order_invoices->select((int)$collected_order_invoice['id']);
|
||||
return [
|
||||
'id' => (int)$collected_order_invoice['id'],
|
||||
'name' => (string)$collected_order_invoice['name'],
|
||||
'notes' => (string)$collected_order_invoice['notes'],
|
||||
'customer_number' => (int)$collected_order_invoice['customer_number'],
|
||||
'customer_name' => (string)$users->getCustomerName((int)$collected_order_invoice['customer_number']),
|
||||
'processor' => $collected_order_invoice['processor'] ? (int)$collected_order_invoice['processor'] : null,
|
||||
'external_id' => (string)$collected_order_invoice['external_id'],
|
||||
'closed_at' => $collected_order_invoice['closed_at'] ? (string)$collected_order_invoice['closed_at'] : null,
|
||||
'updated_at' => (string)$collected_order_invoice['updated_at'],
|
||||
'created_at' => (string)$collected_order_invoice['created_at'],
|
||||
'orders' => $tmp_collected_order_invoices->getOrders(true),
|
||||
'total_net_amount' => (float)$tmp_collected_order_invoices->getTotalAmount()
|
||||
];
|
||||
},
|
||||
));
|
||||
} else {
|
||||
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES', 'User tried to access the list of collected order invoices without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_collected_invoices' => 'List ALL collected order invoices. This is a superuser-only route.'
|
||||
]
|
||||
);
|
||||
|
||||
/** Collected order invoices > Ready to invoice > GET */
|
||||
$this->get('/collected-invoices/ready-to-invoice', function () {
|
||||
global $response;
|
||||
self::requirePermission('list_collected_invoices');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'LIST_COLLECTED_INVOICES_READY_TO_INVOICE', 'User accessed the list of collected order invoices ready to invoice');
|
||||
$collected_order_invoices = new collected_order_invoices_o();
|
||||
// Define the users
|
||||
$users = new users_o();
|
||||
// Define the collected order invoices
|
||||
$tmp_collected_order_invoices = new collected_order_invoices_o();
|
||||
// Return the list of collected order invoices
|
||||
$response->success($collected_order_invoices->listObjectsWithPaginationIfSet(
|
||||
function ($collected_order_invoice) use ($tmp_collected_order_invoices, $users) {
|
||||
// Select the orders for each collected order invoice
|
||||
$tmp_collected_order_invoices->select((int)$collected_order_invoice['id']);
|
||||
return [
|
||||
'id' => (int)$collected_order_invoice['id'],
|
||||
'name' => (string)$collected_order_invoice['name'],
|
||||
'notes' => (string)$collected_order_invoice['notes'],
|
||||
'customer_number' => (int)$collected_order_invoice['customer_number'],
|
||||
'customer_name' => (string)$users->getCustomerName((int)$collected_order_invoice['customer_number']),
|
||||
'processor' => $collected_order_invoice['processor'] ? (int)$collected_order_invoice['processor'] : null,
|
||||
'external_id' => (string)$collected_order_invoice['external_id'],
|
||||
'closed_at' => $collected_order_invoice['closed_at'] ? (string)$collected_order_invoice['closed_at'] : null,
|
||||
'updated_at' => (string)$collected_order_invoice['updated_at'],
|
||||
'created_at' => (string)$collected_order_invoice['created_at'],
|
||||
'orders' => $tmp_collected_order_invoices->getOrders(true),
|
||||
'total_net_amount' => (float)$tmp_collected_order_invoices->getTotalAmount(),
|
||||
];
|
||||
},
|
||||
$collected_order_invoices->forceRestrictFilters(
|
||||
[
|
||||
// This makes sure that the user can only see orders from the departments they explicitly have access to
|
||||
'customer_number' => $collected_order_invoices->listCustomersWithIndividualOrderInvoicing(),
|
||||
]
|
||||
)
|
||||
));
|
||||
} else {
|
||||
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_READY_TO_INVOICE', 'User tried to access the list of collected order invoices ready to invoice without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_collected_invoices' => 'List ALL collected order invoices. This is a superuser-only route.'
|
||||
]
|
||||
);
|
||||
|
||||
/** Collected order invoices > POST */
|
||||
$this->post('/collected-invoices', function () {
|
||||
global $response;
|
||||
self::requirePermission('add_collected_invoice');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'ADD_COLLECTED_INVOICE', 'User added a collected order invoice');
|
||||
// Require the customer number, and validate its type and length
|
||||
self::requireParameters(['customer_number']);
|
||||
self::requireType((int)self::getParameter('customer_number'), 'int');
|
||||
self::requireMinLength('customer_number', 1);
|
||||
self::requireMaxLength('customer_number', 10);
|
||||
// Require the customer number to be above 0
|
||||
self::requireMinValue((int)self::getParameter('customer_number'), 1);
|
||||
// Validate the customer number against the database
|
||||
$customer = (new users_o())->select((int)self::getParameter('customer_number'));
|
||||
$customer->requireSelected();
|
||||
// Define the variables
|
||||
$name = null;
|
||||
$notes = null;
|
||||
$processor = null;
|
||||
// Check if the name is set
|
||||
if (self::isParametersSet(['name'])) {
|
||||
self::requireType((string)self::getParameter('name'), 'string');
|
||||
self::requireMinLength('name', 1);
|
||||
self::requireMaxLength('name', 255);
|
||||
$name = (string)self::getParameter('name');
|
||||
}
|
||||
// Check if the notes are set
|
||||
if (self::isParametersSet(['notes'])) {
|
||||
self::requireType((string)self::getParameter('notes'), 'string');
|
||||
$notes = (string)self::getParameter('notes');
|
||||
}
|
||||
// Check if the processor is set
|
||||
if (self::isParametersSet(['processor'])) {
|
||||
self::requireType((int)self::getParameter('processor'), 'int');
|
||||
$processor = (int)self::getParameter('processor');
|
||||
}
|
||||
// Add the collected order invoice
|
||||
$collected_order_invoices = new collected_order_invoices_o();
|
||||
$collected_order_invoices->add(
|
||||
$customer->id,
|
||||
$name,
|
||||
$notes,
|
||||
$processor
|
||||
);
|
||||
$response->success($collected_order_invoices->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'ADD_COLLECTED_INVOICE', 'User tried to add a collected order invoice without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'add_collected_invoice' => 'Add a collected order invoice. This is a superuser-only route.'
|
||||
]
|
||||
);
|
||||
|
||||
/** Collected order invoices > E-Conomic > POST */
|
||||
$this->post('/collected-invoices/economic', function () {
|
||||
global $response;
|
||||
self::requirePermission('add_collected_invoice_economic');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('orderInvoices', 'global', 1, $user->id, 'ADD_COLLECTED_INVOICE_ECONOMIC', 'User added a collected order invoice to E-Conomic');
|
||||
// Require the ID, and validate its type and length
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
self::requireMinLength('id', 1);
|
||||
self::requireMaxLength('id', 10);
|
||||
// Require the ID to be above 0
|
||||
self::requireMinValue((int)self::getParameter('id'), 1);
|
||||
// Validate the ID against the database
|
||||
$collected_order_invoices = (new collected_order_invoices_o())->select((int)self::getParameter('id'));
|
||||
$collected_order_invoices->requireSelected();
|
||||
// Check if the collected order invoice has an external ID
|
||||
if ($collected_order_invoices->external_id->value() === null) {
|
||||
// Add the collected order invoice to E-Conomic
|
||||
$collected_order_invoices->addToEconomic();
|
||||
$response->success($collected_order_invoices->asArray());
|
||||
}
|
||||
// Check if the invoice has been booked
|
||||
if ($collected_order_invoices->booked_invoice_id->value() !== null) {
|
||||
$response->error('Invoice has already been booked', 400);
|
||||
}
|
||||
// Check if the invoice draft exists in E-Conomic
|
||||
if ($collected_order_invoices->isDraftExisting()) {
|
||||
$response->error('Invoice draft already exists in E-Conomic', 400);
|
||||
}
|
||||
// Create the invoice in E-Conomic
|
||||
$collected_order_invoices->addToEconomic(true);
|
||||
// Return the collected order invoice
|
||||
$response->success($collected_order_invoices->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('orderInvoices', 'global', 0, 0, 'ADD_COLLECTED_INVOICE_ECONOMIC', 'User tried to add a collected order invoice to E-Conomic without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'add_collected_invoice_economic' => 'Add a collected order invoice to E-Conomic. This is a superuser-only route.'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -33,12 +33,38 @@ class orderItemsRoute
|
||||
if (!isset($data['quantity'])) {
|
||||
$response->error('Quantity is required', 400);
|
||||
}
|
||||
$related_item_id = null;
|
||||
// Check if the related_item_id is set
|
||||
if (self::isParametersSet(['related_item_id'])) {
|
||||
// Check if the related_item_id is null, if so continue
|
||||
if ($data['related_item_id'] !== null) {
|
||||
// Check if the related_item_id is a number
|
||||
if (!is_numeric($data['related_item_id'])) {
|
||||
$response->error('Related item ID must be a number', 400);
|
||||
}
|
||||
$related_item_id = (int)$data['related_item_id'];
|
||||
}
|
||||
}
|
||||
$notes = null;
|
||||
// Check if the notes is set
|
||||
if (self::isParametersSet(['notes'])) {
|
||||
// Check if the notes is null, if so continue
|
||||
if (self::getParameter('notes') !== null) {
|
||||
// Check if the notes is a string
|
||||
if (!is_string(self::getParameter('notes'))) {
|
||||
$response->error('Notes must be a string', 400);
|
||||
}
|
||||
$notes = (string)self::getParameter('notes');
|
||||
}
|
||||
}
|
||||
|
||||
// Add the order item to the order This is done individually, to make the notes to the individual order items possible
|
||||
(new order_items_o())->addItemToOrder((int)$data['order_id'], (int)$data['product_id'], (int)$user->id, (int)$data['quantity']);
|
||||
$order_items = (new order_items_o());
|
||||
// Add the order item to the order
|
||||
$order_items->addItemToOrder((int)$data['order_id'], (int)$data['product_id'], (int)$user->id, (int)$data['quantity'], $related_item_id, $notes);
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
['message' => 'Order items added']
|
||||
$order_items->getItemAsArray()
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
@@ -46,7 +72,11 @@ class orderItemsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_order_items' => 'Add order items'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/order/items', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -84,7 +114,11 @@ class orderItemsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_order_items' => 'List all order items'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/order/items', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -112,7 +146,11 @@ class orderItemsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_order_items' => 'Delete order items'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/order/items', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -154,6 +192,10 @@ class orderItemsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_order_items' => 'Edit order items'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\response;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use traits\route_t;
|
||||
@@ -15,25 +16,30 @@ class orderRoute
|
||||
{
|
||||
$this->get('/order', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
global /** @var response $response */
|
||||
$response;
|
||||
$this->requirePermission('fetch_order');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
$user = $response->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Make sure the order id is set
|
||||
if (!(int)$this->fromRequest('id')) {
|
||||
$response->error('Order id is required', 400);
|
||||
}
|
||||
$orders_o = new orders_o();
|
||||
|
||||
// Make sure the order exists
|
||||
if (!(new orders_o())->getOrderById($this->fromRequest('id'))->exists()) {
|
||||
if (!$orders_o->getOrderById($this->fromRequest('id'))->exists()) {
|
||||
$response->error('Order not found', 400);
|
||||
}
|
||||
// Log the incident
|
||||
(new logs_o())->add('orders', 'global', 1, $user->id, 'FETCH_ORDER', 'Successfully fetched order');
|
||||
// Check if the user has access to the department the order is in
|
||||
$this->requirePermission('department_access_' . $orders_o->department_id->value());
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
(new orders_o())->getOrderById($this->fromRequest('id'))->includeIncludes()->asArray()
|
||||
$orders_o->getOrderById($this->fromRequest('id'))->includeIncludes()->asArray()
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
@@ -41,7 +47,12 @@ class orderRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'fetch_order' => 'Fetch any order, provided the user has access to the department the order is in',
|
||||
'department_access_:id' => 'Access to the department the order is in'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/order', function () {
|
||||
|
||||
@@ -77,6 +88,10 @@ class orderRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'update_order' => 'Update order'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -4,10 +4,12 @@ namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\response;
|
||||
use objects\collected_order_invoices_o;
|
||||
use objects\departments_o;
|
||||
use objects\economic_module_orders;
|
||||
use objects\logs_o;
|
||||
use objects\orders_o;
|
||||
use objects\stripe_module_orders_o;
|
||||
use objects\users_o;
|
||||
use traits\route_t;
|
||||
|
||||
@@ -29,17 +31,40 @@ class ordersRoute
|
||||
(new logs_o())->add('orders', 'global', 1, $user->id, 'LIST_ORDERS', 'Successfully listed orders');
|
||||
// Create economic_module_orders object
|
||||
$economic_module_orders = new economic_module_orders();
|
||||
$orders = new orders_o();
|
||||
// Return the list of departments
|
||||
$response->success(
|
||||
(new orders_o())->listObjectsWithPaginationIfSet(
|
||||
$orders->listObjectsWithPaginationIfSet(
|
||||
function ($order) {
|
||||
// Add the invoice status to the order
|
||||
$order['economic_invoice_module'] = (new economic_module_orders())->getByOrderId($order['id'])->asArray();
|
||||
// Add the total amount to the order
|
||||
$order['total_net_amount'] = (new orders_o())->select($order['id'])->getNetAmount();
|
||||
// Add the stripe status to the order
|
||||
$stripe_module_orders = (new stripe_module_orders_o())->select($order['id']);
|
||||
if ($stripe_module_orders->exists()) {
|
||||
$order['stripe_invoice_module'] = $stripe_module_orders->asArray();
|
||||
}
|
||||
// If the invoice collection is set, add it to the order
|
||||
if (!empty($order['invoice_collection_id'])) {
|
||||
$order['invoice_collection'] = [
|
||||
'id' => $order['invoice_collection_id'],
|
||||
'closed_at' => (new collected_order_invoices_o())->select($order['invoice_collection_id'])->closed_at->value(),
|
||||
'booked_invoice_id' => (new collected_order_invoices_o())->select($order['invoice_collection_id'])->booked_invoice_id->value() ?? null,
|
||||
'processor' => (int)(new collected_order_invoices_o())->select($order['invoice_collection_id'])->processor->value() ?? null,
|
||||
];
|
||||
}
|
||||
// Add the customer name to the order
|
||||
$order['customer_name'] = (new users_o())->getCustomerName($order['customer_id']);
|
||||
/** @var array $order */
|
||||
return $order;
|
||||
}
|
||||
},
|
||||
$orders->forceRestrictFilters(
|
||||
[
|
||||
// This makes sure that the user can only see orders from the departments they explicitly have access to
|
||||
'department_id' => $user->getGroup()->getDepartments(),
|
||||
]
|
||||
)
|
||||
)
|
||||
);
|
||||
} else {
|
||||
@@ -48,7 +73,11 @@ class ordersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_orders' => 'List all orders'
|
||||
]
|
||||
);
|
||||
|
||||
|
||||
$this->post('/orders', function () {
|
||||
@@ -94,7 +123,11 @@ class ordersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_order' => 'Add an order'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/orders', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -146,7 +179,11 @@ class ordersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_order' => 'Edit an order'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/orders', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -180,7 +217,11 @@ class ordersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'delete_order' => 'Delete an order'
|
||||
]
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -193,6 +234,9 @@ class ordersRoute
|
||||
if (!isset($data['customer_id'])) {
|
||||
$response->error('Customer ID is required', 400);
|
||||
}
|
||||
if ((int)$data['customer_id'] < 1 || !is_numeric((int)$data['customer_id'])) {
|
||||
$response->error('Customer ID is required', 400);
|
||||
}
|
||||
if (!isset($data['department_id'])) {
|
||||
$response->error('Department ID is required', 400);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use classes\response;
|
||||
use classes\router;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class permissionsRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
global /** @var response $response */
|
||||
/** @var router $router */
|
||||
$router, $response;
|
||||
|
||||
|
||||
/** Permissions > List */
|
||||
$this->get('/permissions', function () {
|
||||
global $response, $router;
|
||||
$this->requirePermission('permissions_list');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('permissions', 'global', 1, 0, 'PERMISSIONS', 'User accessed the permissions list');
|
||||
$response->success($router->getPermissions());
|
||||
} else {
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'permissions_list' => 'List all permissions'
|
||||
]
|
||||
);
|
||||
|
||||
/** Permissions > User > List */
|
||||
self::get('/user/permissions', function () {
|
||||
global $response;
|
||||
self::requirePermission('permissions_list_own');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('permissions', 'global', 1, 0, 'PERMISSIONS', 'User accessed the user permissions list');
|
||||
$response->success((object)$user->getGroup()->getPermissions());
|
||||
} else {
|
||||
(new logs_o())->add('permissions', 'global', 0, 0, 'PERMISSIONS', 'User tried to access the user permissions list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'permissions_list_own' => 'List all user permissions'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -3,6 +3,7 @@
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\departments_o;
|
||||
use objects\logs_o;
|
||||
use objects\plate_scanners_o;
|
||||
use traits\route_t;
|
||||
@@ -41,7 +42,11 @@ class plateScannersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_number_plate_scanners' => 'List all number plate scanners'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/numberplatescanners', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -75,7 +80,11 @@ class plateScannersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_number_plate_scanner' => 'Add a number plate scanner'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/numberplatescanners', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -112,6 +121,59 @@ class plateScannersRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_number_plate_scanner' => 'Edit a number plate scanner'
|
||||
]
|
||||
);
|
||||
|
||||
self::get('/department/numberplatescanners', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('list_department_number_plate_scanners');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Get the department ID
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
self::requireParameterIntPositive((int)self::getParameter('id'), 'id');
|
||||
// Check if the user has access to the department
|
||||
self::requireDepartmentAccess((int)self::getParameter('id'));
|
||||
// Check if the department exists
|
||||
$department = (new departments_o())->select((int)self::getParameter('id'));
|
||||
$department->requireSelected();
|
||||
// Log the incident
|
||||
(new logs_o())->add('numberplatescanners', 'global', 1, $user->id, 'LIST_DEPARTMENT_NUMBER_PLATE_SCANNERS', 'Successfully listed department number plate scanners');
|
||||
// Get the department scanners.
|
||||
$result = (new plate_scanners_o())
|
||||
->getFieldsWhere([
|
||||
'department_id' => (int)self::getParameter('id')
|
||||
], [
|
||||
'id',
|
||||
'name',
|
||||
'notes'
|
||||
]);
|
||||
// Parse the result
|
||||
foreach ( $result as $key => $value ) {
|
||||
$result[$key]['id'] = (int)$value['id'];
|
||||
}
|
||||
// Return the list of plate scanners
|
||||
$response->success(
|
||||
$result
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('numberplatescanners', 'global', 1, 0, 'LIST_DEPARTMENT_NUMBER_PLATE_SCANNERS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_department_number_plate_scanners' => 'List all number plate scanners in a department',
|
||||
'department_access_:id' => 'Access department :id'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -67,7 +67,9 @@ class plateScansRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
'list_number_plate_scans_department' => 'List all number plate scans for a department'
|
||||
]);
|
||||
|
||||
$this->get('/numberplatescans', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -78,17 +80,53 @@ class plateScansRoute
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Get the number plate scans
|
||||
$number_plate_scans = (new plate_scans_o())->listObjectsWithPaginationIfSet();
|
||||
$number_plate_scans = (new plate_scans_o());
|
||||
$result = $number_plate_scans->listObjectsWithPaginationIfSet(null,
|
||||
$number_plate_scans->forceRestrictFilters(
|
||||
[
|
||||
'department_id' => $user->getGroup()->getDepartments()
|
||||
]
|
||||
)
|
||||
);
|
||||
// Log the incident
|
||||
(new logs_o())->add('numberplatescans', 'global', 1, $user->id, 'LIST_NUMBER_PLATE_SCANS', 'Successfully listed number plate scans');
|
||||
// Return the number plate scans
|
||||
$response->success($number_plate_scans);
|
||||
$response->success($result);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('numberplatescans', 'global', 1, 0, 'LIST_NUMBER_PLATE_SCANS', 'No user found, or invalid session');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
}, [
|
||||
'list_number_plate_scans' => 'List all number plate scans, provided the user has access to the department the number plate scan is in',
|
||||
'department_access_:id' => 'Access to the department the number plate scan is in'
|
||||
]);
|
||||
|
||||
self::get('/numberplatescans/post', function () {
|
||||
/**
|
||||
* This is here because the post method is not supported by the software some of the cameras are running on.
|
||||
*/
|
||||
global $response;
|
||||
self::requirePlateScannerAuth();
|
||||
$plate_scanner = (new authentication())->get_plate_scanner();
|
||||
self::requireParameters(['plate', 'token']);
|
||||
// Validate the plate
|
||||
self::requireType('plate', 'string');
|
||||
self::requireMinLength('plate', 1);
|
||||
self::requireMaxLength('plate', 10);
|
||||
// Validate the token
|
||||
self::requireType('token', 'string');
|
||||
self::requireMinLength('token', 1);
|
||||
self::requireMaxLength('token', 100);
|
||||
// Add the number plate scanner
|
||||
(new plate_scans_o())->add($plate_scanner->id, self::getParameter('plate'));
|
||||
// Log the incident
|
||||
(new logs_o())->add('numberplatescans', $plate_scanner->department_id->value(), 1, 0, 'ADD_NUMBER_PLATE_SCANS', 'Successfully added a number plate scan: ' . self::getParameter('plate'));
|
||||
// Return a success message
|
||||
$response->success(['message' => 'License plate scan recorded.', 'plate' => self::getParameter('plate'), 'scanner' => $plate_scanner->name->value()], 201);
|
||||
}, [
|
||||
'add_number_plate_scan' => 'Add a number plate scan'
|
||||
]);
|
||||
}
|
||||
}
|
||||
@@ -32,6 +32,11 @@ class productOptionsRoute
|
||||
'id',
|
||||
'product_id',
|
||||
'option_id',
|
||||
'name',
|
||||
'min',
|
||||
'max',
|
||||
'created_at',
|
||||
'updated_at'
|
||||
])
|
||||
->listObjectsWithPaginationIfSet(
|
||||
function ($option) use ($user) {
|
||||
@@ -40,6 +45,9 @@ class productOptionsRoute
|
||||
'id' => (int)$option['id'],
|
||||
'product_id' => (int)$option['product_id'],
|
||||
'option_id' => (int)$option['option_id'],
|
||||
'name' => (string)$option['name'],
|
||||
'min' => $option['min'] === null ? null : (int)$option['min'],
|
||||
'max' => $option['max'] === null ? null : (int)$option['max'],
|
||||
'created_at' => (string)$option['created_at'],
|
||||
'updated_at' => (string)$option['updated_at'],
|
||||
];
|
||||
@@ -52,7 +60,11 @@ class productOptionsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_product_options' => 'List all product options'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/product/options', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -86,7 +98,11 @@ class productOptionsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_product_option' => 'Add a product option'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/product/options', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -97,15 +113,37 @@ class productOptionsRoute
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required parameters are set
|
||||
self::requireParameters(['id', 'name']);
|
||||
self::requireParameters(['id']);
|
||||
// Check if the parameters are of the correct type
|
||||
self::requireType(self::getParameter('id'), self::TYPE_INT());
|
||||
// Create the object
|
||||
$product_options = new product_options_o();
|
||||
// Select the object
|
||||
$product_options->select(self::getParameter('id'));
|
||||
// Set the name
|
||||
$product_options->set_name(self::getParameter('name'));
|
||||
// Check what the user wants to edit
|
||||
|
||||
// Option name
|
||||
if (self::isParametersSet(['name'])) {
|
||||
// Check if the parameters are of the correct type
|
||||
self::requireType(self::getParameter('name'), self::TYPE_STRING());
|
||||
// Set the name
|
||||
$product_options->set_name(self::getParameter('name'));
|
||||
}
|
||||
// Option min
|
||||
if (self::isParametersSet(['min'])) {
|
||||
// Check if the parameters are of the correct type (Or NULL)
|
||||
self::requireTypeIn(self::getParameter('min'), [self::TYPE_INT(), self::TYPE_NULL()]);
|
||||
// Set the min value
|
||||
$product_options->set_min(self::getParameter('min'));
|
||||
}
|
||||
// Option max
|
||||
if (self::isParametersSet(['max'])) {
|
||||
// Check if the parameters are of the correct type
|
||||
self::requireType(self::getParameter('max'), self::TYPE_INT());
|
||||
// Set the max value
|
||||
$product_options->set_max(self::getParameter('max'));
|
||||
}
|
||||
|
||||
// Log the incident
|
||||
(new logs_o())->add('product_options', 'global', 1, $user->id, 'EDIT_PRODUCT_OPTION', 'User edited a product option');
|
||||
// Return the object
|
||||
@@ -118,6 +156,48 @@ class productOptionsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_product_option' => 'Edit a product option'
|
||||
]
|
||||
);
|
||||
|
||||
$this->delete('/product/options', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
$this->requirePermission('delete_product_option');
|
||||
// Get the user object
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the required parameters are set
|
||||
self::requireParameters(['id']);
|
||||
// Check if the parameters are of the correct type
|
||||
self::requireType((int)self::getParameter('id'), self::TYPE_INT());
|
||||
// Require the minimum value to be above 0
|
||||
self::requireMinValue((int)self::getParameter('id'), 1);
|
||||
// Create the object
|
||||
$product_options = new product_options_o();
|
||||
// Select the object
|
||||
$product_options->select((int)self::getParameter('id'));
|
||||
// Delete the object
|
||||
$product_options->delete();
|
||||
// Log the incident
|
||||
(new logs_o())->add('product_options', 'global', 1, $user->id, 'DELETE_PRODUCT_OPTION', 'User deleted a product option');
|
||||
// Return the object
|
||||
$response->success(
|
||||
'Product option deleted'
|
||||
);
|
||||
} else {
|
||||
// Log the incident
|
||||
(new logs_o())->add('product_options', 'global', 1, 0, 'DELETE_PRODUCT_OPTION', 'User tried to delete a product option without being logged in');
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'delete_product_option' => 'Delete a product option'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -25,7 +25,8 @@ class productsRoute
|
||||
'category' => (int)$product['category'],
|
||||
'piktogram' => (string)$product['piktogram'],
|
||||
'economic_product_id' => (int)$product['economic_product_id'],
|
||||
'apply_category_discount' => (int)$product['apply_category_discount'],
|
||||
'apply_category_discount' => (boolean)$product['apply_category_discount'],
|
||||
'requires_note' => (boolean)$product['requires_note'],
|
||||
'created_at' => (string)$product['created_at'],
|
||||
'updated_at' => (string)$product['updated_at'],
|
||||
'addons' => (new product_options_o())->getProductOptions($product['id'])
|
||||
@@ -39,6 +40,17 @@ class productsRoute
|
||||
$user = (new authentication())->get_user();
|
||||
// Check if the request was successful
|
||||
if ($user) {
|
||||
// Check if the id is set in the request
|
||||
if (self::isParametersSet(['id'])) {
|
||||
// Log the incident
|
||||
(new logs_o())->add('products', 'global', 1, $user->id, 'LIST_PRODUCTS', 'Successfully listed product with id ' . $response->getRequestParameter('id'));
|
||||
// Return the product
|
||||
$response->success(
|
||||
parseProduct(
|
||||
(new products_o())->select((int)self::getParameter('id'))->asArray()
|
||||
)
|
||||
);
|
||||
}
|
||||
// Check if the category is set in the request
|
||||
$data = $_GET ?? [];
|
||||
// Check if the category is set
|
||||
@@ -53,7 +65,9 @@ class productsRoute
|
||||
$products = (new products_o())->applyDepartmentPricing((array)$products, (int)$data['department_id']);
|
||||
}
|
||||
$response->success(
|
||||
$products
|
||||
array_map(function ($product) {
|
||||
return parseProduct($product);
|
||||
}, $products)
|
||||
);
|
||||
}
|
||||
// Log the incident
|
||||
@@ -81,7 +95,11 @@ class productsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'list_products' => 'List all products'
|
||||
]
|
||||
);
|
||||
|
||||
$this->post('/products', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -124,7 +142,11 @@ class productsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'add_product' => 'Add a product'
|
||||
]
|
||||
);
|
||||
|
||||
$this->put('/products', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -164,6 +186,9 @@ class productsRoute
|
||||
if (self::isParametersSet(['apply_category_discount'])) {
|
||||
$product->apply_category_discount->set($response->getRequestParameter('apply_category_discount') ? 1 : 0);
|
||||
}
|
||||
if (self::isParametersSet(['requires_note'])) {
|
||||
$product->requires_note->set($response->getRequestParameter('requires_note') ? 1 : 0);
|
||||
}
|
||||
(new logs_o())->add('products', 'global', 1, $user->id, 'EDIT_PRODUCT', 'Product id: ' . $id);
|
||||
// Return a success message
|
||||
$response->success(['message' => 'Product edited successfully']);
|
||||
@@ -173,6 +198,10 @@ class productsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'edit_product' => 'Edit a product'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,185 @@
|
||||
<?php
|
||||
|
||||
namespace routes;
|
||||
|
||||
use classes\authentication;
|
||||
use objects\groups_o;
|
||||
use objects\logs_o;
|
||||
use traits\route_t;
|
||||
|
||||
class rolesRoute
|
||||
{
|
||||
use route_t;
|
||||
|
||||
public function run(): void
|
||||
{
|
||||
self::get('/roles', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('list_roles');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('roles', 'global', 1, 0, 'ROLES', 'User accessed the roles list');
|
||||
$groups = new groups_o();
|
||||
// Check if the id parameter is set
|
||||
if (self::isParametersSet(['id'])) {
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
$groups->select((int)self::getParameter('id'));
|
||||
$groups->requireSelected();
|
||||
$response->success($groups->asArray());
|
||||
}
|
||||
// Return the list of roles
|
||||
$response->success($groups->listObjectsWithPaginationIfSet(
|
||||
function ($group) {
|
||||
return [
|
||||
'id' => (int)$group['id'],
|
||||
'name' => (string)$group['name'],
|
||||
'description' => (string)$group['description'],
|
||||
'created_at' => (string)$group['created_at'],
|
||||
'permissions' => (new groups_o())->select((int)$group['id'])->getPermissions()
|
||||
];
|
||||
}
|
||||
));
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to access the roles list without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'list_roles' => 'List all roles'
|
||||
]
|
||||
);
|
||||
|
||||
self::post('/roles', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('add_role');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
(new logs_o())->add('roles', 'global', 1, 0, 'ROLES', 'User added a role');
|
||||
self::requireParameters(['name', 'description']);
|
||||
self::requireType((string)self::getParameter('name'), 'string');
|
||||
self::requireType((string)self::getParameter('description'), 'string');
|
||||
$group = new groups_o();
|
||||
$group->add(
|
||||
(string)self::getParameter('name'),
|
||||
(string)self::getParameter('description')
|
||||
);
|
||||
$response->success($group->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to add a role without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'add_role' => 'Add a role'
|
||||
]
|
||||
);
|
||||
|
||||
self::put('/roles', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('edit_role');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
$group = new groups_o();
|
||||
$group->select((int)self::getParameter('id'));
|
||||
$group->requireSelected();
|
||||
// Check which parameters are set and update them
|
||||
if (self::isParametersSet(['name'])) {
|
||||
$group->name->set((string)self::getParameter('name'));
|
||||
}
|
||||
if (self::isParametersSet(['description'])) {
|
||||
$group->description->set((string)self::getParameter('description'));
|
||||
}
|
||||
(new logs_o())->add('roles', 'global', 1, $user->id, 'ROLES', 'User edited a role');
|
||||
$response->success($group->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to edit a role without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'edit_role' => 'Edit a role'
|
||||
]
|
||||
);
|
||||
|
||||
self::post('/roles/permissions', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('add_role_permission');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
self::requireParameters(['group_id', 'permission_id']);
|
||||
self::requireType((int)self::getParameter('group_id'), self::type_int());
|
||||
self::requireType((string)self::getParameter('permission_id'), 'string');
|
||||
$group = new groups_o();
|
||||
$group->select((int)self::getParameter('group_id'));
|
||||
$group->requireSelected();
|
||||
$group->addPermission((string)self::getParameter('permission_id'));
|
||||
(new logs_o())->add('roles', 'global', 1, $user->id, 'ROLES', 'User added a permission to a role');
|
||||
$response->success($group->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to add a permission to a role without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'add_role_permission' => 'Add a permission to a role'
|
||||
]
|
||||
);
|
||||
|
||||
self::delete('/roles/permissions', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('delete_role_permission');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
self::requireParameters(['group_id', 'permission_id']);
|
||||
self::requireType((int)self::getParameter('group_id'), self::type_int());
|
||||
self::requireMinLength('group_id', 1);
|
||||
self::requireType((string)self::getParameter('permission_id'), 'string');
|
||||
self::requireMinLength('permission_id', 1);
|
||||
$group = new groups_o();
|
||||
$group->select((int)self::getParameter('group_id'));
|
||||
$group->requireSelected();
|
||||
$group->removePermission((string)self::getParameter('permission_id'));
|
||||
(new logs_o())->add('roles', 'global', 1, $user->id, 'ROLES', 'User deleted a permission from a role');
|
||||
$response->success($group->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to delete a permission from a role without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'delete_role_permission' => 'Remove a permission from a role'
|
||||
]
|
||||
);
|
||||
|
||||
self::post('/roles/clone', function () {
|
||||
// Require the user to be logged in
|
||||
global $response;
|
||||
self::requirePermission('clone_role');
|
||||
$user = (new authentication())->get_user();
|
||||
if ($user) {
|
||||
self::requireParameters(['id']);
|
||||
self::requireType((int)self::getParameter('id'), self::type_int());
|
||||
$group = new groups_o();
|
||||
$group->select((int)self::getParameter('id'));
|
||||
$group->requireSelected();
|
||||
$group->clone($group->name->value() . ' - Klon', (string)$group->description->value());
|
||||
(new logs_o())->add('roles', 'global', 1, $user->id, 'ROLES', 'User cloned a role');
|
||||
$response->success($group->asArray());
|
||||
} else {
|
||||
(new logs_o())->add('roles', 'global', 0, 0, 'ROLES', 'User tried to clone a role without a valid session');
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
},
|
||||
[
|
||||
'clone_role' => 'Clone a role'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -30,6 +30,10 @@ class sessionRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'fetch_session' => 'Fetch session'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
@@ -42,7 +42,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_bookings_new' => 'List all new bookings'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Orders >> New orders */
|
||||
$this->get('/statistics/orders/new', function () {
|
||||
@@ -72,7 +76,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_orders_new' => 'List all new orders'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income */
|
||||
$this->get('/statistics/economic/totals', function () {
|
||||
@@ -102,7 +110,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income' => 'Get total income'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Department sent invoice totals */
|
||||
$this->get('/statistics/economic/totals/department_sent_invoice_totals', function () {
|
||||
@@ -132,7 +144,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_department_sent_invoice_totals' => 'Get department sent invoice totals'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Department draft invoice totals */
|
||||
$this->get('/statistics/economic/totals/department_draft_invoice_totals', function () {
|
||||
@@ -162,7 +178,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_department_draft_invoice_totals' => 'Get department draft invoice totals'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income today */
|
||||
$this->get('/statistics/income/today', function () {
|
||||
@@ -191,7 +211,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_today' => 'Get total income today'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income yesterday */
|
||||
$this->get('/statistics/income/yesterday', function () {
|
||||
@@ -220,7 +244,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_yesterday' => 'Get total income yesterday'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income this month */
|
||||
$this->get('/statistics/income/this-month', function () {
|
||||
@@ -249,7 +277,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_this_month' => 'Get total income this month'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income last month */
|
||||
$this->get('/statistics/income/last-month', function () {
|
||||
@@ -278,7 +310,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_last_month' => 'Get total income last month'
|
||||
]
|
||||
);
|
||||
|
||||
/** Statistics >> Economic >> Total income this year */
|
||||
$this->get('/statistics/income/this-year', function () {
|
||||
@@ -307,7 +343,11 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_this_year' => 'Get total income this year'
|
||||
]
|
||||
);
|
||||
|
||||
$this->get('/statistics/income/departments', function () {
|
||||
// Require the user to be logged in
|
||||
@@ -349,6 +389,10 @@ class statisticsRoute
|
||||
// Return an error
|
||||
$response->error('Invalid session', 400);
|
||||
}
|
||||
});
|
||||
},
|
||||
[
|
||||
'statistics_economic_income_today_departments' => 'Get total income today by departments'
|
||||
]
|
||||
);
|
||||
}
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user