diff --git a/services/nginx/app/classes/db.php b/services/nginx/app/classes/db.php index 8e550847..2c845f14 100644 --- a/services/nginx/app/classes/db.php +++ b/services/nginx/app/classes/db.php @@ -134,5 +134,12 @@ class db return $return === 0; } + public function getView(string $view): array + { + $sql = "SELECT * FROM $view"; + $result = $this->query($sql); + return $this->fetch_all($result); + } + } \ No newline at end of file diff --git a/services/nginx/app/objects/collected_order_invoices_o.php b/services/nginx/app/objects/collected_order_invoices_o.php index 52c8fdef..7a0832c3 100644 --- a/services/nginx/app/objects/collected_order_invoices_o.php +++ b/services/nginx/app/objects/collected_order_invoices_o.php @@ -374,7 +374,7 @@ class collected_order_invoices_o extends db // Require the invoice collection to be selected self::requireSelected(); // Require the invoice collection to not be closed - if (!empty($this->closed_at->value())) { + if (!empty($this->closed_at->value()) && !empty($this->processor->value())) { throw new Exception('Invoice collection is closed'); } } diff --git a/services/nginx/app/routes/orderInvoicesRoute.php b/services/nginx/app/routes/orderInvoicesRoute.php index b6c90213..c71c5665 100644 --- a/services/nginx/app/routes/orderInvoicesRoute.php +++ b/services/nginx/app/routes/orderInvoicesRoute.php @@ -277,6 +277,203 @@ class orderInvoicesRoute 'list_collected_invoices_customers' => 'List ALL collected order invoices customers. This is a superuser-only route.' ] ); + + $this->get('/collected-invoices/customers/invoicePerOrder', 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_CUSTOMERS_INVOICE_PER_ORDER', 'User accessed the list of collected order invoices customers with invoice per order'); + // Define the users + $users_o = new users_o(); + $users_o->setView('customers_invoice_count_per_order'); + $result = $users_o + ->setSearchableFields([ + 'customer_number', + 'display_name', + 'active_invoices', + 'closed_invoices', + ]) + ->listObjectsWithPaginationIfSet( + function ($collected_order_invoice) use ($users_o) { + return [ + 'customer_number' => (int)$collected_order_invoice['customer_number'], + 'display_name' => (string)$users_o->getCustomerName((int)$collected_order_invoice['customer_number']), + 'active_invoices' => (int)$collected_order_invoice['active_invoices'], + 'closed_invoices' => (int)$collected_order_invoice['closed_invoices'], + ]; + }, + ); + // Return the list of customers + $response->success($result); + } else { + (new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_CUSTOMERS_INVOICE_PER_ORDER', 'User tried to access the list of collected order invoices customers with invoice per order without a valid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'list_collected_invoices_customers_invoice_per_order' => 'List ALL collected order invoices customers with invoice per order. This is a superuser-only route.' + ] + ); + + $this->get('/collected-invoices/customers/invoicePerMonth', 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_CUSTOMERS_INVOICE_PER_MONTH', 'User accessed the list of collected order invoices customers with invoice per month'); + // Define the users + $users_o = new users_o(); + $users_o->setView('customers_invoice_count_per_month'); + $result = $users_o + ->setSearchableFields([ + 'customer_number', + 'customer_name', + 'active_invoices', + 'closed_invoices', + ]) + ->listObjectsWithPaginationIfSet( + function ($collected_order_invoice) use ($users_o) { + return [ + 'customer_number' => (int)$collected_order_invoice['customer_number'], + 'display_name' => (string)$users_o->getCustomerName((int)$collected_order_invoice['customer_number']), + 'active_invoices' => (int)$collected_order_invoice['active_invoices'], + 'closed_invoices' => (int)$collected_order_invoice['closed_invoices'], + ]; + }, + ); + // Return the list of customers + $response->success($result); + } else { + (new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_CUSTOMERS_INVOICE_PER_MONTH', 'User tried to access the list of collected order invoices customers with invoice per month without a valid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'list_collected_invoices_customers_invoice_per_month' => 'List ALL collected order invoices customers with invoice per month. This is a superuser-only route.' + ] + ); + + $this->post('/collected-invoices/customers/invoiceTotals', function () { + // This is a superuser-only route + 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_CUSTOMERS_INVOICE_TOTALS', 'User accessed the list of collected order invoices customers with invoice totals'); + // Require the customer_numbers parameter + self::requireParameters(['customer_numbers']); + // Print the customer_numbers parameter + $customer_numbers = self::getParameter('customer_numbers'); + // validate the customer_numbers parameter + if (!is_array($customer_numbers)) { + $response->error('customer_numbers must be an array', 400); + } + // Validate the customer_numbers parameter + foreach ( $customer_numbers as $customer_number ) { + self::requireType((int)$customer_number, self::type_int()); + if (!is_numeric($customer_number)) { + $response->error('customer_numbers must be an array of integers', 400); + } + if (!$customer_number || $customer_number < 1) { + $response->error('customer_numbers must be an array of integers greater than 0', 400); + } + } + // Now we can safely use the customer_numbers parameter + // Define the result array + $result = []; + // Loop through the customer_numbers array, and get the invoice totals for each customer + foreach ( $customer_numbers as $customer_number ) { + // Define the invoices array + $tmp_invoices = [ + 'closed_invoices' => [], + 'open_invoices' => [], + ]; + // Define the total net amount + $tmp_total_net_amount = [ + 'closed_invoices' => 0, + 'open_invoices' => 0, + ]; + // Define the collected order invoices + $collected_order_invoices = new collected_order_invoices_o(); + // Get the collected order invoices for the customer + $collected_order_invoices->setView('invoices_with_completed_orders'); + $tmp_invoice_collections = $collected_order_invoices->listObjectsWithPaginationIfSet( + function ($collected_order_invoice) use ($tmp_invoices, $customer_number, $collected_order_invoices) { + // Select the orders for each collected order invoice + $collected_order_invoices->select((int)$collected_order_invoice['id']); + // Get the details for the collected order invoice + return $this->getOrderInvoiceDetails($collected_order_invoice, new users_o(), $collected_order_invoices); + }, + $collected_order_invoices->forceRestrictFilters([ + 'customer_number' => $customer_number, + ]) + ); + // Loop through the collected order invoices, and get the total net amount + foreach ( $tmp_invoice_collections as $tmp_invoice_collection ) { + // Update the total net amount + if ($tmp_invoice_collection['closed_at'] !== null) { + $tmp_total_net_amount['closed_invoices'] += $tmp_invoice_collection['total_net_amount']; + // Add the closed invoice to the closed invoices array + $tmp_invoices['closed_invoices'][] = $tmp_invoice_collection; + } else { + $tmp_total_net_amount['open_invoices'] += $tmp_invoice_collection['total_net_amount']; + // Add the open invoice to the open invoices array + $tmp_invoices['open_invoices'][] = $tmp_invoice_collection; + } + } + $tmp_user = (new users_o())->getUserByCustomerNumber($customer_number); + // Add the customer to the result array + $result[$customer_number] = [ + 'customer_number' => (int)$customer_number, + 'customer_name' => (string)$tmp_user->display_name->value(), + 'user_id' => (int)$tmp_user->id, + 'invoices' => $tmp_invoices, + 'total_net_amount' => $tmp_total_net_amount, + ]; + } + + // Return the list of customers + $response->success($result); + } else { + (new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_CUSTOMERS_INVOICE_TOTALS', 'User tried to access the list of collected order invoices customers with invoice totals without a valid session'); + $response->error('Invalid session', 400); + } + }); + + $this->get('/collected-invoices/transactions', 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_TRANSACTIONS', 'User accessed the list of collected order invoices transactions'); + // Get the collected order invoices + $collected_order_invoices = new collected_order_invoices_o(); + // Define the transactions + $transactions = $orders_o->listObjectsWithPaginationIfSet( + function ($order) use ($orders_o) { + // Select the orders for each collected order invoice + $orders_o->select((int)$order['id']); + return [ + 'id' => (int)$order['id'], + 'customer_number' => (int)$order['customer_number'], + 'external_id' => (string)$order['external_id'], + 'created_at' => (string)$order['created_at'], + 'updated_at' => (string)$order['updated_at'], + ]; + }, + ); + // Return the list of transactions + $response->success($transactions); + } else { + (new logs_o())->add('orderInvoices', 'global', 0, 0, 'LIST_COLLECTED_INVOICES_TRANSACTIONS', 'User tried to access the list of collected order invoices transactions without a valid session'); + $response->error('Invalid session', 400); + } + }, + [ + 'list_collected_invoices_transactions' => 'List ALL collected order invoices transactions. This is a superuser-only route.' + ] + ); } /** diff --git a/services/nginx/app/traits/db_object_t.php b/services/nginx/app/traits/db_object_t.php index 72074361..b772d215 100644 --- a/services/nginx/app/traits/db_object_t.php +++ b/services/nginx/app/traits/db_object_t.php @@ -5,16 +5,29 @@ namespace traits; use classes\db; use classes\response; use Exception; +use objects\bookings_new_o; use objects\bookings_o; +use objects\branding_o; use objects\categories_o; +use objects\collected_order_invoices_o; use objects\cron_o; +use objects\currency_conversion_rates_o; use objects\customer_codes_o; use objects\customer_notes_o; use objects\customer_vehicles_o; use objects\department_categories_o; +use objects\department_daily_reports_o; +use objects\department_variables_o; use objects\departments_o; use objects\economic_module_orders; +use objects\form_submissions_o; +use objects\fxratesapi_conversion_rates_o; +use objects\groups_o; +use objects\groups_permissions_o; use objects\logs_o; +use objects\module_action_logs_o; +use objects\motorapi_lookups_o; +use objects\notifications_o; use objects\order_items_o; use objects\orders_o; use objects\plate_scanners_o; @@ -22,6 +35,8 @@ use objects\plate_scans_o; use objects\product_options_o; use objects\products_o; use objects\ratelimit_o; +use objects\stripe_module_customers_o; +use objects\stripe_module_orders_o; use objects\tokens_o; use objects\user_key_value_pairs_o; use objects\user_price_overrides_o; @@ -203,7 +218,7 @@ trait db_object_t } // Check if the value is "null", if it is, set it to null foreach ( $temp as $key => $value ) { - if (strtolower($value) === 'null') { + if (!is_array($value) && strtolower($value) === 'null') { $temp[$key] = null; continue; } @@ -784,6 +799,17 @@ trait db_object_t return $this; } + /** + * Set the view, used on the pagination + * @param string $view The view to set + * @return users_o|bookings_new_o|bookings_o|branding_o|categories_o|collected_order_invoices_o|cron_o|currency_conversion_rates_o|customer_codes_o|customer_notes_o|customer_vehicles_o|department_categories_o|department_daily_reports_o|department_variables_o|departments_o|economic_module_orders|form_submissions_o|fxratesapi_conversion_rates_o|groups_o|groups_permissions_o|logs_o|module_action_logs_o|motorapi_lookups_o|notifications_o|order_items_o|orders_o|plate_scanners_o|plate_scans_o|product_options_o|products_o|ratelimit_o|stripe_module_customers_o|stripe_module_orders_o|tokens_o|user_key_value_pairs_o|user_price_overrides_o|db_object_t + */ + public function setView(string $view): self + { + $this->table = $view; + return $this; + } + /** * Add an object to the database, using the data provided * @param array $data The data to add the object with (E.g. ['name' => 'John', 'email' => 'email@example.com'])