Files
api/services/nginx/app/routes/economicInvoiceRoute.php
T

402 lines
21 KiB
PHP

<?php
namespace routes;
use classes\authentication;
use classes\response;
use classes\router;
use economic_invoice_draft_mo;
use objects\departments_o;
use objects\economic_module_orders;
use objects\logs_o;
use objects\orders_o;
use objects\users_o;
use traits\route_t;
class economicInvoiceRoute
{
use route_t;
public function run(): void
{
global /** @var response $response */
/** @var router $router */
$router, $response;
$this->post('/economic/invoice/draft/export', function () {
global $response;
$this->requirePermission('economic_invoice_draft_export');
$user = (new authentication())->get_user();
if ($user) {
$order_id = $response->getRequestParameter('order_id');
if (!isset($order_id)) {
$response->error('Order ID is required', 400);
}
// Validate the order ID is a number
if (!is_numeric($order_id)) {
$response->error('Order ID must be a number', 400);
}
$order = (new orders_o())->getOrderById($order_id);
// Check if the order exists
if (!$order->exists()) {
$response->error('Order not found', 404);
}
// Get the order items
$order_items = (new orders_o())->getOrderItems($order_id);
// Apply the department pricing
$order_items = (new orders_o())->applyDepartmentPrices($order_items, $order->department_id->value());
// Get the customer
$customer = (new orders_o())->getCustomerByOrderId($order_id);
// Check if the customer exists
if (!$customer->exists()) {
$response->error('Customer not found', 404);
}
// Get the customer economic number
$customer_economic = $customer->getCustomerEcocomicData()->economic_customer;
$economic_invoice_draft = (new economic_invoice_draft_mo());
// Set the customer number
$economic_invoice_draft->setCustomerNumber((int)$customer_economic->customer_number);
// Set the recipient
$economic_invoice_draft->setRecipient(
$customer_economic->name ?? 'Ukendt',
$customer_economic->address ?? 'Ukendt',
$customer_economic->zip ?? 'Ukendt',
$customer_economic->city ?? 'Ukendt'
);
// Make sure there are order items
if (count($order_items) === 0) {
$response->error('No order items found', 404);
}
// Get the department
$department = (new departments_o())->getDepartmentById($order->department_id->value());
// Add the department, date, reference
$this->addTheDepartmentDateReference($economic_invoice_draft, $department['name'], $order);
// Add the lines to the invoice
foreach ( $order_items as $order_item ) {
// Add the order item to the invoice draft
$this->addOrderItemToInvoice(
$customer,
$order,
$order_item,
$economic_invoice_draft,
$order_item['quantity'] ?? 1);
}
// Check if the user has an open invoice draft
$hasOpenInvoiceDraft = $customer->hasOpenInvoiceDraft();
if ($hasOpenInvoiceDraft && !$customer->invoicePerOrder()) {
// Get the open invoice draft
$openInvoiceDraft = $customer->getOpenInvoiceDraft();
// Add the order to the invoice draft
$result = $this->addOrderToInvoiceDraft($openInvoiceDraft, $order, $customer, $order_items);
}
// If the customer doesn't want to be billed per order, or if there's no open invoice draft, we'll create a new one
// Create the invoice draft
if (!isset($result)) {
$result = $economic_invoice_draft->createInvoiceDraftExample();
}
// Check if the invoice draft was created, or if the lines were added (lines is an array, and should not be empty)
if (!isset($result->draftInvoiceNumber) && !isset($result->lines[0])) {
// Log the error
(new logs_o())->add('economic_invoice_draft', 'global', 3, $user->id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Failed to create economic invoice draft');
// Check if we can get the errors from the response
if (isset($result->errors)) {
$response->add_meta('economic_errors', $result->errors);
}
$response->add_meta('economic_result', $result);
// Try to parse the error message
$response->error($result->message ?? 'Failed to create economic invoice draft', 500);
}
// Add the economic invoice draft to the order
$economic_module_orders = (new economic_module_orders())->getByOrderId($order_id);
// Remove the existing invoice draft (if any)
if ($economic_module_orders->economic_invoice_draft_id->value() > 0) {
$economic_invoice_draft->deleteInvoiceDraft($economic_module_orders->economic_invoice_draft_id->value());
}
$economic_module_orders->economic_invoice_draft_id->set($result->draftInvoiceNumber ?? $customer->getOpenInvoiceDraft());
if (!$customer->invoicePerOrder()) {
// If the customer wants to be billed per order, we'll add the order to the invoice draft
$customer->setOpenInvoiceDraft($result->draftInvoiceNumber ?? $customer->getOpenInvoiceDraft());
} else {
// If the customer doesn't want to be billed per order, we'll remove the open invoice draft
$customer->unsetOpenInvoiceDraft();
}
// Return the response
(new logs_o())->add('economic_invoice_draft', 'global', 1, $user->id, 'ECONOMIC_INVOICE_DRAFT_EXPORT', 'Successfully exported an economic invoice draft');
$response->success($economic_module_orders->getArray());
} else {
(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 () {
global /** @var response $response */
$response;
$this->requirePermission('economic_invoice_draft_delete');
$user = (new authentication())->get_user();
if ($user) {
$order_id = $response->getRequestParameter('order_id');
if (!isset($order_id)) {
$response->error('Order ID is required', 400);
}
$order = (new orders_o())->getOrderById($order_id);
// Check if the order exists
if (!$order->exists()) {
$response->error('Order not found', 404);
}
// Make sure the order has an economic invoice draft
$economic_module_orders = (new economic_module_orders())->getByOrderId($order_id);
if ($economic_module_orders->economic_invoice_draft_id->value() === 0) {
$response->error('No economic invoice draft found', 404);
}
$economic_invoice_draft = (new economic_invoice_draft_mo());
// Get the invoice draft number
$invoiceDraftId = $economic_module_orders->economic_invoice_draft_id->value();
$customer = (new orders_o())->getCustomerByOrderId($order_id);
if (!$customer->invoicePerOrder()) {
// Check if the customer has an open invoice draft
if ($customer->hasOpenInvoiceDraft()) {
// Check if it's the same as the order's invoice draft
if ((int)$customer->getOpenInvoiceDraft() === (int)$invoiceDraftId) {
// Remove the open invoice draft from the customer
$customer->deleteOpenInvoiceDraft();
}
}
}
// Delete the invoice draft
$economic_invoice_draft->deleteInvoiceDraft($invoiceDraftId);
// Remove the economic invoice draft from the order
$economic_module_orders->economic_invoice_draft_id->set(null);
// Return the response
(new logs_o())->add('economic_invoice_draft', 'global', 1, $user->id, 'ECONOMIC_INVOICE_DRAFT_DELETE', 'Successfully deleted an economic invoice draft');
$response->success($economic_module_orders->getArray());
} else {
(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;
$this->requirePermission('economic_invoice_export');
$user = (new authentication())->get_user();
if ($user) {
$order_id = $response->getRequestParameter('order_id');
if (!isset($order_id)) {
$response->error('Order ID is required', 400);
}
$order = (new orders_o())->getOrderById($order_id);
// Check if the order exists
if (!$order->exists()) {
$response->error('Order not found', 404);
}
// Get the customer
$customer = (new orders_o())->getCustomerByOrderId($order_id);
// Check if the customer exists
if (!$customer->exists()) {
$response->error('Customer not found', 404);
}
// Make sure the order has an economic invoice draft
$economic_module_orders = (new economic_module_orders())->getByOrderId($order_id);
if ($economic_module_orders->economic_invoice_draft_id->value() === 0) {
$response->error('No economic invoice draft found', 404);
}
$economic_invoice_draft = (new economic_invoice_draft_mo());
// Get the invoice draft number
$invoiceDraftId = $economic_module_orders->economic_invoice_draft_id->value();
// Make sure there's not already an invoice created
$invoiceId = $economic_module_orders->economic_invoice_id->value();
if ($invoiceId > 0) {
$response->error('An invoice has already been created, invoice ID: ' . $invoiceId, 400);
}
// Publish the invoice draft
$result = $economic_invoice_draft->publishInvoiceDraft((int)$invoiceDraftId);
// Check if the invoice was created
if (!isset($result->bookedInvoiceNumber)) {
// Log the error
(new logs_o())->add('economic_invoice', 'global', 3, $user->id, 'ECONOMIC_INVOICE_EXPORT', 'Failed to create economic invoice from draft: ' . $invoiceDraftId);
// Check if we can get the errors from the response
if (isset($result->errors)) {
$response->add_meta('economic_errors', $result->errors);
}
// Try to parse the error message
$response->error($result->message ?? 'Failed to create economic invoice', 500);
}
// Add the economic invoice to the order
$economic_module_orders = (new economic_module_orders())->getByOrderId($order_id);
$economic_module_orders->economic_invoice_id->set($result->bookedInvoiceNumber);
// Remove the economic invoice draft from the customer
$customer->unsetOpenInvoiceDraft();
// Return the response
(new logs_o())->add('economic_invoice', 'global', 1, $user->id, 'ECONOMIC_INVOICE_EXPORT', 'Successfully exported an economic invoice');
$response->success($economic_module_orders->getArray());
} else {
(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'
]);
}
/**
* @param economic_invoice_draft_mo $economic_invoice_draft
* @param $department_name
* @param orders_o $order
* @return void
*/
function addTheDepartmentDateReference(economic_invoice_draft_mo $economic_invoice_draft, $department_name, orders_o $order): void
{
// The format is:
// Truck Wash - [department name], [date], (?)Ref(erence): [reference], Reg 1: [reg_1], (?)Reg 2: [reg_2], (?)Reg 3: [reg_3]
// (?)[note]
// Example:
// 12-02-2025 13:27, Truck Wash - Administration, Ref: 123456, Reg 1: ABC123, Reg 2: DEF456, Reg 3: GHI789
// This is a note for the invoice
//
// (?) = Optional
$parsed_date = date('d/m/Y H:i', strtotime($order->created_at->value()));
$economic_invoice_draft->addLineTEXT("[ " . $parsed_date . ' ' . $department_name . ' #' . $order->id . " ]");
// If there's a reference, add it to the invoice
if ($order->reference->value() !== '') {
$economic_invoice_draft->addLineTEXT('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 ) {
$economic_invoice_draft->addLineTEXT('# ' . $line);
}
} else {
$economic_invoice_draft->addLineTEXT('# ' . $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
$economic_invoice_draft->addLineTEXT($line_reg);
// If there's a note, add it to the invoice
if ($order->notes->value() !== '') {
$economic_invoice_draft->addLineTEXT('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 ) {
$economic_invoice_draft->addLineTEXT('# ' . $line);
}
} else {
$economic_invoice_draft->addLineTEXT('# ' . $order->notes->value());
}
}
}
/**
* @param users_o $customer
* @param orders_o $order
* @param mixed $order_item
* @param economic_invoice_draft_mo $economic_invoice_draft
* @param int $quantity
* @return void
* @throws \Exception
*/
function addOrderItemToInvoice(users_o $customer, orders_o $order, mixed $order_item, economic_invoice_draft_mo $economic_invoice_draft, int $quantity = 1): void
{
// The format is:
// [product name], (?)Ref(erence): [reference], (!?)Reg 1: [reg 1], (!?)Reg 2: [reg 2], (!?)Reg 3: [reg 3], (?)Note: [note], (?)Discount: ([order item price] - [product price]) DKK ([discount percentage] %)
// (?) = Optional
// (!) = Required if the customer requires it
// (!?) = Should be added if the customer requires it
// Example:
// Tankcleaning 4 spulehoveder, Ref: 123456, Reg 1: ABC123, Reg 2: DEF456, Reg 3: GHI789, Note: This is a note, Discount: -100 DKK (20%)
// Get the department
$department = $order->getDepartmentByOrderId($order->id);
$economic_department_id = $department['economic_department_id'];
$economic_dimension_id = $department['economic_dimension_id'] ?? 0;
// Add the line to the invoice
$economic_invoice_draft->addLine(
(string)$order_item['product']['economic_product_id'],
(string)$order_item['product']['name'],
(int)$quantity,
(int)$order_item['price'],
0, // Since we can't be specific about the discount, we set it to 0. (The API has a limit of 2 decimals, and that's not enough for our needs)
(int)$economic_department_id ?? 0,
(int)$economic_dimension_id ?? 0 // If the department is not set, we'll set it to 0
);
// 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'])
$economic_invoice_draft->addLineTEXT('Rabat: ' . ($order_item['price'] - $order_item['product']['price']) . ' DKK (' . $discountPercentage . '%)');
// If there's a reference, add it to the line
if ($order_item['reference'] !== '') {
$economic_invoice_draft->addLineTEXT('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 ) {
$economic_invoice_draft->addLineTEXT('# ' . $line);
}
} else {
$economic_invoice_draft->addLineTEXT('# ' . $order_item['reference']);
}
}
// Add the registration numbers (if they exist, and the customer requires it)
if ($customer->doesUserHaveAttribute('requiresRegistrationNumbersInvoice')) {
$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());
}
$economic_invoice_draft->addLineTEXT($line_reg);
}
// If there's a note, add it to the line
if ($order_item['notes'] !== '') {
$economic_invoice_draft->addLineTEXT('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 ) {
$economic_invoice_draft->addLineTEXT('# ' . $line);
}
} else {
$economic_invoice_draft->addLineTEXT('# ' . $order_item['notes']);
}
}
}
function addOrderToInvoiceDraft(int $economic_invoice_draft_id, orders_o $order, users_o $customer, array $order_items): object
{
$economic_invoice_draft = (new economic_invoice_draft_mo());
// Add two empty lines to the invoice, to separate the orders
$economic_invoice_draft->addLineTEXT('');
$economic_invoice_draft->addLineTEXT('');
// Add the department, date, reference
$this->addTheDepartmentDateReference($economic_invoice_draft, $order->getDepartmentByOrderId($order->id)['name'], $order);
// Add the lines to the invoice
foreach ( $order_items as $order_item ) {
// Add the order item to the invoice draft
$this->addOrderItemToInvoice($customer, $order, $order_item, $economic_invoice_draft, $order_item['quantity'] ?? 1);
}
return $economic_invoice_draft->addLinesToInvoiceDraft($economic_invoice_draft_id);
}
}