Add invoice collection assignment logic to orders and users

Introduced methods to manage, assign, and retrieve invoice collections for orders and users. Enhanced the system to support flexible invoice grouping, including per-order logic and automated assignment to open or newly created invoice collections.
This commit is contained in:
Jepp9350
2025-02-28 13:50:27 +01:00
parent 9bf0355e47
commit e9aeedc327
4 changed files with 201 additions and 16 deletions
@@ -40,20 +40,29 @@ class collected_order_invoices_o extends db
$db;
// Sanitize the input
$customer_number = $db->escape_string($customer_number);
$name = $db->escape_string($name);
$notes = $db->escape_string($notes);
$processor = $db->escape_string($processor);
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,
'processor' => $processor
'notes' => $notes
]);
self::select((int)$tmp_id);
self::requireSelected();
// Set the processor
if (!empty($processor)) {
$this->processor->set($processor);
}
self::objectChanged();
return $this;
}
@@ -124,7 +133,104 @@ class collected_order_invoices_o extends db
'created_at' => (string)$this->created_at->value(),
'updated_at' => (string)$this->updated_at->value(),
'closed_at' => (string)$this->closed_at->value(),
'orders' => $this->getOrders()
];
}
/**
* 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;
}
/**
* 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;
}
}
+27 -1
View File
@@ -25,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
{
@@ -64,8 +65,9 @@ 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
{
@@ -150,6 +152,7 @@ class orders_o extends db
'reg_3' => $this->reg_3->value(),
'created_at' => $this->created_at->value(),
'deleted_at' => $this->deleted_at->value(),
'invoice_collection_id' => (int)$this->invoice_collection_id->value(),
];
}
@@ -318,12 +321,35 @@ class orders_o extends db
// Set the values of the object properties
$this->getObjectProperties();
self::requireSelected();
self::assignToInvoiceCollection();
return $this;
} 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
+61 -9
View File
@@ -399,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
@@ -872,4 +863,65 @@ 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());
}
}
@@ -47,7 +47,8 @@ class orderInvoicesRoute
'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']
'created_at' => (string)$collected_order_invoice['created_at'],
'orders' => ((new collected_order_invoices_o())->select((int)$collected_order_invoice['id']))->getOrders(true)
];
}
));