diff --git a/services/nginx/app/objects/collected_order_invoices_o.php b/services/nginx/app/objects/collected_order_invoices_o.php index ef119738..e1564c07 100644 --- a/services/nginx/app/objects/collected_order_invoices_o.php +++ b/services/nginx/app/objects/collected_order_invoices_o.php @@ -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; + } + } \ No newline at end of file diff --git a/services/nginx/app/objects/orders_o.php b/services/nginx/app/objects/orders_o.php index 37a67735..e8d1e5e7 100644 --- a/services/nginx/app/objects/orders_o.php +++ b/services/nginx/app/objects/orders_o.php @@ -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 diff --git a/services/nginx/app/objects/users_o.php b/services/nginx/app/objects/users_o.php index 21b5daf3..fc466916 100644 --- a/services/nginx/app/objects/users_o.php +++ b/services/nginx/app/objects/users_o.php @@ -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()); + } } \ No newline at end of file diff --git a/services/nginx/app/routes/orderInvoicesRoute.php b/services/nginx/app/routes/orderInvoicesRoute.php index 67de9112..04ebe788 100644 --- a/services/nginx/app/routes/orderInvoicesRoute.php +++ b/services/nginx/app/routes/orderInvoicesRoute.php @@ -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) ]; } ));