', $strings[1], $this->_api_endpoint); //TODO: Hungarian notation
+ }
+ }
+ }
- /**
- * Call an API method. Every request needs the API key
- * @param string $httpVerb The HTTP method to be used
- * @param string $method The API method to call, e.g. 'lists/list'
- * @param array $args An array of arguments to pass to the method. Will be json-encoded for you.
- * @return array|bool Associative array of json decoded API response or false on error.
- */
- public function call(string $method, string $httpVerb = 'POST', array $args = []): bool|array
- {
- if(!empty($this->_api_key)) //TODO: Hungarian notation
- {
- return $this->_request($httpVerb, $method, $args); //TODO: Hungarian notation
- }
+ /**
+ * Call an API method. Every request needs the API key
+ * @param string $httpVerb The HTTP method to be used
+ * @param string $method The API method to call, e.g. 'lists/list'
+ * @param array $args An array of arguments to pass to the method. Will be json-encoded for you.
+ * @return array|bool Associative array of json decoded API response or false on error.
+ */
+ public function call(string $method, string $httpVerb = 'POST', array $args = []): bool|array
+ {
+ if(!empty($this->_api_key)) //TODO: Hungarian notation
+ {
+ return $this->_request($httpVerb, $method, $args); //TODO: Hungarian notation
+ }
- return false;
- }
+ return false;
+ }
- /**
- * Builds the request URL based on request type
- * @param string $httpVerb The HTTP method to be used
- * @param string $method The API method to be called
- * @param array $args Assoc array of parameters to be passed
- * @return string Request URL
- */
- private function _build_request_url(string $method, string $httpVerb = 'POST', array $args = []): string //TODO: Hungarian notation.
- {
- if($httpVerb == 'GET')
- {
- return $this->_api_endpoint . $method . '?' . http_build_query($args); //TODO: Hungarian notation
- }
+ /**
+ * Builds the request URL based on request type
+ * @param string $httpVerb The HTTP method to be used
+ * @param string $method The API method to be called
+ * @param array $args Assoc array of parameters to be passed
+ * @return string Request URL
+ */
+ private function _build_request_url(string $method, string $httpVerb = 'POST', array $args = []): string //TODO: Hungarian notation.
+ {
+ if($httpVerb == 'GET')
+ {
+ return $this->_api_endpoint . $method . '?' . http_build_query($args); //TODO: Hungarian notation
+ }
- return $this->_api_endpoint . $method; //TODO: Hungarian notation
- }
+ return $this->_api_endpoint . $method; //TODO: Hungarian notation
+ }
- /**
- * Performs the underlying HTTP request.
- * @param string $httpVerb The HTTP method to be used
- * @param string $method The API method to be called
- * @param array $args Assoc array of parameters to be passed
- * @return bool|array Assoc array of decoded result or False
- */
- private function _request(string $httpVerb, string $method, array $args = []): bool|array //TODO: Hungarian notation
- {
- $result = false;
+ /**
+ * Performs the underlying HTTP request.
+ * @param string $httpVerb The HTTP method to be used
+ * @param string $method The API method to be called
+ * @param array $args Assoc array of parameters to be passed
+ * @return bool|array Assoc array of decoded result or False
+ */
+ private function _request(string $httpVerb, string $method, array $args = []): bool|array //TODO: Hungarian notation
+ {
+ $result = false;
- if(($ch = curl_init()) !== false)
- {
- curl_setopt($ch, CURLOPT_URL, $this->_build_request_url($method, $httpVerb, $args));
- curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
- curl_setopt($ch, CURLOPT_USERPWD, "user:" . $this->_api_key);
- curl_setopt($ch, CURLOPT_USERAGENT, 'PHP-MCAPI/3.0');
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
- curl_setopt($ch, CURLOPT_TIMEOUT, 10);
- curl_setopt($ch, CURLOPT_POST, true);
- curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
- curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($args));
- curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpVerb);
+ if(($ch = curl_init()) !== false)
+ {
+ curl_setopt($ch, CURLOPT_URL, $this->_build_request_url($method, $httpVerb, $args));
+ curl_setopt($ch, CURLOPT_HTTPHEADER, ['Content-Type: application/json']);
+ curl_setopt($ch, CURLOPT_USERPWD, "user:" . $this->_api_key);
+ curl_setopt($ch, CURLOPT_USERAGENT, 'PHP-MCAPI/3.0');
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
+ curl_setopt($ch, CURLOPT_POST, true);
+ curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, true);
+ curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($args));
+ curl_setopt($ch, CURLOPT_CUSTOMREQUEST, $httpVerb);
- $result = curl_exec($ch);
+ $result = curl_exec($ch);
- curl_close($ch);
- }
+ curl_close($ch);
+ }
- return $result ? json_decode($result, true) : false;
- }
+ return $result ? json_decode($result, true) : false;
+ }
}
@@ -140,206 +140,206 @@ class MailchimpConnector
* Inspired by the work of ThinkShout: https://github.com/thinkshout/mailchimp-api-php
*/
-class Mailchimp_lib //TODO: IMO We need to stick to the one class per file principle.
+class Mailchimp_lib //TODO: IMO We need to stick to the one class per file principle.
{
- private $_connector; //TODO: Hungarian notation
+ private $_connector; //TODO: Hungarian notation
- /**
- * @param array $params
- */
- public function __construct(array $params = [])
- {
- $api_key = (count($params) > 0 && !empty($params['api_key'])) ? $params['api_key'] : '';
- $this->_connector = new MailchimpConnector($api_key);
- }
+ /**
+ * @param array $params
+ */
+ public function __construct(array $params = [])
+ {
+ $api_key = (count($params) > 0 && !empty($params['api_key'])) ? $params['api_key'] : '';
+ $this->_connector = new MailchimpConnector($api_key);
+ }
- /**
- * Gets information about all lists owned by the authenticated account.
- *
- * @param array $parameters
- * Associative array of optional request parameters.
- * By the default it places a simple query to list name & id and count of members & merge_fields
- * NOTE: no space between , and next word is allowed. You will not get the filter to work in full but just the first tag
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists
- */
- public function getLists(array $parameters = ['fields' => 'lists.id,lists.name,lists.stats.member_count,lists.stats.merge_field_count']): bool|array
- {
- return $this->_connector->call('/lists', 'GET', $parameters); //TODO: Hungarian notation
- }
+ /**
+ * Gets information about all lists owned by the authenticated account.
+ *
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * By the default it places a simple query to list name & id and count of members & merge_fields
+ * NOTE: no space between , and next word is allowed. You will not get the filter to work in full but just the first tag
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists
+ */
+ public function getLists(array $parameters = ['fields' => 'lists.id,lists.name,lists.stats.member_count,lists.stats.merge_field_count']): bool|array
+ {
+ return $this->_connector->call('/lists', 'GET', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Gets a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param array $parameters Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists_list_id
- */
- public function getList(string $list_id, array $parameters = ['fields' => 'id,name,stats.member_count,stats.merge_field_count']): bool|array
- {
- return $this->_connector->call("/lists/$list_id", 'GET', $parameters); //TODO: Hungarian notation
- }
+ /**
+ * Gets a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param array $parameters Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/#read-get_lists_list_id
+ */
+ public function getList(string $list_id, array $parameters = ['fields' => 'id,name,stats.member_count,stats.merge_field_count']): bool|array
+ {
+ return $this->_connector->call("/lists/$list_id", 'GET', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Gets information about all members of a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members
- */
- public function getMembers(string $list_id, int $count, int $offset, array $parameters = ['fields' => 'members.id,members.email_address,members.unique_email_id,members.status,members.merge_fields']): bool|array
- {
- $parameters += [
- 'count' => $count,
- 'offset' => $offset
- ];
+ /**
+ * Gets information about all members of a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members
+ */
+ public function getMembers(string $list_id, int $count, int $offset, array $parameters = ['fields' => 'members.id,members.email_address,members.unique_email_id,members.status,members.merge_fields']): bool|array
+ {
+ $parameters += [
+ 'count' => $count,
+ 'offset' => $offset
+ ];
- return $this->_connector->call("/lists/$list_id/members", 'GET', $parameters); //TODO: Hungarian notation
- }
+ return $this->_connector->call("/lists/$list_id/members", 'GET', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Gets information about a member of a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $md5id
- * The member's email address md5 hash which is the id.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members_subscriber_hash
- */
- public function getMemberInfoById(string $list_id, string $md5id, array $parameters = ['fields' => 'email_address,status,merge_fields']): bool|array
- {
- return $this->_connector->call("/lists/$list_id/members/$md5id", 'GET', $parameters); //TODO: Hungarian notation
- }
+ /**
+ * Gets information about a member of a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $md5id
+ * The member's email address md5 hash which is the id.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members_subscriber_hash
+ */
+ public function getMemberInfoById(string $list_id, string $md5id, array $parameters = ['fields' => 'email_address,status,merge_fields']): bool|array
+ {
+ return $this->_connector->call("/lists/$list_id/members/$md5id", 'GET', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Gets information about a member of a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $email
- * The member's email address.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members_subscriber_hash
- */
- public function getMemberInfo(string $list_id, string $email, array $parameters = []): bool|array
- {
- return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'GET', $parameters);
- }
+ /**
+ * Gets information about a member of a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $email
+ * The member's email address.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#read-get_lists_list_id_members_subscriber_hash
+ */
+ public function getMemberInfo(string $list_id, string $email, array $parameters = []): bool|array
+ {
+ return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'GET', $parameters);
+ }
- /**
- * Gets activity related to a member of a MailChimp list.
- *
- * @param string $list_id The ID of the list.
- * @param string $email The member's email address.
- * @param array $parameters Associative array of optional request parameters.
- * @return array|bool Associative array of results or false.
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/activity/#read-get_lists_list_id_members_subscriber_hash_activity
- */
- public function getMemberActivity(string $list_id, string $email, array $parameters = []): bool|array
- {
- return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)) . '/activity', 'GET', $parameters); //TODO: Hungarian notation
- }
+ /**
+ * Gets activity related to a member of a MailChimp list.
+ *
+ * @param string $list_id The ID of the list.
+ * @param string $email The member's email address.
+ * @param array $parameters Associative array of optional request parameters.
+ * @return array|bool Associative array of results or false.
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/activity/#read-get_lists_list_id_members_subscriber_hash_activity
+ */
+ public function getMemberActivity(string $list_id, string $email, array $parameters = []): bool|array
+ {
+ return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)) . '/activity', 'GET', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Adds a new member to a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $email
- * The email address to add.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
- */
- public function addMember(string $list_id, string $email, string $first_name, string $last_name, array $parameters = []): bool|array
- {
- $parameters += [
- 'email_address' => $email,
- 'status' => 'subscribed',
- 'merge_fields' => [
- 'FNAME' => $first_name,
- 'LNAME' => $last_name
- ]
- ];
+ /**
+ * Adds a new member to a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $email
+ * The email address to add.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#create-post_lists_list_id_members
+ */
+ public function addMember(string $list_id, string $email, string $first_name, string $last_name, array $parameters = []): bool|array
+ {
+ $parameters += [
+ 'email_address' => $email,
+ 'status' => 'subscribed',
+ 'merge_fields' => [
+ 'FNAME' => $first_name,
+ 'LNAME' => $last_name
+ ]
+ ];
- return $this->_connector->call("/lists/$list_id/members/", 'POST', $parameters); //TODO: Hungarian notation
- }
+ return $this->_connector->call("/lists/$list_id/members/", 'POST', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Removes a member from a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $email
- * The member's email address.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#delete-delete_lists_list_id_members_subscriber_hash
- */
- public function removeMember(string $list_id, string $email): bool|array
- {
- return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'DELETE'); //TODO: Hungarian notation
- }
+ /**
+ * Removes a member from a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $email
+ * The member's email address.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#delete-delete_lists_list_id_members_subscriber_hash
+ */
+ public function removeMember(string $list_id, string $email): bool|array
+ {
+ return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'DELETE'); //TODO: Hungarian notation
+ }
- /**
- * Updates a member of a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $email
- * The member's email address.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-patch_lists_list_id_members_subscriber_hash
- */
- public function updateMember(string $list_id, string $email, string $first_name, string $last_name, array $parameters = []): bool|array
- {
- $parameters += [
- 'status' => 'subscribed',
- 'merge_fields' => [
- 'FNAME' => $first_name,
- 'LNAME' => $last_name
- ]
- ];
+ /**
+ * Updates a member of a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $email
+ * The member's email address.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-patch_lists_list_id_members_subscriber_hash
+ */
+ public function updateMember(string $list_id, string $email, string $first_name, string $last_name, array $parameters = []): bool|array
+ {
+ $parameters += [
+ 'status' => 'subscribed',
+ 'merge_fields' => [
+ 'FNAME' => $first_name,
+ 'LNAME' => $last_name
+ ]
+ ];
- return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'PATCH', $parameters); //TODO: Hungarian notation
- }
+ return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'PATCH', $parameters); //TODO: Hungarian notation
+ }
- /**
- * Adds a new or update an existing member of a MailChimp list.
- *
- * @param string $list_id
- * The ID of the list.
- * @param string $email
- * The member's email address.
- * @param array $parameters
- * Associative array of optional request parameters.
- * @return array|bool
- * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-put_lists_list_id_members_subscriber_hash
- */
- public function addOrUpdateMember(string $list_id, string $email, string $first_name, string $last_name, string $status, array $parameters = []): bool|array
- {
- $parameters += [
- 'email_address' => $email,
- 'status' => $status,
- 'status_if_new' => 'subscribed',
- 'merge_fields' => [
- 'FNAME' => $first_name,
- 'LNAME' => $last_name
- ]
- ];
+ /**
+ * Adds a new or update an existing member of a MailChimp list.
+ *
+ * @param string $list_id
+ * The ID of the list.
+ * @param string $email
+ * The member's email address.
+ * @param array $parameters
+ * Associative array of optional request parameters.
+ * @return array|bool
+ * @see http://developer.mailchimp.com/documentation/mailchimp/reference/lists/members/#edit-put_lists_list_id_members_subscriber_hash
+ */
+ public function addOrUpdateMember(string $list_id, string $email, string $first_name, string $last_name, string $status, array $parameters = []): bool|array
+ {
+ $parameters += [
+ 'email_address' => $email,
+ 'status' => $status,
+ 'status_if_new' => 'subscribed',
+ 'merge_fields' => [
+ 'FNAME' => $first_name,
+ 'LNAME' => $last_name
+ ]
+ ];
- return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'PUT', $parameters); //TODO: Hungarian notation
- }
+ return $this->_connector->call("/lists/$list_id/members/" . md5(strtolower($email)), 'PUT', $parameters); //TODO: Hungarian notation
+ }
}
diff --git a/app/Libraries/Receiving_lib.php b/app/Libraries/Receiving_lib.php
index 5a9b4b903..4d2e4f4fd 100644
--- a/app/Libraries/Receiving_lib.php
+++ b/app/Libraries/Receiving_lib.php
@@ -19,539 +19,539 @@ use Config\OSPOS;
*/
class Receiving_lib
{
- private Attribute $attribute;
- private Item $item;
- private Item_kit_items $item_kit_items;
- private Item_quantity $item_quantity;
- private Receiving $receiving;
- private Stock_location $stock_location;
- private Session $session;
-
- public function __construct()
- {
- $this->attribute = model(Attribute::class);
- $this->item = model(Item::class);
- $this->item_kit_items = model(Item_kit_items::class);
- $this->item_quantity = model(Item_quantity::class);
- $this->receiving = model(Receiving::class);
- $this->stock_location = model(Stock_location::class);
-
- $this->session = session();
- }
-
- /**
- * @return array
- */
- public function get_cart(): array
- {
- if(!$this->session->get('recv_cart'))
- {
- $this->set_cart ([]);
- }
-
- return $this->session->get('recv_cart');
- }
-
- /**
- * @param array $cart_data
- * @return void
- */
- public function set_cart(array $cart_data): void
- {
- $this->session->set('recv_cart', $cart_data);
- }
-
- /**
- * @return void
- */
- public function empty_cart(): void
- {
- $this->session->remove('recv_cart');
- }
-
- /**
- * @return int
- */
- public function get_supplier(): int
- {
- if(!$this->session->get('recv_supplier'))
- {
- $this->set_supplier(-1); //TODO: Replace -1 with a constant.
- }
-
- return $this->session->get('recv_supplier');
- }
-
- /**
- * @param int $supplier_id
- * @return void
- */
- public function set_supplier(int $supplier_id): void
- {
- $this->session->set('recv_supplier', $supplier_id);
- }
-
- /**
- * @return void
- */
- public function remove_supplier(): void
- {
- $this->session->remove('recv_supplier');
- }
-
- /**
- * @return string
- */
- public function get_mode(): string
- {
- if(!$this->session->get('recv_mode'))
- {
- $this->set_mode('receive');
- }
-
- return $this->session->get('recv_mode');
- }
-
- /**
- * @param string $mode
- * @return void
- */
- public function set_mode(string $mode): void
- {
- $this->session->set('recv_mode', $mode);
- }
-
- /**
- * @return void
- */
- public function clear_mode(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_mode()
- {
- $this->session->remove('recv_mode');
- }
-
- /**
- * @return int
- */
- public function get_stock_source(): int
- {
- if(!$this->session->get('recv_stock_source'))
- {
- $this->set_stock_source($this->stock_location->get_default_location_id('receivings'));
- }
-
- return $this->session->get('recv_stock_source');
- }
-
- /**
- * @return string
- */
- public function get_comment(): string
- {
- $comment = $this->session->get('recv_comment');
-
- return empty($comment) ? '' : $comment;
- }
-
- /**
- * @param string $comment
- * @return void
- */
- public function set_comment(string $comment): void
- {
- $this->session->set('recv_comment', $comment);
- }
-
- /**
- * @return void
- */
- public function clear_comment(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_comment()
- {
- $this->session->remove('recv_comment');
- }
-
- /**
- * @return string
- */
- public function get_reference(): string
- {
- return $this->session->get('recv_reference') ?? '';
- }
-
- /**
- * @param string $reference
- * @return void
- */
- public function set_reference(string $reference): void
- {
- $this->session->set('recv_reference', $reference);
- }
-
- /**
- * @return void
- */
- public function clear_reference(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_reference()
- {
- $this->session->remove('recv_reference');
- }
-
- /**
- * @return bool
- */
- public function is_print_after_sale(): bool
- {
- return $this->session->get('recv_print_after_sale') == 'true'
- || $this->session->get('recv_print_after_sale') == '1';
- }
-
- /**
- * @param bool $print_after_sale
- * @return void
- */
- public function set_print_after_sale(bool $print_after_sale): void
- {
- $this->session->set('recv_print_after_sale', $print_after_sale);
- }
-
- /**
- * @param int $stock_source
- * @return void
- */
- public function set_stock_source(int $stock_source): void
- {
- $this->session->set('recv_stock_source', $stock_source);
- }
-
- /**
- * @return void
- */
- public function clear_stock_source(): void
- {
- $this->session->remove('recv_stock_source');
- }
-
- /**
- * @return string
- */
- public function get_stock_destination(): string
- {
- if(!$this->session->get('recv_stock_destination'))
- {
- $this->set_stock_destination($this->stock_location->get_default_location_id('receivings'));
- }
-
- return $this->session->get('recv_stock_destination');
- }
-
- /**
- * @param string $stock_destination
- * @return void
- */
- public function set_stock_destination(?string $stock_destination): void
- {
- $this->session->set('recv_stock_destination', $stock_destination);
- }
-
- /**
- * @return void
- */
- public function clear_stock_destination(): void
- {
- $this->session->remove('recv_stock_destination');
- }
- //TODO: This array signature needs to be reworked. It's way too long. Perhaps an object needs to be passed rather than these?
-
- /**
- * @param int $item_id
- * @param int $quantity
- * @param int|null $item_location
- * @param float $discount
- * @param int $discount_type
- * @param float|null $price
- * @param string|null $description
- * @param string|null $serialnumber
- * @param float|null $receiving_quantity
- * @param int|null $receiving_id
- * @param bool $include_deleted
- * @return bool
- */
- public function add_item(int $item_id, int $quantity = 1, int $item_location = null, float $discount = 0, int $discount_type = 0, float $price = null, string $description = null, string $serialnumber = null, float $receiving_quantity = null, int $receiving_id = null, bool $include_deleted = false): bool
- {
- $config = config(OSPOS::class)->settings;
-
- //make sure item exists in database.
- if(!$this->item->exists($item_id, $include_deleted))
- {
- //try to get item id given an item_number
- $item_id = $this->item->get_item_id($item_id, $include_deleted);
-
- if(!$item_id)
- {
- return false;
- }
- }
-
- //Get items in the receiving so far.
- $items = $this->get_cart();
-
- //We need to loop through all items in the cart.
- //If the item is already there, get it's key($updatekey).
- //We also need to get the next key that we are going to use in case we need to add the
- //item to the list. Since items can be deleted, we can't use a count. we use the highest key + 1.
-
- $maxkey = 0; //Highest key so far
- $itemalreadyinsale = false; //We did not find the item yet.
- $updatekey = 0; //Key to use to update(quantity)
-
- foreach($items as $item)
- {
- //We primed the loop so maxkey is 0 the first time.
- //Also, we have stored the key in the element itself, so we can compare.
- //There is an array public function to get the associated key for an element, but I like it better
- //like that!
-
- if($maxkey <= $item['line'])
- {
- $maxkey = $item['line'];
- }
-
- if($item['item_id'] == $item_id && $item['item_location'] == $item_location)
- {
- $itemalreadyinsale = true;
- $updatekey = $item['line'];
- }
- }
-
- $insertkey = $maxkey + 1;
- $item_info = $this->item->get_info($item_id);
-
- //array records are identified by $insertkey and item_id is just another field.
- $price = $price != null ? $price : $item_info->cost_price;
-
- if($config['multi_pack_enabled'])
- {
- $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
- }
-
- if ($item_info->receiving_quantity == 0 || $item_info->receiving_quantity == 1)
- {
- $receiving_quantity_choices = [1 => 'x1'];
- }
- else
- {
- $receiving_quantity_choices = [
- to_quantity_decimals($item_info->receiving_quantity) => 'x' . to_quantity_decimals($item_info->receiving_quantity),
- 1 => 'x1'
- ];
- }
-
- if(is_null($receiving_quantity))
- {
- $receiving_quantity = $item_info->receiving_quantity;
- }
-
- $attribute_links = $this->attribute->get_link_values($item_id, 'receiving_id', $receiving_id, Attribute::SHOW_IN_RECEIVINGS)->getRowObject();
-
- $item = [
- $insertkey => [
- 'item_id' => $item_id,
- 'item_location' => $item_location,
- 'item_number' => $item_info->item_number,
- 'stock_name' => $this->stock_location->get_location_name($item_location),
- 'line' => $insertkey,
- 'name' => $item_info->name,
- 'description' => $description != null ? $description: $item_info->description,
- 'serialnumber' => $serialnumber != null ? $serialnumber: '',
- 'attribute_values' => $attribute_links->attribute_values,
- 'attribute_dtvalues' => $attribute_links->attribute_dtvalues,
- 'allow_alt_description' => $item_info->allow_alt_description,
- 'is_serialized' => $item_info->is_serialized,
- 'quantity' => $quantity,
- 'discount' => $discount,
- 'discount_type' => $discount_type,
- 'in_stock' => $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity,
- 'price' => $price,
- 'receiving_quantity' => $receiving_quantity,
- 'receiving_quantity_choices' => $receiving_quantity_choices,
- 'total' => $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity)
- ]
- ];
-
- //Item already exists
- if($itemalreadyinsale) //TODO: This variable does not adhere to naming conventions.
- {
- $items[$updatekey]['quantity'] += $quantity;
- $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount, $discount_type, $items[$updatekey]['receiving_quantity']);
- }
- else
- {
- //add to existing array
- $items += $item;
- }
-
- $this->set_cart($items);
-
- return true;
- }
-
- /**
- * @param $line
- * @param string $description
- * @param string $serialnumber
- * @param float $quantity
- * @param float $discount
- * @param int|null $discount_type
- * @param float $price
- * @param float $receiving_quantity
- * @return bool
- */
- public function edit_item($line, string $description, string $serialnumber, float $quantity, float $discount, ?int $discount_type, float $price, float $receiving_quantity): bool
- {
- $items = $this->get_cart();
- if(isset($items[$line]))
- {
- $line = &$items[$line];
- $line['description'] = $description;
- $line['serialnumber'] = $serialnumber;
- $line['quantity'] = $quantity;
- $line['receiving_quantity'] = $receiving_quantity;
- $line['discount'] = $discount;
-
- if(!is_null($discount_type))
- {
- $line['discount_type'] = $discount_type;
- }
-
- $line['price'] = $price;
- $line['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity);
- $this->set_cart($items);
- }
-
- return false; //TODO: This function will always return false.
- }
-
- /**
- * @param $line int|string The item_number or item_id of the item to be removed from the receiving.
- */
- public function delete_item($line): void
- {
- $items = $this->get_cart();
- unset($items[$line]);
- $this->set_cart($items);
- }
-
- /**
- * @param int $receipt_receiving_id
- * @return void
- */
- public function return_entire_receiving(int $receipt_receiving_id): void
- {
- //RECV #
- $pieces = explode(' ', $receipt_receiving_id);
-
- if(preg_match("/(RECV|KIT)/", $pieces[0])) //TODO: this needs to be converted to ternary notation.
- {
- $receiving_id = $pieces[1];
- }
- else
- {
- $receiving_id = $this->receiving->get_receiving_by_reference($receipt_receiving_id)->getRow()->receiving_id;
- }
-
- $this->empty_cart();
- $this->remove_supplier();
- $this->clear_comment();
-
- foreach($this->receiving->get_receiving_items($receiving_id)->getResult() as $row)
- {
- $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, true);
- }
-
- $this->set_supplier($this->receiving->get_supplier($receiving_id)->person_id);
- }
-
- /**
- * @param string $external_item_kit_id
- * @param int $item_location
- * @param float $discount
- * @param int $discount_type
- * @return void
- */
- public function add_item_kit(string $external_item_kit_id, int $item_location, float $discount, int $discount_type): void
- {
- //KIT #
- $pieces = explode(' ',$external_item_kit_id);
- $item_kit_id = count($pieces) > 1 ? $pieces[1] : $external_item_kit_id;
-
- foreach($this->item_kit_items->get_info($item_kit_id) as $item_kit_item)
- {
- $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, $discount_type);
- }
- }
-
- /**
- * @param int $receiving_id
- * @return void
- */
- public function copy_entire_receiving(int $receiving_id): void
- {
- $this->empty_cart();
- $this->remove_supplier();
-
- foreach($this->receiving->get_receiving_items($receiving_id)->getResult() as $row)
- {
- $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, true);
- }
-
- $this->set_supplier((int) $this->receiving->get_supplier($receiving_id)->person_id);
- //$this->set_reference($this->receiving->get_info($receiving_id)->getRow()->reference); //TODO: If this code won't be added back in, then let's delete it.
- }
-
- /**
- * @return void
- */
- public function clear_all(): void
- {
- $this->clear_mode();
- $this->empty_cart();
- $this->remove_supplier();
- $this->clear_comment();
- $this->clear_reference();
- }
-
- /**
- * @param float $quantity
- * @param float $price
- * @param float $discount
- * @param int|null $discount_type
- * @param float $receiving_quantity
- * @return string
- */
- public function get_item_total(float $quantity, float $price, float $discount, ?int $discount_type, float $receiving_quantity): string
- {
- $extended_quantity = bcmul($quantity, $receiving_quantity);
- $total = bcmul($extended_quantity, $price);
- $discount_amount = $discount;
-
- if($discount_type == PERCENT) //TODO: === ?
- {
- $discount_fraction = bcdiv($discount, 100);
- $discount_amount = bcmul($total, $discount_fraction);
- }
-
- return bcsub($total, $discount_amount);
- }
-
- /**
- * @return string
- */
- public function get_total(): string
- {
- $total = 0;
- foreach($this->get_cart() as $item)
- {
- $total = bcadd($total, $this->get_item_total(($item['quantity']), $item['price'], $item['discount'], $item['discount_type'], $item['receiving_quantity']));
- }
-
- return $total;
- }
+ private Attribute $attribute;
+ private Item $item;
+ private Item_kit_items $item_kit_items;
+ private Item_quantity $item_quantity;
+ private Receiving $receiving;
+ private Stock_location $stock_location;
+ private Session $session;
+
+ public function __construct()
+ {
+ $this->attribute = model(Attribute::class);
+ $this->item = model(Item::class);
+ $this->item_kit_items = model(Item_kit_items::class);
+ $this->item_quantity = model(Item_quantity::class);
+ $this->receiving = model(Receiving::class);
+ $this->stock_location = model(Stock_location::class);
+
+ $this->session = session();
+ }
+
+ /**
+ * @return array
+ */
+ public function get_cart(): array
+ {
+ if(!$this->session->get('recv_cart'))
+ {
+ $this->set_cart ([]);
+ }
+
+ return $this->session->get('recv_cart');
+ }
+
+ /**
+ * @param array $cart_data
+ * @return void
+ */
+ public function set_cart(array $cart_data): void
+ {
+ $this->session->set('recv_cart', $cart_data);
+ }
+
+ /**
+ * @return void
+ */
+ public function empty_cart(): void
+ {
+ $this->session->remove('recv_cart');
+ }
+
+ /**
+ * @return int
+ */
+ public function get_supplier(): int
+ {
+ if(!$this->session->get('recv_supplier'))
+ {
+ $this->set_supplier(-1); //TODO: Replace -1 with a constant.
+ }
+
+ return $this->session->get('recv_supplier');
+ }
+
+ /**
+ * @param int $supplier_id
+ * @return void
+ */
+ public function set_supplier(int $supplier_id): void
+ {
+ $this->session->set('recv_supplier', $supplier_id);
+ }
+
+ /**
+ * @return void
+ */
+ public function remove_supplier(): void
+ {
+ $this->session->remove('recv_supplier');
+ }
+
+ /**
+ * @return string
+ */
+ public function get_mode(): string
+ {
+ if(!$this->session->get('recv_mode'))
+ {
+ $this->set_mode('receive');
+ }
+
+ return $this->session->get('recv_mode');
+ }
+
+ /**
+ * @param string $mode
+ * @return void
+ */
+ public function set_mode(string $mode): void
+ {
+ $this->session->set('recv_mode', $mode);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_mode(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_mode()
+ {
+ $this->session->remove('recv_mode');
+ }
+
+ /**
+ * @return int
+ */
+ public function get_stock_source(): int
+ {
+ if(!$this->session->get('recv_stock_source'))
+ {
+ $this->set_stock_source($this->stock_location->get_default_location_id('receivings'));
+ }
+
+ return $this->session->get('recv_stock_source');
+ }
+
+ /**
+ * @return string
+ */
+ public function get_comment(): string
+ {
+ $comment = $this->session->get('recv_comment');
+
+ return empty($comment) ? '' : $comment;
+ }
+
+ /**
+ * @param string $comment
+ * @return void
+ */
+ public function set_comment(string $comment): void
+ {
+ $this->session->set('recv_comment', $comment);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_comment(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_comment()
+ {
+ $this->session->remove('recv_comment');
+ }
+
+ /**
+ * @return string
+ */
+ public function get_reference(): string
+ {
+ return $this->session->get('recv_reference') ?? '';
+ }
+
+ /**
+ * @param string $reference
+ * @return void
+ */
+ public function set_reference(string $reference): void
+ {
+ $this->session->set('recv_reference', $reference);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_reference(): void //TODO: This function verb is inconsistent from the others. Consider refactoring to remove_reference()
+ {
+ $this->session->remove('recv_reference');
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_print_after_sale(): bool
+ {
+ return $this->session->get('recv_print_after_sale') == 'true'
+ || $this->session->get('recv_print_after_sale') == '1';
+ }
+
+ /**
+ * @param bool $print_after_sale
+ * @return void
+ */
+ public function set_print_after_sale(bool $print_after_sale): void
+ {
+ $this->session->set('recv_print_after_sale', $print_after_sale);
+ }
+
+ /**
+ * @param int $stock_source
+ * @return void
+ */
+ public function set_stock_source(int $stock_source): void
+ {
+ $this->session->set('recv_stock_source', $stock_source);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_stock_source(): void
+ {
+ $this->session->remove('recv_stock_source');
+ }
+
+ /**
+ * @return string
+ */
+ public function get_stock_destination(): string
+ {
+ if(!$this->session->get('recv_stock_destination'))
+ {
+ $this->set_stock_destination($this->stock_location->get_default_location_id('receivings'));
+ }
+
+ return $this->session->get('recv_stock_destination');
+ }
+
+ /**
+ * @param string $stock_destination
+ * @return void
+ */
+ public function set_stock_destination(?string $stock_destination): void
+ {
+ $this->session->set('recv_stock_destination', $stock_destination);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_stock_destination(): void
+ {
+ $this->session->remove('recv_stock_destination');
+ }
+ //TODO: This array signature needs to be reworked. It's way too long. Perhaps an object needs to be passed rather than these?
+
+ /**
+ * @param int $item_id
+ * @param int $quantity
+ * @param int|null $item_location
+ * @param float $discount
+ * @param int $discount_type
+ * @param float|null $price
+ * @param string|null $description
+ * @param string|null $serialnumber
+ * @param float|null $receiving_quantity
+ * @param int|null $receiving_id
+ * @param bool $include_deleted
+ * @return bool
+ */
+ public function add_item(int $item_id, int $quantity = 1, int $item_location = null, float $discount = 0, int $discount_type = 0, float $price = null, string $description = null, string $serialnumber = null, float $receiving_quantity = null, int $receiving_id = null, bool $include_deleted = false): bool
+ {
+ $config = config(OSPOS::class)->settings;
+
+ //make sure item exists in database.
+ if(!$this->item->exists($item_id, $include_deleted))
+ {
+ //try to get item id given an item_number
+ $item_id = $this->item->get_item_id($item_id, $include_deleted);
+
+ if(!$item_id)
+ {
+ return false;
+ }
+ }
+
+ //Get items in the receiving so far.
+ $items = $this->get_cart();
+
+ //We need to loop through all items in the cart.
+ //If the item is already there, get it's key($updatekey).
+ //We also need to get the next key that we are going to use in case we need to add the
+ //item to the list. Since items can be deleted, we can't use a count. we use the highest key + 1.
+
+ $maxkey = 0; //Highest key so far
+ $itemalreadyinsale = false; //We did not find the item yet.
+ $updatekey = 0; //Key to use to update(quantity)
+
+ foreach($items as $item)
+ {
+ //We primed the loop so maxkey is 0 the first time.
+ //Also, we have stored the key in the element itself, so we can compare.
+ //There is an array public function to get the associated key for an element, but I like it better
+ //like that!
+
+ if($maxkey <= $item['line'])
+ {
+ $maxkey = $item['line'];
+ }
+
+ if($item['item_id'] == $item_id && $item['item_location'] == $item_location)
+ {
+ $itemalreadyinsale = true;
+ $updatekey = $item['line'];
+ }
+ }
+
+ $insertkey = $maxkey + 1;
+ $item_info = $this->item->get_info($item_id);
+
+ //array records are identified by $insertkey and item_id is just another field.
+ $price = $price != null ? $price : $item_info->cost_price;
+
+ if($config['multi_pack_enabled'])
+ {
+ $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
+ }
+
+ if ($item_info->receiving_quantity == 0 || $item_info->receiving_quantity == 1)
+ {
+ $receiving_quantity_choices = [1 => 'x1'];
+ }
+ else
+ {
+ $receiving_quantity_choices = [
+ to_quantity_decimals($item_info->receiving_quantity) => 'x' . to_quantity_decimals($item_info->receiving_quantity),
+ 1 => 'x1'
+ ];
+ }
+
+ if(is_null($receiving_quantity))
+ {
+ $receiving_quantity = $item_info->receiving_quantity;
+ }
+
+ $attribute_links = $this->attribute->get_link_values($item_id, 'receiving_id', $receiving_id, Attribute::SHOW_IN_RECEIVINGS)->getRowObject();
+
+ $item = [
+ $insertkey => [
+ 'item_id' => $item_id,
+ 'item_location' => $item_location,
+ 'item_number' => $item_info->item_number,
+ 'stock_name' => $this->stock_location->get_location_name($item_location),
+ 'line' => $insertkey,
+ 'name' => $item_info->name,
+ 'description' => $description != null ? $description: $item_info->description,
+ 'serialnumber' => $serialnumber != null ? $serialnumber: '',
+ 'attribute_values' => $attribute_links->attribute_values,
+ 'attribute_dtvalues' => $attribute_links->attribute_dtvalues,
+ 'allow_alt_description' => $item_info->allow_alt_description,
+ 'is_serialized' => $item_info->is_serialized,
+ 'quantity' => $quantity,
+ 'discount' => $discount,
+ 'discount_type' => $discount_type,
+ 'in_stock' => $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity,
+ 'price' => $price,
+ 'receiving_quantity' => $receiving_quantity,
+ 'receiving_quantity_choices' => $receiving_quantity_choices,
+ 'total' => $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity)
+ ]
+ ];
+
+ //Item already exists
+ if($itemalreadyinsale) //TODO: This variable does not adhere to naming conventions.
+ {
+ $items[$updatekey]['quantity'] += $quantity;
+ $items[$updatekey]['total'] = $this->get_item_total($items[$updatekey]['quantity'], $price, $discount, $discount_type, $items[$updatekey]['receiving_quantity']);
+ }
+ else
+ {
+ //add to existing array
+ $items += $item;
+ }
+
+ $this->set_cart($items);
+
+ return true;
+ }
+
+ /**
+ * @param $line
+ * @param string $description
+ * @param string $serialnumber
+ * @param float $quantity
+ * @param float $discount
+ * @param int|null $discount_type
+ * @param float $price
+ * @param float $receiving_quantity
+ * @return bool
+ */
+ public function edit_item($line, string $description, string $serialnumber, float $quantity, float $discount, ?int $discount_type, float $price, float $receiving_quantity): bool
+ {
+ $items = $this->get_cart();
+ if(isset($items[$line]))
+ {
+ $line = &$items[$line];
+ $line['description'] = $description;
+ $line['serialnumber'] = $serialnumber;
+ $line['quantity'] = $quantity;
+ $line['receiving_quantity'] = $receiving_quantity;
+ $line['discount'] = $discount;
+
+ if(!is_null($discount_type))
+ {
+ $line['discount_type'] = $discount_type;
+ }
+
+ $line['price'] = $price;
+ $line['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, $receiving_quantity);
+ $this->set_cart($items);
+ }
+
+ return false; //TODO: This function will always return false.
+ }
+
+ /**
+ * @param $line int|string The item_number or item_id of the item to be removed from the receiving.
+ */
+ public function delete_item($line): void
+ {
+ $items = $this->get_cart();
+ unset($items[$line]);
+ $this->set_cart($items);
+ }
+
+ /**
+ * @param int $receipt_receiving_id
+ * @return void
+ */
+ public function return_entire_receiving(int $receipt_receiving_id): void
+ {
+ //RECV #
+ $pieces = explode(' ', $receipt_receiving_id);
+
+ if(preg_match("/(RECV|KIT)/", $pieces[0])) //TODO: this needs to be converted to ternary notation.
+ {
+ $receiving_id = $pieces[1];
+ }
+ else
+ {
+ $receiving_id = $this->receiving->get_receiving_by_reference($receipt_receiving_id)->getRow()->receiving_id;
+ }
+
+ $this->empty_cart();
+ $this->remove_supplier();
+ $this->clear_comment();
+
+ foreach($this->receiving->get_receiving_items($receiving_id)->getResult() as $row)
+ {
+ $this->add_item($row->item_id, -$row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, true);
+ }
+
+ $this->set_supplier($this->receiving->get_supplier($receiving_id)->person_id);
+ }
+
+ /**
+ * @param string $external_item_kit_id
+ * @param int $item_location
+ * @param float $discount
+ * @param int $discount_type
+ * @return void
+ */
+ public function add_item_kit(string $external_item_kit_id, int $item_location, float $discount, int $discount_type): void
+ {
+ //KIT #
+ $pieces = explode(' ',$external_item_kit_id);
+ $item_kit_id = count($pieces) > 1 ? $pieces[1] : $external_item_kit_id;
+
+ foreach($this->item_kit_items->get_info($item_kit_id) as $item_kit_item)
+ {
+ $this->add_item($item_kit_item['item_id'], $item_kit_item['quantity'], $item_location, $discount, $discount_type);
+ }
+ }
+
+ /**
+ * @param int $receiving_id
+ * @return void
+ */
+ public function copy_entire_receiving(int $receiving_id): void
+ {
+ $this->empty_cart();
+ $this->remove_supplier();
+
+ foreach($this->receiving->get_receiving_items($receiving_id)->getResult() as $row)
+ {
+ $this->add_item($row->item_id, $row->quantity_purchased, $row->item_location, $row->discount, $row->discount_type, $row->item_unit_price, $row->description, $row->serialnumber, $row->receiving_quantity, $receiving_id, true);
+ }
+
+ $this->set_supplier((int) $this->receiving->get_supplier($receiving_id)->person_id);
+ //$this->set_reference($this->receiving->get_info($receiving_id)->getRow()->reference); //TODO: If this code won't be added back in, then let's delete it.
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_all(): void
+ {
+ $this->clear_mode();
+ $this->empty_cart();
+ $this->remove_supplier();
+ $this->clear_comment();
+ $this->clear_reference();
+ }
+
+ /**
+ * @param float $quantity
+ * @param float $price
+ * @param float $discount
+ * @param int|null $discount_type
+ * @param float $receiving_quantity
+ * @return string
+ */
+ public function get_item_total(float $quantity, float $price, float $discount, ?int $discount_type, float $receiving_quantity): string
+ {
+ $extended_quantity = bcmul($quantity, $receiving_quantity);
+ $total = bcmul($extended_quantity, $price);
+ $discount_amount = $discount;
+
+ if($discount_type == PERCENT) //TODO: === ?
+ {
+ $discount_fraction = bcdiv($discount, 100);
+ $discount_amount = bcmul($total, $discount_fraction);
+ }
+
+ return bcsub($total, $discount_amount);
+ }
+
+ /**
+ * @return string
+ */
+ public function get_total(): string
+ {
+ $total = 0;
+ foreach($this->get_cart() as $item)
+ {
+ $total = bcadd($total, $this->get_item_total(($item['quantity']), $item['price'], $item['discount'], $item['discount_type'], $item['receiving_quantity']));
+ }
+
+ return $total;
+ }
}
diff --git a/app/Libraries/Sale_lib.php b/app/Libraries/Sale_lib.php
index 37fc64f09..ffca37795 100644
--- a/app/Libraries/Sale_lib.php
+++ b/app/Libraries/Sale_lib.php
@@ -23,1777 +23,1777 @@ use ReflectionException;
*/
class Sale_lib
{
- private Attribute $attribute;
- private Customer $customer;
- private Dinner_table $dinner_table;
- private Item $item;
- private Item_kit_items $item_kit_items;
- private Item_quantity $item_quantity;
- private Item_taxes $item_taxes;
- private Sale $sale;
- private Stock_location $stock_location;
- private Session $session;
- private array $config;
-
- public function __construct()
- {
- $this->session = session();
-
- $this->attribute = model(Attribute::class);
- $this->customer = model(Customer::class);
- $this->dinner_table = model(Dinner_table::class);
- $this->item = model(Item::class);
- $this->item_kit_items = model(Item_kit_items::class);
- $this->item_quantity = model(Item_quantity::class);
- $this->item_taxes = model(Item_taxes::class);
- $this->sale = model(Sale::class);
- $this->stock_location = model(Stock_location::class);
- $this->config = config(OSPOS::class)->settings;
- }
-
- /**
- * @return array
- */
- public function get_line_sequence_options(): array
- {
- return [
- '0' => lang('Sales.entry'),
- '1' => lang('Sales.group_by_type'),
- '2' => lang('Sales.group_by_category')
- ];
- }
-
- /**
- * @return array
- */
- public function get_register_mode_options(): array
- {
- $register_modes = [];
-
- if(!$this->config['invoice_enable'])
- {
- $register_modes['sale'] = lang('Sales.sale');
- }
- else
- {
- $register_modes['sale'] = lang('Sales.receipt');
- $register_modes['sale_quote'] = lang('Sales.quote');
-
- if($this->config['work_order_enable'])
- {
- $register_modes['sale_work_order'] = lang('Sales.work_order');
- }
-
- $register_modes['sale_invoice'] = lang('Sales.invoice');
- }
-
- $register_modes['return'] = lang('Sales.return');
-
- return $register_modes;
- }
-
- /**
- * @return array
- */
- public function get_invoice_type_options(): array
- {
- $invoice_types = [];
- $invoice_types['invoice'] = lang('Sales.invoice_type_invoice');
- $invoice_types['tax_invoice'] = lang('Sales.invoice_type_tax_invoice');
- $invoice_types['custom_invoice'] = lang('Sales.invoice_type_custom_invoice');
- $invoice_types['custom_tax_invoice'] = lang('Sales.invoice_type_custom_tax_invoice');
- return $invoice_types;
- }
-
- /**
- * @return array
- */
- public function get_cart(): array
- {
- if(!$this->session->get('sales_cart'))
- {
- $this->set_cart ([]);
- }
-
- return $this->session->get('sales_cart');
- }
-
- /**
- * @param array $cart
- * @return array
- */
- public function sort_and_filter_cart(array $cart): array
- {
- if(empty($cart))
- {
- return $cart;
- }
-
- $filtered_cart = [];
-
- foreach($cart as $k => $v) //TODO: We should not be using single-letter variable names for readability. Several of these foreach loops should be refactored.
- {
- if($v['print_option'] == PRINT_YES)
- {
- if($v['price'] == 0.0)
- {
- $v['discount'] = 0.0;
- }
- $filtered_cart[] = $v;
- }
- }
-
- //TODO: This set of if/elseif/else needs to be converted to a switch statement
- // Entry sequence (this will render kits in the expected sequence)
- if($this->config['line_sequence'] == '0')
- {
- $sort = [];
- foreach($filtered_cart as $k => $v)
- {
- $sort['line'][$k] = $v['line'];
- }
- array_multisort($sort['line'], SORT_ASC, $filtered_cart);
- }
- // Group by Stock Type (nonstock first - type 1, stock next - type 0)
- elseif($this->config['line_sequence'] == '1') //TODO: Need to change these to constants
- {
- $sort = [];
- foreach($filtered_cart as $k => $v)
- {
- $sort['stock_type'][$k] = $v['stock_type'];
- $sort['description'][$k] = $v['description'];
- $sort['name'][$k] = $v['name'];
- }
- array_multisort($sort['stock_type'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC, $filtered_cart);
- }
- // Group by Item Category
- elseif($this->config['line_sequence'] == '2') //TODO: Need to change these to constants
- {
- $sort = [];
- foreach($filtered_cart as $k => $v)
- {
- $sort['category'][$k] = $v['stock_type'];
- $sort['description'][$k] = $v['description'];
- $sort['name'][$k] = $v['name'];
- }
- array_multisort($sort['category'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC, $filtered_cart);
- }
- // Group by entry sequence in descending sequence (the Standard)
- else
- {
- $sort = [];
- foreach($filtered_cart as $k => $v)
- {
- $sort['line'][$k] = $v['line'];
- }
- array_multisort($sort['line'], SORT_ASC, $filtered_cart);
- }
-
- return $filtered_cart;
- }
-
- /**
- * @param array $cart_data
- * @return void
- */
- public function set_cart(array $cart_data): void
- {
- $this->session->set('sales_cart', $cart_data);
- }
-
- /**
- * @return void
- */
- public function empty_cart(): void
- {
- $this->session->remove('sales_cart');
- }
-
- /**
- * @return void
- */
- public function remove_temp_items(): void
- {
- // Loop through the cart items and delete temporary items specific to this sale
- $cart = $this->get_cart();
- foreach($cart as $line=>$item)
- {
- if($item['item_type'] == ITEM_TEMP) //TODO: === ?
- {
- $this->item->delete($item['item_id']);
- }
- }
- }
-
- /**
- * @return string
- */
- public function get_comment(): string
- {
- // avoid returning a null that results in a 0 in the comment if nothing is set/available
- $comment = $this->session->get('sales_comment');
-
- return empty($comment) ? '' : $comment;
- }
-
- /**
- * @param string $comment
- * @return void
- */
- public function set_comment(string $comment): void
- {
- $this->session->set('sales_comment', $comment);
- }
-
- /**
- * @return void
- */
- public function clear_comment(): void
- {
- $this->session->remove('sales_comment');
- }
-
- /**
- * @return string|null
- */
- public function get_invoice_number(): ?string
- {
- return $this->session->get('sales_invoice_number');
- }
-
- /**
- * @return string|null
- */
- public function get_quote_number(): ?string
- {
- return $this->session->get('sales_quote_number');
- }
-
- /**
- * @return string|null
- */
- public function get_work_order_number(): ?string
- {
- return $this->session->get('sales_work_order_number');
- }
-
- /**
- * @return int|null
- */
- public function get_sale_type(): ?int
- {
- return $this->session->get('sale_type', 0);
- }
-
- /**
- * @param int $invoice_number
- * @param bool $keep_custom
- * @return void
- */
- public function set_invoice_number(int $invoice_number, bool $keep_custom = false): void
- {
- $current_invoice_number = $this->session->get('sales_invoice_number');
-
- if(!$keep_custom || empty($current_invoice_number))
- {
- $this->session->set('sales_invoice_number', $invoice_number);
- }
- }
-
- /**
- * @param string|null $quote_number
- * @param bool $keep_custom
- * @return void
- */
- public function set_quote_number(?string $quote_number, bool $keep_custom = false): void
- {
- $current_quote_number = $this->session->get('sales_quote_number');
-
- if(!$keep_custom || empty($current_quote_number))
- {
- $this->session->set('sales_quote_number', $quote_number);
- }
- }
-
- /**
- * @param string|null $work_order_number
- * @param bool $keep_custom
- * @return void
- */
- public function set_work_order_number(?string $work_order_number, bool $keep_custom = false): void
- {
- $current_work_order_number = $this->session->get('sales_work_order_number');
-
- if(!$keep_custom || empty($current_work_order_number))
- {
- $this->session->set('sales_work_order_number', $work_order_number);
- }
- }
-
- /**
- * @param int $sale_type
- * @param bool $keep_custom
- * @return void
- */
- public function set_sale_type(int $sale_type, bool $keep_custom = false): void
- {
- $current_sale_type = $this->session->get('sale_type');
-
- if(!$keep_custom || empty($current_sale_type))
- {
- $this->session->set('sale_type', $sale_type);
- }
- }
-
- /**
- * @return void
- */
- public function clear_invoice_number(): void
- {
- $this->session->remove('sales_invoice_number');
- }
-
- /**
- * @return void
- */
- public function clear_quote_number(): void
- {
- $this->session->remove('sales_quote_number');
- }
-
- /**
- * @return void
- */
- public function clear_work_order_number(): void
- {
- $this->session->remove('sales_work_order_number');
- }
-
- /**
- * @return void
- */
- public function clear_sale_type(): void
- {
- $this->session->remove('sale_type');
- }
-
- /**
- * @param int $suspended_id
- * @return void
- */
- public function set_suspended_id(int $suspended_id): void
- {
- $this->session->set('suspended_id', $suspended_id);
- }
-
- /**
- * @return int
- */
- public function get_suspended_id(): int
- {
- return $this->session->get('suspended_id');
- }
-
- /**
- * @return bool
- */
- public function is_invoice_mode(): bool
- {
- return ($this->session->get('sales_mode') == 'sale_invoice' && $this->config['invoice_enable']);
- }
-
- /**
- * @return bool
- */
- public function is_sale_by_receipt_mode(): bool //TODO: This function is not called anywhere in the code.
- {
- return ($this->session->get('sales_mode') == 'sale'); //TODO: === ?
- }
-
- /**
- * @return bool
- */
- public function is_quote_mode(): bool
- {
- return ($this->session->get('sales_mode') == 'sale_quote'); //TODO: === ?
- }
-
- /**
- * @return bool
- */
- public function is_return_mode(): bool
- {
- return ($this->session->get('sales_mode') == 'return'); //TODO: === ?
- }
-
- /**
- * @return bool
- */
- public function is_work_order_mode(): bool
- {
- return ($this->session->get('sales_mode') == 'sale_work_order'); //TODO: === ?
- }
-
- /**
- * @param string $price_work_orders
- * @return void
- */
- public function set_price_work_orders(string $price_work_orders): void
- {
- $this->session->set('sales_price_work_orders', $price_work_orders);
- }
-
- /**
- * @return bool
- */
- public function is_price_work_orders(): bool
- {
- return ($this->session->get('sales_price_work_orders') == 'true' //TODO: === ?
- || $this->session->get('sales_price_work_orders') == '1'); //TODO: === ?
- }
-
- /**
- * @param bool $print_after_sale
- * @return void
- */
- public function set_print_after_sale(bool $print_after_sale): void
- {
- $this->session->set('sales_print_after_sale', $print_after_sale);
- }
-
- /**
- * @return bool
- */
- public function is_print_after_sale(): bool
- {//TODO: this needs to be converted to a switch statement
- if($this->config['print_receipt_check_behaviour'] == 'always') //TODO: 'behaviour' is the british spelling, but the rest of the code is in American English. Not a big deal, but noticed. Also ===
- {
- return true;
- }
- elseif($this->config['print_receipt_check_behaviour'] == 'never') //TODO: === ?
- {
- return false;
- }
- else // remember last setting, session based though
- {
- return ($this->session->get('sales_print_after_sale') == 'true' //TODO: === ?
- || $this->session->get('sales_print_after_sale') == '1'); //TODO: === ?
- }
- }
-
- /**
- * @param string $email_receipt
- * @return void
- */
- public function set_email_receipt(string $email_receipt): void
- {
- $this->session->set('sales_email_receipt', $email_receipt);
- }
-
- /**
- * @return void
- */
- public function clear_email_receipt(): void
- {
- $this->session->remove('sales_email_receipt');
- }
-
- /**
- * @return bool
- */
- public function is_email_receipt(): bool
- {//TODO: this needs to be converted to a switch statement
- if($this->config['email_receipt_check_behaviour'] == 'always') //TODO: 'behaviour' is the british spelling, but the rest of the code is in American English. Not a big deal, but noticed. Also ===
- {
- return true;
- }
- elseif($this->config['email_receipt_check_behaviour'] == 'never') //TODO: === ?
- {
- return false;
- }
- else // remember last setting, session based though
- {
- return ($this->session->get('sales_email_receipt') == 'true' //TODO: === ?
- || $this->session->get('sales_email_receipt') == '1'); //TODO: === ?
- }
- }
-
- /**
- * Multiple Payments
- */
- public function get_payments(): array
- {
- if(!$this->session->get('sales_payments'))
- {
- $this->set_payments ([]);
- }
-
- return $this->session->get('sales_payments');
- }
-
- /**
- * Multiple Payments
- */
- public function set_payments(array $payments_data): void
- {
- $this->session->set('sales_payments', $payments_data);
- }
-
- /**
- * Adds a new payment to the payments array or updates an existing one.
- * It will also disable cash_mode if a non-qualifying payment type is added.
- * @param string $payment_id
- * @param string $payment_amount
- * @param int $cash_adjustment
- */
- public function add_payment(string $payment_id, string $payment_amount, int $cash_adjustment = CASH_ADJUSTMENT_FALSE): void
- {
- $payments = $this->get_payments();
- if(isset($payments[$payment_id]))
- {
- //payment_method already exists, add to payment_amount
- $payments[$payment_id]['payment_amount'] = bcadd($payments[$payment_id]['payment_amount'], $payment_amount);
- }
- else
- {
- //add to existing array
- $payment = [
- $payment_id => [
- 'payment_type' => $payment_id,
- 'payment_amount' => $payment_amount,
- 'cash_refund' => 0,
- 'cash_adjustment' => $cash_adjustment
- ]
- ];
-
- $payments += $payment;
- }
-
- if($this->session->get('cash_mode'))
- {
- if($this->session->get('cash_rounding') && $payment_id != lang('Sales.cash') && $payment_id != lang('Sales.cash_adjustment'))
- {
- $this->session->set('cash_mode', CASH_MODE_FALSE);
- }
- }
-
- $this->set_payments($payments);
- }
-
- /**
- * Multiple Payments
- */
- public function edit_payment(string $payment_id, float $payment_amount): bool
- {
- $payments = $this->get_payments();
- if(isset($payments[$payment_id]))
- {
- $payments[$payment_id]['payment_type'] = $payment_id;
- $payments[$payment_id]['payment_amount'] = $payment_amount;
- $this->set_payments($payments);
-
- return true;
- }
-
- return false;
- }
-
- /**
- * Delete the selected payment from the payment array and if cash rounding is enabled
- * and the payment type is one of the cash types then automatically delete the other
- * @param string $payment_id
- */
- public function delete_payment(string $payment_id): void
- {
- $payments = $this->get_payments();
- $decoded_payment_id = urldecode($payment_id);
-
- unset($payments[$decoded_payment_id]);
-
- $cash_rounding = $this->reset_cash_rounding();
-
- if($cash_rounding)
- {
- if($decoded_payment_id == lang('Sales.cash')) //TODO: === ?
- {
- unset($payments[lang('Sales.cash_adjustment')]);
- }
-
- if($decoded_payment_id == lang('Sales.cash_adjustment')) //TODO: === ?
- {
- unset($payments[lang('Sales.cash')]);
- }
- }
- $this->set_payments($payments);
- }
-
- /**
- * Multiple Payments
- */
- public function empty_payments(): void //TODO: function verbs are very inconsistent in these libraries.
- {
- $this->session->remove('sales_payments');
- }
-
- /**
- * Retrieve the total payments made, excluding any cash adjustments
- * and establish if cash_mode is in play
- */
- public function get_payments_total(): string
- {
- $subtotal = '0.0';
- $cash_mode_eligible = CASH_MODE_TRUE;
-
- foreach($this->get_payments() as $payments)
- {
- if(!$payments['cash_adjustment'])
- {
- $subtotal = bcadd($payments['payment_amount'], $subtotal);
- }
- if(lang('Sales.cash') != $payments['payment_type'] && lang('Sales.cash_adjustment') != $payments['payment_type'])
- {
- $cash_mode_eligible = CASH_MODE_FALSE;
- }
- }
-
- if($cash_mode_eligible && $this->session->get('cash_rounding')) //TODO: $cache_mode_eligible will always evaluate to true
- {
- $this->session->set('cash_mode', CASH_MODE_TRUE);
- }
-
- return $subtotal;
- }
-
- /**
- * Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'paid_in_full'
- * 'subtotal', 'discounted_subtotal', 'tax_exclusive_subtotal', 'item_count', 'total_units', 'cash_adjustment_amount'
- */
- public function get_totals(array $taxes): array
- {
- $totals = [];
-
- $prediscount_subtotal = '0.0';
- $subtotal = '0.0';
- $total = '0.0';
- $total_discount = '0.0';
- $item_count = 0;
- $total_units = 0.0;
-
- foreach($this->get_cart() as $item)
- {
- if($item['stock_type'] == HAS_STOCK)
- {
- $item_count++;
- $total_units += $item['quantity'];
- }
- $discount_amount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']);
- $total_discount = bcadd($total_discount, $discount_amount);
-
- $extended_amount = $this->get_extended_amount($item['quantity'], $item['price']);
- $extended_discounted_amount = $this->get_extended_amount($item['quantity'], $item['price'], $discount_amount);
- $prediscount_subtotal = bcadd($prediscount_subtotal, $extended_amount);
- $total = bcadd($total, $extended_discounted_amount);
-
- $subtotal = bcadd($subtotal, $extended_discounted_amount);
- }
-
- $totals['prediscount_subtotal'] = $prediscount_subtotal;
- $totals['total_discount'] = $total_discount;
- $sales_tax = '0';
-
- foreach($taxes as $tax)
- {
- if($tax['tax_type'] === Tax_lib::TAX_TYPE_EXCLUDED)
- {
- $total = bcadd($total, $tax['sale_tax_amount']);
- $sales_tax = bcadd($sales_tax, $tax['sale_tax_amount']);
- }
- else
- {
- $subtotal = bcsub($subtotal, $tax['sale_tax_amount']);
- }
- }
-
- $totals['subtotal'] = $subtotal;
- $totals['total'] = $total;
- $totals['tax_total'] = $sales_tax;
-
- $payment_total = $this->get_payments_total();
- $totals['payment_total'] = $payment_total;
- $cash_rounding = $this->session->get('cash_rounding');
- $cash_mode = $this->session->get('cash_mode');
-
- if($cash_rounding)
- {
- $cash_total = $this->check_for_cash_rounding($total);
- $totals['cash_total'] = $cash_total;
- }
- else
- {
- $cash_total = $total;
- $totals['cash_total'] = $cash_total;
- }
-
- $amount_due = bcsub($total, $payment_total);
- $totals['amount_due'] = $amount_due;
-
- $cash_amount_due = bcsub($cash_total, $payment_total);
- $totals['cash_amount_due'] = $cash_amount_due;
-
- if($cash_mode) //TODO: Convert to ternary notation
- {
- $current_due = $cash_amount_due;
- }
- else
- {
- $current_due = $amount_due;
- }
-
- // 0 decimal -> 1 / 2 = 0.5, 1 decimals -> 0.1 / 2 = 0.05, 2 decimals -> 0.01 / 2 = 0.005
- $threshold = bcpow('10', (string)-totals_decimals()) / 2;
-
- if($this->get_mode() == 'return') //TODO: Convert to ternary notation.
- {
- $totals['payments_cover_total'] = $current_due > -$threshold;
- }
- else
- {
- $totals['payments_cover_total'] = $current_due < $threshold;
- }
-
- $totals['item_count'] = $item_count;
- $totals['total_units'] = $total_units;
- $totals['cash_adjustment_amount'] = 0.0;
-
- if($totals['payments_cover_total'])
- {
- $totals['cash_adjustment_amount'] = round($cash_total - $totals['total'], totals_decimals(), PHP_ROUND_HALF_UP);
- }
-
- $cash_mode = $this->session->get('cash_mode'); //TODO: This variable is never used.
-
- return $totals;
- }
-
- /**
- * Multiple Payments
- */
- public function get_amount_due(): string
- {
- // Payment totals need to be identified first so that we know whether or not there is a non-cash payment involved
- $payment_total = $this->get_payments_total();
- $sales_total = $this->get_total();
- $amount_due = bcsub($sales_total, $payment_total);
- $precision = totals_decimals();
- $rounded_due = bccomp((string)round((float)$amount_due, $precision, PHP_ROUND_HALF_UP), '0', $precision); //TODO: Is round() currency safe?
-
- // take care of rounding error introduced by round tripping payment amount to the browser
- return $rounded_due == 0 ? '0' : $amount_due; //TODO: ===
- }
-
- /**
- * @return int
- */
- public function get_customer(): int
- {
- if(!$this->session->get('sales_customer'))
- {
- $this->set_customer(-1); //TODO: Replace -1 with a constant
- }
-
- return $this->session->get('sales_customer');
- }
-
- /**
- * @param int $customer_id
- * @return void
- */
- public function set_customer(int $customer_id): void
- {
- $this->session->set('sales_customer', $customer_id);
- }
-
- /**
- * @return void
- */
- public function remove_customer(): void
- {
- $this->session->remove('sales_customer');
- }
-
- /**
- * @return int
- */
- public function get_employee(): int
- {
- if(!$this->session->get('sales_employee'))
- {
- $this->set_employee(-1); //TODO: Replace -1 with a constant
- }
-
- return $this->session->get('sales_employee');
- }
-
- /**
- * @param int $employee_id
- * @return void
- */
- public function set_employee(int $employee_id): void
- {
- $this->session->set('sales_employee', $employee_id);
- }
-
- /**
- * @return void
- */
- public function remove_employee(): void
- {
- $this->session->remove('sales_employee');
- }
-
- /**
- * @return string
- */
- public function get_mode(): string
- {
- if(!$this->session->get('sales_mode'))
- {
- $this->set_mode('sale');
- }
- return $this->session->get('sales_mode');
- }
-
- /**
- * @param string $mode
- * @return void
- */
- public function set_mode(string $mode): void
- {
- $this->session->set('sales_mode', $mode);
- }
-
- /**
- * @return void
- */
- public function clear_mode(): void
- {
- $this->session->remove('sales_mode');
- }
-
- /**
- * @return int|null
- */
- public function get_dinner_table(): ?int
- {
- if(!$this->session->get('dinner_table'))
- {
- if($this->config['dinner_table_enable'])
- {
- $this->set_dinner_table(1); //TODO: Replace 1 with constant
- }
- }
-
- return $this->session->get('dinner_table');
- }
-
- /**
- * @param int|null $dinner_table
- * @return void
- */
- public function set_dinner_table(?int $dinner_table): void
- {
- $this->session->set('dinner_table', $dinner_table);
- }
-
- /**
- * @return void
- */
- public function clear_table(): void
- {
- $this->session->remove('dinner_table');
- }
-
- /**
- * @return int
- */
- public function get_sale_location(): int
- {
- if(!$this->session->get('sales_location'))
- {
- $this->set_sale_location($this->stock_location->get_default_location_id('sales'));
- }
-
- return $this->session->get('sales_location');
- }
-
- /**
- * @param int $location
- * @return void
- */
- public function set_sale_location(int $location): void
- {
- $this->session->set('sales_location', $location);
- }
-
- /**
- * @param string $payment_type
- * @return void
- */
- public function set_payment_type(string $payment_type): void
- {
- $this->session->set('payment_type', $payment_type);
- }
-
- /**
- * @return string|null
- */
- public function get_payment_type(): ?string
- {
- return $this->session->get('payment_type');
- }
-
- /**
- * @return void
- */
- public function clear_sale_location(): void
- {
- $this->session->remove('sales_location');
- }
-
- /**
- * @param string $value
- * @return void
- */
- public function set_giftcard_remainder(string $value): void
- {
- $this->session->set('sales_giftcard_remainder', $value);
- }
-
- /**
- * @return string|null
- */
- public function get_giftcard_remainder(): ?string
- {
- return $this->session->get('sales_giftcard_remainder');
- }
-
- /**
- * @return void
- */
- public function clear_giftcard_remainder(): void
- {
- $this->session->remove('sales_giftcard_remainder');
- }
-
- /**
- * @param string $value
- * @return void
- */
- public function set_rewards_remainder(string $value): void
- {
- $this->session->set('sales_rewards_remainder', $value);
- }
-
- /**
- * @return string|null
- */
- public function get_rewards_remainder(): ?string
- {
- return $this->session->get('sales_rewards_remainder');
- }
-
- /**
- * @return void
- */
- public function clear_rewards_remainder(): void
- {
- $this->session->remove('sales_rewards_remainder');
- }
-
- //TODO: this function needs to be reworked... way too many parameters. Also, optional parameters must go after mandatory parameters.
-
- /**
- * @param int $item_id
- * @param int $item_location
- * @param string $quantity
- * @param string $discount
- * @param int $discount_type
- * @param int $price_mode
- * @param int|null $kit_price_option
- * @param int|null $kit_print_option
- * @param string|null $price_override
- * @param string|null $description
- * @param string|null $serialnumber
- * @param int|null $sale_id
- * @param bool $include_deleted
- * @param bool|null $print_option
- * @param bool|null $line
- * @return bool
- */
- public function add_item(int &$item_id, int $item_location, string $quantity = '1', string &$discount = '0.0', int $discount_type = 0, int $price_mode = PRICE_MODE_STANDARD, int $kit_price_option = null, int $kit_print_option = null, string $price_override = null, string $description = null, string $serialnumber = null, int $sale_id = null, bool $include_deleted = false, bool $print_option = null, bool $line = null): bool
- {
- $item_info = $this->item->get_info_by_id_or_number($item_id, $include_deleted);
-
- //make sure item exists
- if(empty($item_info))
- {
- $item_id = NEW_ENTRY;
- return false;
- }
-
- $applied_discount = $discount;
- $item_id = $item_info->item_id;
- $item_type = $item_info->item_type;
- $stock_type = $item_info->stock_type;
-
- $price = $item_info->unit_price;
- $cost_price = $item_info->cost_price;
- if($price_override != null)
- {
- $price = $price_override;
- }
-
- if($price_mode == PRICE_MODE_KIT)
- {
- if(!($kit_price_option == PRICE_OPTION_ALL
- || $kit_price_option == PRICE_OPTION_KIT && $item_type == ITEM_KIT
- || $kit_price_option == PRICE_OPTION_KIT_STOCK && $stock_type == HAS_STOCK)) //TODO: === ?
- {
- $price = '0.00';
- $applied_discount = '0.00';
- }
-
- // If price is zero do not include a discount regardless of type
- if($price == '0.00') //TODO: === ?
- {
- $applied_discount = '0.00';
- }
-
- // If fixed discount then apply no more than the item price
- if($discount_type == FIXED) //TODO: === ?
- {
- if($applied_discount > $price)
- {
- $applied_discount = $price;
- $discount -= $applied_discount;
- }
- else
- {
- $discount = 0;
- }
- }
- }
-
- // Serialization and Description
-
- //Get all items in the cart so far...
- $items = $this->get_cart();
-
- //We need to loop through all items in the cart.
- //If the item is already there, get it's key($updatekey).
- //We also need to get the next key that we are going to use in case we need to add the
- //item to the cart. Since items can be deleted, we can't use a count. we use the highest key + 1.
-
- $maxkey = 0; //Highest key so far
- $itemalreadyinsale = false; //We did not find the item yet. //TODO: variable naming here does not match the convention
- $insertkey = 0; //Key to use for new entry. //TODO: $insertkey is never used
- $updatekey = 0; //Key to use to update(quantity)
-
- foreach($items as $item)
- {
- //We primed the loop so maxkey is 0 the first time.
- //Also, we have stored the key in the element itself so we can compare.
-
- if($maxkey <= $item['line']) //TODO: variable naming here does not match the convention
- {
- $maxkey = $item['line'];
- }
-
- if($item['item_id'] == $item_id && $item['item_location'] == $item_location) //TODO: === ?
- {
- $itemalreadyinsale = true;
- $updatekey = $item['line'];
- if(!$item_info->is_serialized)
- {
- $quantity = bcadd($quantity, $items[$updatekey]['quantity']);
- }
- }
- }
-
- $insertkey = $maxkey + 1;//TODO Does not follow naming conventions.
- //array/cart records are identified by $insertkey and item_id is just another field.
-
- if($price_mode == PRICE_MODE_KIT) //TODO: === ?
- {
- if($kit_print_option == PRINT_ALL) //TODO: === ?
- {
- $print_option_selected = PRINT_YES;
- }
- elseif($kit_print_option == PRINT_KIT && $item_type == ITEM_KIT) //TODO: === ?
- {
- $print_option_selected = PRINT_YES;
- }
- elseif($kit_print_option == PRINT_PRICED && $price > 0) //TODO: === ?
- {
- $print_option_selected = PRINT_YES;
- }
- else
- {
- $print_option_selected = PRINT_NO;
- }
- }
- else
- { //TODO: Convert this to ternary notation
- if($print_option != null) //TODO: === ?
- {
- $print_option_selected = $print_option;
- }
- else
- {
- $print_option_selected = PRINT_YES;
- }
- }
-
- $total = $this->get_item_total($quantity, $price, $applied_discount, $discount_type);
- $discounted_total = $this->get_item_total($quantity, $price, $applied_discount, $discount_type, true);
-
- if($this->config['multi_pack_enabled'])
- {
- $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
- }
-
- $attribute_links = $this->attribute->get_link_values($item_id, 'sale_id', $sale_id, Attribute::SHOW_IN_SALES)->getRowObject();
-
- //Item already exists and is not serialized, add to quantity
- if(!$itemalreadyinsale || $item_info->is_serialized)
- {
- $item = [
- $insertkey => [
- 'item_id' => $item_id,
- 'item_location' => $item_location,
- 'stock_name' => $this->stock_location->get_location_name($item_location),
- 'line' => $insertkey,
- 'name' => $item_info->name,
- 'item_number' => $item_info->item_number,
- 'attribute_values' => $attribute_links->attribute_values,
- 'attribute_dtvalues' => $attribute_links->attribute_dtvalues,
- 'description' => $description != null ? $description : $item_info->description,
- 'serialnumber' => $serialnumber != null ? $serialnumber : '',
- 'allow_alt_description' => $item_info->allow_alt_description,
- 'is_serialized' => $item_info->is_serialized,
- 'quantity' => $quantity,
- 'discount' => $applied_discount,
- 'discount_type' => $discount_type,
- 'in_stock' => $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity,
- 'price' => $price,
- 'cost_price' => $cost_price,
- 'total' => $total,
- 'discounted_total' => $discounted_total,
- 'print_option' => $print_option_selected,
- 'stock_type' => $stock_type,
- 'item_type' => $item_type,
- 'hsn_code' => $item_info->hsn_code,
- 'tax_category_id' => $item_info->tax_category_id
- ]
- ];
-
- //add to existing array
- $items += $item;
- }
- else
- {
- $line = &$items[$updatekey];
- $line['quantity'] = $quantity;
- $line['total'] = $total;
- $line['discounted_total'] = $discounted_total;
- }
-
- $this->set_cart($items);
-
- return true;
- }
-
- /**
- * @param int $item_id
- * @param int $item_location
- * @return string
- */
- public function out_of_stock(int $item_id, int $item_location): string
- {
- //make sure item exists
- if($item_id != -1) //TODO: !== ?. Also Replace -1 with a constant
- {
- $item_info = $this->item->get_info_by_id_or_number($item_id);
-
- if($item_info->stock_type == HAS_STOCK) //TODO: === ?
- {
- $item_quantity = $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity;
- $quantity_added = $this->get_quantity_already_added($item_id, $item_location);
-
- if($item_quantity - $quantity_added < 0)
- {
- return lang('Sales.quantity_less_than_zero');
- }
- elseif($item_quantity - $quantity_added < $item_info->reorder_level)
- {
- return lang('Sales.quantity_less_than_reorder_level');
- }
- }
- }
-
- return '';
- }
-
- /**
- * @param int $item_id
- * @param int $item_location
- * @return string
- */
- public function get_quantity_already_added(int $item_id, int $item_location): string
- {
- $items = $this->get_cart();
- $quantity_already_added = '0.0';
- foreach($items as $item)
- {
- if($item['item_id'] == $item_id && $item['item_location'] == $item_location) //TODO: === ?
- {
- $quantity_already_added += $item['quantity']; //TODO: for precision we likely need to use bcadd() since we are using that everywhere else for quantity
- }
- }
-
- return $quantity_already_added;
- }
-
- /**
- * @param string $line_to_get
- * @return int
- */
- public function get_item_id(string $line_to_get): int
- {
- $items = $this->get_cart();
-
- foreach($items as $line => $item)
- {
- if($line == $line_to_get)
- {
- return $item['item_id'];
- }
- }
-
- return -1; //TODO: Replace -1 with constant
- }
-
- /* @param string $line
- * @param string $description
- * @param string $serialnumber
- * @param string $quantity
- * @param string $discount
- * @param string|null $discount_type
- * @param string|null $price
- * @param string|null $discounted_total
- * @return bool
- */
- public function edit_item(string $line, string $description, string $serialnumber, string $quantity, string $discount, ?string $discount_type, ?string $price, ?string $discounted_total = null): bool
- {
- $items = $this->get_cart();
- if(isset($items[$line]))
- {
- $line = &$items[$line];
- if($discounted_total != null && $discounted_total != $line['discounted_total'])
- {
- // Note when entered the "discounted_total" is expected to be entered without a discount
- $quantity = $this->get_quantity_sold($discounted_total, $price);
- }
- $line['description'] = $description;
- $line['serialnumber'] = $serialnumber;
- $line['quantity'] = $quantity;
- $line['discount'] = $discount;
-
- if($discount_type != null)
- {
- $line['discount_type'] = $discount_type;
- }
-
- $line['price'] = $price;
- $line['total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type']);
- $line['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type'], true);
- $this->set_cart($items);
- }
-
- return false; //TODO: This function will always return false.
- }
-
- /**
- * @param int $line
- * @return void
- */
- public function delete_item(int $line): void
- {
- $items = $this->get_cart();
- $item_type = $items[$line]['item_type'];
-
- if($item_type == ITEM_TEMP)
- {
- $item_id = $items[$line]['item_id'];
- $this->item->delete($item_id);
- }
-
- unset($items[$line]);
- $this->set_cart($items);
- }
-
- /**
- * @param string $receipt_sale_id
- * @return void
- */
- public function return_entire_sale(string $receipt_sale_id): void
- {
- //POS #
- $pieces = explode(' ', $receipt_sale_id);
- $sale_id = $pieces[1];
-
- $this->empty_cart();
- $this->remove_customer();
-
- foreach($this->sale->get_sale_items_ordered($sale_id)->getResult() as $row)
- {
- $this->add_item($row->item_id, $row->item_location, -$row->quantity_purchased, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, null, null, $row->item_unit_price, $row->description, $row->serialnumber, null, true);
- }
-
- $this->set_customer($this->sale->get_customer($sale_id)->person_id);
- }
-
- /**
- * @param string $external_item_kit_id
- * @param int $item_location
- * @param float $discount
- * @param string $discount_type
- * @param bool $kit_price_option
- * @param bool $kit_print_option
- * @param string $stock_warning
- * @return bool
- */
- public function add_item_kit(string $external_item_kit_id, int $item_location, float $discount, string $discount_type, bool $kit_price_option, bool $kit_print_option, ?string &$stock_warning): bool
- {
- //KIT #
- $pieces = explode(' ', $external_item_kit_id);
- $item_kit_id = (count($pieces) > 1) ? $pieces[1] : $external_item_kit_id;
- $result = true;
- $applied_discount = $discount;
-
- foreach($this->item_kit_items->get_info($item_kit_id) as $item_kit_item)
- {
- $result &= $this->add_item($item_kit_item['item_id'], $item_location, $item_kit_item['quantity'], $discount, $discount_type, PRICE_MODE_KIT, $kit_price_option, $kit_print_option);
-
- if($stock_warning == null)
- {
- $stock_warning = $this->out_of_stock($item_kit_item['item_id'], $item_location);
- }
- }
-
- return $result;
- }
-
- /**
- * @param int $sale_id
- * @return void
- */
- public function copy_entire_sale(int $sale_id): void
- {
- $this->empty_cart();
- $this->remove_customer();
-
- foreach($this->sale->get_sale_items_ordered($sale_id)->getResult() as $row)
- {
- $this->add_item($row->item_id, $row->item_location, $row->quantity_purchased, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, null, null, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, true, $row->print_option);
- }
-
- $this->session->set('cash_mode', CASH_MODE_FALSE);
-
- // Establish cash_mode for this sale by inspecting the payments
- if($this->session->get('cash_rounding'))
- {
- $cash_types_only = true;
- foreach($this->sale->get_sale_payments($sale_id)->getResult() as $row)
- {
- if($row->payment_type != lang('Sales.cash') && $row->payment_type != lang('Sales.cash_adjustment'))
- {
- $cash_types_only = false;
- }
-
- }
- //TODO: Consider converting to ternary notation.
- //$cash_types_only
- // ? $this->session->set('cash_mode', CASH_MODE_TRUE)
- // : $this->session->set('cash_mode', CASH_MODE_FALSE);
- if($cash_types_only)
- {
- $this->session->set('cash_mode', CASH_MODE_TRUE);
- }
- else
- {
- $this->session->set('cash_mode', CASH_MODE_FALSE);
- }
- }
-
- // Now load payments
- foreach($this->sale->get_sale_payments($sale_id)->getResult() as $row)
- {
- $this->add_payment($row->payment_type, $row->payment_amount, $row->cash_adjustment);
- }
-
- $this->set_customer($this->sale->get_customer($sale_id)->person_id);
- $this->set_employee($this->sale->get_employee($sale_id)->person_id);
- $this->set_quote_number($this->sale->get_quote_number($sale_id));
- $this->set_work_order_number($this->sale->get_work_order_number($sale_id));
- $this->set_sale_type($this->sale->get_sale_type($sale_id));
- $this->set_comment($this->sale->get_comment($sale_id));
- $this->set_dinner_table($this->sale->get_dinner_table($sale_id));
- $this->session->set('sale_id', $sale_id);
- }
-
- /**
- * @return int
- */
- public function get_sale_id(): int
- {
- return $this->session->get('sale_id');
- }
-
- /**
- * @return void
- */
- public function clear_all(): void
- {
- $this->session->set('sale_id', -1); //TODO: Replace -1 with constant
- $this->clear_mode();
- $this->clear_table();
- $this->empty_cart();
- $this->clear_comment();
- $this->clear_email_receipt();
- $this->clear_invoice_number();
- $this->clear_quote_number();
- $this->clear_work_order_number();
- $this->clear_sale_type();
- $this->clear_giftcard_remainder();
- $this->empty_payments();
- $this->remove_customer();
- $this->clear_cash_flags();
- }
-
- /**
- * @return void
- */
- public function clear_cash_flags(): void
- {
- $this->session->remove('cash_rounding');
- $this->session->remove('cash_mode');
- $this->session->remove('payment_type');
- }
-
- /**
- * Determines if cash rounding should be a consideration for this site
- * It also set resets the cash mode to disabled which will then be re-evaluated when
- * retrieving payments.
- */
- public function reset_cash_rounding(): int
- {
- $cash_rounding_code = $this->config['cash_rounding_code'];
-
- if(cash_decimals() < totals_decimals() || $cash_rounding_code == Rounding_mode::HALF_FIVE) //TODO: convert to ternary notation.
- {
- $cash_rounding = 1; //TODO: Replace with constant
- }
- else
- {
- $cash_rounding = 0; //TODO: Replace with constant
- }
- $this->session->set('cash_rounding', $cash_rounding);
- $this->session->set('cash_mode', CASH_MODE_FALSE);
-
- return $cash_rounding;
- }
-
- /**
- * @return bool
- */
- public function is_customer_taxable(): bool //TODO: This function is never called in the code
- {
- $customer_id = $this->get_customer();
- $customer = $this->customer->get_info($customer_id);
-
- //Do not charge sales tax if we have a customer that is not taxable
- return $customer->taxable or $customer_id == -1; //TODO: Replace with constant. Also, I'm not sure we should be using the or operator instead of || here. $a || $b guarantees that the result of those two get returned. It's possible that return $a or $b could return just the result of $a since `or` has a lower precedence.
- }
-
- /**
- * @param string $discount
- * @param int $discount_type
- * @return void
- */
- public function apply_customer_discount(string $discount, int $discount_type): void
- {
- // Get all items in the cart so far...
- $items = $this->get_cart();
-
- foreach($items as &$item)
- {
- $quantity = $item['quantity'];
- $price = $item['price'];
-
- // set a new discount only if the current one is 0
- if($item['discount'] == 0.0) //TODO: === ?
- {
- $item['discount'] = $discount;
- $item['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type);
- $item['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, true);
- }
- }
-
- $this->set_cart($items);
- }
-
- /**
- * @return string
- */
- public function get_discount(): string
- {
- $discount = '0.0';
- foreach($this->get_cart() as $item)
- {
- if($item['discount'] > '0.0')
- {
- $item_discount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']);
- $discount = bcadd($discount, $item_discount);
- }
- }
-
- return $discount;
- }
-
- /**
- * @param bool $include_discount
- * @param bool $exclude_tax
- * @return string
- */
- public function get_subtotal(bool $include_discount = false, bool $exclude_tax = false): string
- {
- return $this->calculate_subtotal($include_discount, $exclude_tax);
- }
-
- /**
- * @param int $item_id
- * @param string $quantity
- * @param string $price
- * @param string $discount
- * @param int $discount_type
- * @param bool $include_discount
- * @return string
- */
- public function get_item_total_tax_exclusive(int $item_id, string $quantity, string $price, string $discount, int $discount_type, bool $include_discount = false): string
- {
- $tax_info = $this->item_taxes->get_info($item_id);
- $item_total = $this->get_item_total($quantity, $price, $discount, $discount_type, $include_discount);
-
- // only additive tax here
- foreach($tax_info as $tax)
- {
- $tax_percentage = $tax['percent'];
- $item_total = bcsub($item_total, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage));
- }
-
- return $item_total;
- }
-
- //TODO: This function doesn't seem to be called anywhere in the code.
-
- /**
- * @param int $item_id
- * @param string $discounted_extended_amount
- * @param string $quantity
- * @param string $price
- * @param string $discount
- * @param int $discount_type
- * @return string
- */
- public function get_extended_total_tax_exclusive(int $item_id, string $discounted_extended_amount, string $quantity, string $price, string $discount = '0.0', int $discount_type = 0): string
- {
- $tax_info = $this->item_taxes->get_info($item_id);
-
- // only additive tax here
- foreach($tax_info as $tax)
- {
- $tax_percentage = $tax['percent'];
- $discounted_extended_amount = bcsub($discounted_extended_amount, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage));
- }
-
- return $discounted_extended_amount;
- }
-
- /**
- * @param string $quantity
- * @param string $price
- * @param string $discount
- * @param int $discount_type
- * @param bool $include_discount
- * @return string
- */
- public function get_item_total(string $quantity, string $price, string $discount, int $discount_type, bool $include_discount = false): string
- {
- $total = bcmul($quantity, $price);
- if($include_discount)
- {
- $discount_amount = $this->get_item_discount($quantity, $price, $discount, $discount_type);
-
- return bcsub($total, $discount_amount);
- }
-
- return $total;
- }
-
- /**
- * Derive the quantity sold based on the new total entered, returning the quanitity rounded to the
- * appropriate decimal positions.
- * @param string $total
- * @param string $price
- * @return string
- */
- public function get_quantity_sold(string $total, string $price): string
- {
- return bcdiv($total, $price, quantity_decimals());
- }
-
- /**
- * @param string $quantity
- * @param string $price
- * @param string $discount_amount
- * @return string
- */
- public function get_extended_amount(string $quantity, string $price, string $discount_amount = '0.0'): string
- {
- $extended_amount = bcmul($quantity, $price);
-
- return bcsub($extended_amount, $discount_amount);
- }
-
- /**
- * @param string $quantity
- * @param string $price
- * @param string $discount
- * @param int $discount_type
- * @return string
- */
- public function get_item_discount(string $quantity, string $price, string $discount, int $discount_type): string
- {
- $total = bcmul($quantity, $price);
- if($discount_type == PERCENT) //TODO: === ?. Also, ternary notation
- {
- $discount = bcmul($total, bcdiv($discount, '100'));
- }
- else
- {
- $discount = bcmul($quantity, $discount);
- }
-
- return (string)round((float)$discount, totals_decimals(), PHP_ROUND_HALF_UP); //TODO: is this safe with monetary amounts?
- }
-
- /**
- * @param string $quantity
- * @param string $price
- * @param string $discount
- * @param int $discount_type
- * @param string $tax_percentage
- * @return string
- */
- public function get_item_tax(string $quantity, string $price, string $discount, int $discount_type, string $tax_percentage): string
- {
- $item_total = $this->get_item_total($quantity, $price, $discount, $discount_type, true);
-
- if($this->config['tax_included'])
- {
- $tax_fraction = bcdiv(bcadd('100', $tax_percentage), '100');
- $price_tax_excl = bcdiv($item_total, $tax_fraction);
-
- return bcsub($item_total, $price_tax_excl);
- }
-
- $tax_fraction = bcdiv($tax_percentage, '100');
-
- return bcmul($item_total, $tax_fraction);
- }
-
- /**
- * @param bool $include_discount
- * @param bool $exclude_tax
- * @return string
- */
- public function calculate_subtotal(bool $include_discount = false, bool $exclude_tax = false): string
- {
- $subtotal = '0.0';
- foreach($this->get_cart() as $item)
- {
- if($exclude_tax && $this->config['tax_included'])
- {
- $subtotal = bcadd($subtotal, $this->get_item_total_tax_exclusive($item['item_id'], $item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount));
- }
- else
- {
- $subtotal = bcadd($subtotal, $this->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount));
- }
- }
-
- return $subtotal;
- }
-
- /**
- * Calculates the total sales amount with the default option to include cash rounding
- * @param bool $include_cash_rounding
- * @return string
- */
- public function get_total(bool $include_cash_rounding = true): string
- {
- $total = $this->calculate_subtotal(true);
-
- $cash_mode = $this->session->get('cash_mode');
-
- if(!$this->config['tax_included'])
- {
- $cart = $this->get_cart();
- $tax_lib = new Tax_lib();
-
- foreach($tax_lib->get_taxes($cart)[0] as $tax)
- {
- $total = bcadd($total, $tax['sale_tax_amount']);
- }
- }
-
- if($include_cash_rounding && $cash_mode)
- {
- $total = $this->check_for_cash_rounding($total);
- }
-
- return $total;
- }
-
- /**
- * @param int|null $current_dinner_table_id
- * @return array
- */
- public function get_empty_tables(?int $current_dinner_table_id): array
- {
- return $this->dinner_table->get_empty_tables($current_dinner_table_id);
- }
-
- /**
- * @param string $total
- * @return string
- */
- public function check_for_cash_rounding(string $total): string
- {
- $cash_decimals = cash_decimals();
- $cash_rounding_code = $this->config['cash_rounding_code'];
-
- return Rounding_mode::round_number($cash_rounding_code, (float)$total, $cash_decimals);
- }
+ private Attribute $attribute;
+ private Customer $customer;
+ private Dinner_table $dinner_table;
+ private Item $item;
+ private Item_kit_items $item_kit_items;
+ private Item_quantity $item_quantity;
+ private Item_taxes $item_taxes;
+ private Sale $sale;
+ private Stock_location $stock_location;
+ private Session $session;
+ private array $config;
+
+ public function __construct()
+ {
+ $this->session = session();
+
+ $this->attribute = model(Attribute::class);
+ $this->customer = model(Customer::class);
+ $this->dinner_table = model(Dinner_table::class);
+ $this->item = model(Item::class);
+ $this->item_kit_items = model(Item_kit_items::class);
+ $this->item_quantity = model(Item_quantity::class);
+ $this->item_taxes = model(Item_taxes::class);
+ $this->sale = model(Sale::class);
+ $this->stock_location = model(Stock_location::class);
+ $this->config = config(OSPOS::class)->settings;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_line_sequence_options(): array
+ {
+ return [
+ '0' => lang('Sales.entry'),
+ '1' => lang('Sales.group_by_type'),
+ '2' => lang('Sales.group_by_category')
+ ];
+ }
+
+ /**
+ * @return array
+ */
+ public function get_register_mode_options(): array
+ {
+ $register_modes = [];
+
+ if(!$this->config['invoice_enable'])
+ {
+ $register_modes['sale'] = lang('Sales.sale');
+ }
+ else
+ {
+ $register_modes['sale'] = lang('Sales.receipt');
+ $register_modes['sale_quote'] = lang('Sales.quote');
+
+ if($this->config['work_order_enable'])
+ {
+ $register_modes['sale_work_order'] = lang('Sales.work_order');
+ }
+
+ $register_modes['sale_invoice'] = lang('Sales.invoice');
+ }
+
+ $register_modes['return'] = lang('Sales.return');
+
+ return $register_modes;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_invoice_type_options(): array
+ {
+ $invoice_types = [];
+ $invoice_types['invoice'] = lang('Sales.invoice_type_invoice');
+ $invoice_types['tax_invoice'] = lang('Sales.invoice_type_tax_invoice');
+ $invoice_types['custom_invoice'] = lang('Sales.invoice_type_custom_invoice');
+ $invoice_types['custom_tax_invoice'] = lang('Sales.invoice_type_custom_tax_invoice');
+ return $invoice_types;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_cart(): array
+ {
+ if(!$this->session->get('sales_cart'))
+ {
+ $this->set_cart ([]);
+ }
+
+ return $this->session->get('sales_cart');
+ }
+
+ /**
+ * @param array $cart
+ * @return array
+ */
+ public function sort_and_filter_cart(array $cart): array
+ {
+ if(empty($cart))
+ {
+ return $cart;
+ }
+
+ $filtered_cart = [];
+
+ foreach($cart as $k => $v) //TODO: We should not be using single-letter variable names for readability. Several of these foreach loops should be refactored.
+ {
+ if($v['print_option'] == PRINT_YES)
+ {
+ if($v['price'] == 0.0)
+ {
+ $v['discount'] = 0.0;
+ }
+ $filtered_cart[] = $v;
+ }
+ }
+
+ //TODO: This set of if/elseif/else needs to be converted to a switch statement
+ // Entry sequence (this will render kits in the expected sequence)
+ if($this->config['line_sequence'] == '0')
+ {
+ $sort = [];
+ foreach($filtered_cart as $k => $v)
+ {
+ $sort['line'][$k] = $v['line'];
+ }
+ array_multisort($sort['line'], SORT_ASC, $filtered_cart);
+ }
+ // Group by Stock Type (nonstock first - type 1, stock next - type 0)
+ elseif($this->config['line_sequence'] == '1') //TODO: Need to change these to constants
+ {
+ $sort = [];
+ foreach($filtered_cart as $k => $v)
+ {
+ $sort['stock_type'][$k] = $v['stock_type'];
+ $sort['description'][$k] = $v['description'];
+ $sort['name'][$k] = $v['name'];
+ }
+ array_multisort($sort['stock_type'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC, $filtered_cart);
+ }
+ // Group by Item Category
+ elseif($this->config['line_sequence'] == '2') //TODO: Need to change these to constants
+ {
+ $sort = [];
+ foreach($filtered_cart as $k => $v)
+ {
+ $sort['category'][$k] = $v['stock_type'];
+ $sort['description'][$k] = $v['description'];
+ $sort['name'][$k] = $v['name'];
+ }
+ array_multisort($sort['category'], SORT_DESC, $sort['description'], SORT_ASC, $sort['name'], SORT_ASC, $filtered_cart);
+ }
+ // Group by entry sequence in descending sequence (the Standard)
+ else
+ {
+ $sort = [];
+ foreach($filtered_cart as $k => $v)
+ {
+ $sort['line'][$k] = $v['line'];
+ }
+ array_multisort($sort['line'], SORT_ASC, $filtered_cart);
+ }
+
+ return $filtered_cart;
+ }
+
+ /**
+ * @param array $cart_data
+ * @return void
+ */
+ public function set_cart(array $cart_data): void
+ {
+ $this->session->set('sales_cart', $cart_data);
+ }
+
+ /**
+ * @return void
+ */
+ public function empty_cart(): void
+ {
+ $this->session->remove('sales_cart');
+ }
+
+ /**
+ * @return void
+ */
+ public function remove_temp_items(): void
+ {
+ // Loop through the cart items and delete temporary items specific to this sale
+ $cart = $this->get_cart();
+ foreach($cart as $line=>$item)
+ {
+ if($item['item_type'] == ITEM_TEMP) //TODO: === ?
+ {
+ $this->item->delete($item['item_id']);
+ }
+ }
+ }
+
+ /**
+ * @return string
+ */
+ public function get_comment(): string
+ {
+ // avoid returning a null that results in a 0 in the comment if nothing is set/available
+ $comment = $this->session->get('sales_comment');
+
+ return empty($comment) ? '' : $comment;
+ }
+
+ /**
+ * @param string $comment
+ * @return void
+ */
+ public function set_comment(string $comment): void
+ {
+ $this->session->set('sales_comment', $comment);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_comment(): void
+ {
+ $this->session->remove('sales_comment');
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_invoice_number(): ?string
+ {
+ return $this->session->get('sales_invoice_number');
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_quote_number(): ?string
+ {
+ return $this->session->get('sales_quote_number');
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_work_order_number(): ?string
+ {
+ return $this->session->get('sales_work_order_number');
+ }
+
+ /**
+ * @return int|null
+ */
+ public function get_sale_type(): ?int
+ {
+ return $this->session->get('sale_type', 0);
+ }
+
+ /**
+ * @param int $invoice_number
+ * @param bool $keep_custom
+ * @return void
+ */
+ public function set_invoice_number(int $invoice_number, bool $keep_custom = false): void
+ {
+ $current_invoice_number = $this->session->get('sales_invoice_number');
+
+ if(!$keep_custom || empty($current_invoice_number))
+ {
+ $this->session->set('sales_invoice_number', $invoice_number);
+ }
+ }
+
+ /**
+ * @param string|null $quote_number
+ * @param bool $keep_custom
+ * @return void
+ */
+ public function set_quote_number(?string $quote_number, bool $keep_custom = false): void
+ {
+ $current_quote_number = $this->session->get('sales_quote_number');
+
+ if(!$keep_custom || empty($current_quote_number))
+ {
+ $this->session->set('sales_quote_number', $quote_number);
+ }
+ }
+
+ /**
+ * @param string|null $work_order_number
+ * @param bool $keep_custom
+ * @return void
+ */
+ public function set_work_order_number(?string $work_order_number, bool $keep_custom = false): void
+ {
+ $current_work_order_number = $this->session->get('sales_work_order_number');
+
+ if(!$keep_custom || empty($current_work_order_number))
+ {
+ $this->session->set('sales_work_order_number', $work_order_number);
+ }
+ }
+
+ /**
+ * @param int $sale_type
+ * @param bool $keep_custom
+ * @return void
+ */
+ public function set_sale_type(int $sale_type, bool $keep_custom = false): void
+ {
+ $current_sale_type = $this->session->get('sale_type');
+
+ if(!$keep_custom || empty($current_sale_type))
+ {
+ $this->session->set('sale_type', $sale_type);
+ }
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_invoice_number(): void
+ {
+ $this->session->remove('sales_invoice_number');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_quote_number(): void
+ {
+ $this->session->remove('sales_quote_number');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_work_order_number(): void
+ {
+ $this->session->remove('sales_work_order_number');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_sale_type(): void
+ {
+ $this->session->remove('sale_type');
+ }
+
+ /**
+ * @param int $suspended_id
+ * @return void
+ */
+ public function set_suspended_id(int $suspended_id): void
+ {
+ $this->session->set('suspended_id', $suspended_id);
+ }
+
+ /**
+ * @return int
+ */
+ public function get_suspended_id(): int
+ {
+ return $this->session->get('suspended_id');
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_invoice_mode(): bool
+ {
+ return ($this->session->get('sales_mode') == 'sale_invoice' && $this->config['invoice_enable']);
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_sale_by_receipt_mode(): bool //TODO: This function is not called anywhere in the code.
+ {
+ return ($this->session->get('sales_mode') == 'sale'); //TODO: === ?
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_quote_mode(): bool
+ {
+ return ($this->session->get('sales_mode') == 'sale_quote'); //TODO: === ?
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_return_mode(): bool
+ {
+ return ($this->session->get('sales_mode') == 'return'); //TODO: === ?
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_work_order_mode(): bool
+ {
+ return ($this->session->get('sales_mode') == 'sale_work_order'); //TODO: === ?
+ }
+
+ /**
+ * @param string $price_work_orders
+ * @return void
+ */
+ public function set_price_work_orders(string $price_work_orders): void
+ {
+ $this->session->set('sales_price_work_orders', $price_work_orders);
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_price_work_orders(): bool
+ {
+ return ($this->session->get('sales_price_work_orders') == 'true' //TODO: === ?
+ || $this->session->get('sales_price_work_orders') == '1'); //TODO: === ?
+ }
+
+ /**
+ * @param bool $print_after_sale
+ * @return void
+ */
+ public function set_print_after_sale(bool $print_after_sale): void
+ {
+ $this->session->set('sales_print_after_sale', $print_after_sale);
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_print_after_sale(): bool
+ {//TODO: this needs to be converted to a switch statement
+ if($this->config['print_receipt_check_behaviour'] == 'always') //TODO: 'behaviour' is the british spelling, but the rest of the code is in American English. Not a big deal, but noticed. Also ===
+ {
+ return true;
+ }
+ elseif($this->config['print_receipt_check_behaviour'] == 'never') //TODO: === ?
+ {
+ return false;
+ }
+ else // remember last setting, session based though
+ {
+ return ($this->session->get('sales_print_after_sale') == 'true' //TODO: === ?
+ || $this->session->get('sales_print_after_sale') == '1'); //TODO: === ?
+ }
+ }
+
+ /**
+ * @param string $email_receipt
+ * @return void
+ */
+ public function set_email_receipt(string $email_receipt): void
+ {
+ $this->session->set('sales_email_receipt', $email_receipt);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_email_receipt(): void
+ {
+ $this->session->remove('sales_email_receipt');
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_email_receipt(): bool
+ {//TODO: this needs to be converted to a switch statement
+ if($this->config['email_receipt_check_behaviour'] == 'always') //TODO: 'behaviour' is the british spelling, but the rest of the code is in American English. Not a big deal, but noticed. Also ===
+ {
+ return true;
+ }
+ elseif($this->config['email_receipt_check_behaviour'] == 'never') //TODO: === ?
+ {
+ return false;
+ }
+ else // remember last setting, session based though
+ {
+ return ($this->session->get('sales_email_receipt') == 'true' //TODO: === ?
+ || $this->session->get('sales_email_receipt') == '1'); //TODO: === ?
+ }
+ }
+
+ /**
+ * Multiple Payments
+ */
+ public function get_payments(): array
+ {
+ if(!$this->session->get('sales_payments'))
+ {
+ $this->set_payments ([]);
+ }
+
+ return $this->session->get('sales_payments');
+ }
+
+ /**
+ * Multiple Payments
+ */
+ public function set_payments(array $payments_data): void
+ {
+ $this->session->set('sales_payments', $payments_data);
+ }
+
+ /**
+ * Adds a new payment to the payments array or updates an existing one.
+ * It will also disable cash_mode if a non-qualifying payment type is added.
+ * @param string $payment_id
+ * @param string $payment_amount
+ * @param int $cash_adjustment
+ */
+ public function add_payment(string $payment_id, string $payment_amount, int $cash_adjustment = CASH_ADJUSTMENT_FALSE): void
+ {
+ $payments = $this->get_payments();
+ if(isset($payments[$payment_id]))
+ {
+ //payment_method already exists, add to payment_amount
+ $payments[$payment_id]['payment_amount'] = bcadd($payments[$payment_id]['payment_amount'], $payment_amount);
+ }
+ else
+ {
+ //add to existing array
+ $payment = [
+ $payment_id => [
+ 'payment_type' => $payment_id,
+ 'payment_amount' => $payment_amount,
+ 'cash_refund' => 0,
+ 'cash_adjustment' => $cash_adjustment
+ ]
+ ];
+
+ $payments += $payment;
+ }
+
+ if($this->session->get('cash_mode'))
+ {
+ if($this->session->get('cash_rounding') && $payment_id != lang('Sales.cash') && $payment_id != lang('Sales.cash_adjustment'))
+ {
+ $this->session->set('cash_mode', CASH_MODE_FALSE);
+ }
+ }
+
+ $this->set_payments($payments);
+ }
+
+ /**
+ * Multiple Payments
+ */
+ public function edit_payment(string $payment_id, float $payment_amount): bool
+ {
+ $payments = $this->get_payments();
+ if(isset($payments[$payment_id]))
+ {
+ $payments[$payment_id]['payment_type'] = $payment_id;
+ $payments[$payment_id]['payment_amount'] = $payment_amount;
+ $this->set_payments($payments);
+
+ return true;
+ }
+
+ return false;
+ }
+
+ /**
+ * Delete the selected payment from the payment array and if cash rounding is enabled
+ * and the payment type is one of the cash types then automatically delete the other
+ * @param string $payment_id
+ */
+ public function delete_payment(string $payment_id): void
+ {
+ $payments = $this->get_payments();
+ $decoded_payment_id = urldecode($payment_id);
+
+ unset($payments[$decoded_payment_id]);
+
+ $cash_rounding = $this->reset_cash_rounding();
+
+ if($cash_rounding)
+ {
+ if($decoded_payment_id == lang('Sales.cash')) //TODO: === ?
+ {
+ unset($payments[lang('Sales.cash_adjustment')]);
+ }
+
+ if($decoded_payment_id == lang('Sales.cash_adjustment')) //TODO: === ?
+ {
+ unset($payments[lang('Sales.cash')]);
+ }
+ }
+ $this->set_payments($payments);
+ }
+
+ /**
+ * Multiple Payments
+ */
+ public function empty_payments(): void //TODO: function verbs are very inconsistent in these libraries.
+ {
+ $this->session->remove('sales_payments');
+ }
+
+ /**
+ * Retrieve the total payments made, excluding any cash adjustments
+ * and establish if cash_mode is in play
+ */
+ public function get_payments_total(): string
+ {
+ $subtotal = '0.0';
+ $cash_mode_eligible = CASH_MODE_TRUE;
+
+ foreach($this->get_payments() as $payments)
+ {
+ if(!$payments['cash_adjustment'])
+ {
+ $subtotal = bcadd($payments['payment_amount'], $subtotal);
+ }
+ if(lang('Sales.cash') != $payments['payment_type'] && lang('Sales.cash_adjustment') != $payments['payment_type'])
+ {
+ $cash_mode_eligible = CASH_MODE_FALSE;
+ }
+ }
+
+ if($cash_mode_eligible && $this->session->get('cash_rounding')) //TODO: $cache_mode_eligible will always evaluate to true
+ {
+ $this->session->set('cash_mode', CASH_MODE_TRUE);
+ }
+
+ return $subtotal;
+ }
+
+ /**
+ * Returns 'subtotal', 'total', 'cash_total', 'payment_total', 'amount_due', 'cash_amount_due', 'paid_in_full'
+ * 'subtotal', 'discounted_subtotal', 'tax_exclusive_subtotal', 'item_count', 'total_units', 'cash_adjustment_amount'
+ */
+ public function get_totals(array $taxes): array
+ {
+ $totals = [];
+
+ $prediscount_subtotal = '0.0';
+ $subtotal = '0.0';
+ $total = '0.0';
+ $total_discount = '0.0';
+ $item_count = 0;
+ $total_units = 0.0;
+
+ foreach($this->get_cart() as $item)
+ {
+ if($item['stock_type'] == HAS_STOCK)
+ {
+ $item_count++;
+ $total_units += $item['quantity'];
+ }
+ $discount_amount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']);
+ $total_discount = bcadd($total_discount, $discount_amount);
+
+ $extended_amount = $this->get_extended_amount($item['quantity'], $item['price']);
+ $extended_discounted_amount = $this->get_extended_amount($item['quantity'], $item['price'], $discount_amount);
+ $prediscount_subtotal = bcadd($prediscount_subtotal, $extended_amount);
+ $total = bcadd($total, $extended_discounted_amount);
+
+ $subtotal = bcadd($subtotal, $extended_discounted_amount);
+ }
+
+ $totals['prediscount_subtotal'] = $prediscount_subtotal;
+ $totals['total_discount'] = $total_discount;
+ $sales_tax = '0';
+
+ foreach($taxes as $tax)
+ {
+ if($tax['tax_type'] === Tax_lib::TAX_TYPE_EXCLUDED)
+ {
+ $total = bcadd($total, $tax['sale_tax_amount']);
+ $sales_tax = bcadd($sales_tax, $tax['sale_tax_amount']);
+ }
+ else
+ {
+ $subtotal = bcsub($subtotal, $tax['sale_tax_amount']);
+ }
+ }
+
+ $totals['subtotal'] = $subtotal;
+ $totals['total'] = $total;
+ $totals['tax_total'] = $sales_tax;
+
+ $payment_total = $this->get_payments_total();
+ $totals['payment_total'] = $payment_total;
+ $cash_rounding = $this->session->get('cash_rounding');
+ $cash_mode = $this->session->get('cash_mode');
+
+ if($cash_rounding)
+ {
+ $cash_total = $this->check_for_cash_rounding($total);
+ $totals['cash_total'] = $cash_total;
+ }
+ else
+ {
+ $cash_total = $total;
+ $totals['cash_total'] = $cash_total;
+ }
+
+ $amount_due = bcsub($total, $payment_total);
+ $totals['amount_due'] = $amount_due;
+
+ $cash_amount_due = bcsub($cash_total, $payment_total);
+ $totals['cash_amount_due'] = $cash_amount_due;
+
+ if($cash_mode) //TODO: Convert to ternary notation
+ {
+ $current_due = $cash_amount_due;
+ }
+ else
+ {
+ $current_due = $amount_due;
+ }
+
+ // 0 decimal -> 1 / 2 = 0.5, 1 decimals -> 0.1 / 2 = 0.05, 2 decimals -> 0.01 / 2 = 0.005
+ $threshold = bcpow('10', (string)-totals_decimals()) / 2;
+
+ if($this->get_mode() == 'return') //TODO: Convert to ternary notation.
+ {
+ $totals['payments_cover_total'] = $current_due > -$threshold;
+ }
+ else
+ {
+ $totals['payments_cover_total'] = $current_due < $threshold;
+ }
+
+ $totals['item_count'] = $item_count;
+ $totals['total_units'] = $total_units;
+ $totals['cash_adjustment_amount'] = 0.0;
+
+ if($totals['payments_cover_total'])
+ {
+ $totals['cash_adjustment_amount'] = round($cash_total - $totals['total'], totals_decimals(), PHP_ROUND_HALF_UP);
+ }
+
+ $cash_mode = $this->session->get('cash_mode'); //TODO: This variable is never used.
+
+ return $totals;
+ }
+
+ /**
+ * Multiple Payments
+ */
+ public function get_amount_due(): string
+ {
+ // Payment totals need to be identified first so that we know whether or not there is a non-cash payment involved
+ $payment_total = $this->get_payments_total();
+ $sales_total = $this->get_total();
+ $amount_due = bcsub($sales_total, $payment_total);
+ $precision = totals_decimals();
+ $rounded_due = bccomp((string)round((float)$amount_due, $precision, PHP_ROUND_HALF_UP), '0', $precision); //TODO: Is round() currency safe?
+
+ // take care of rounding error introduced by round tripping payment amount to the browser
+ return $rounded_due == 0 ? '0' : $amount_due; //TODO: ===
+ }
+
+ /**
+ * @return int
+ */
+ public function get_customer(): int
+ {
+ if(!$this->session->get('sales_customer'))
+ {
+ $this->set_customer(-1); //TODO: Replace -1 with a constant
+ }
+
+ return $this->session->get('sales_customer');
+ }
+
+ /**
+ * @param int $customer_id
+ * @return void
+ */
+ public function set_customer(int $customer_id): void
+ {
+ $this->session->set('sales_customer', $customer_id);
+ }
+
+ /**
+ * @return void
+ */
+ public function remove_customer(): void
+ {
+ $this->session->remove('sales_customer');
+ }
+
+ /**
+ * @return int
+ */
+ public function get_employee(): int
+ {
+ if(!$this->session->get('sales_employee'))
+ {
+ $this->set_employee(-1); //TODO: Replace -1 with a constant
+ }
+
+ return $this->session->get('sales_employee');
+ }
+
+ /**
+ * @param int $employee_id
+ * @return void
+ */
+ public function set_employee(int $employee_id): void
+ {
+ $this->session->set('sales_employee', $employee_id);
+ }
+
+ /**
+ * @return void
+ */
+ public function remove_employee(): void
+ {
+ $this->session->remove('sales_employee');
+ }
+
+ /**
+ * @return string
+ */
+ public function get_mode(): string
+ {
+ if(!$this->session->get('sales_mode'))
+ {
+ $this->set_mode('sale');
+ }
+ return $this->session->get('sales_mode');
+ }
+
+ /**
+ * @param string $mode
+ * @return void
+ */
+ public function set_mode(string $mode): void
+ {
+ $this->session->set('sales_mode', $mode);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_mode(): void
+ {
+ $this->session->remove('sales_mode');
+ }
+
+ /**
+ * @return int|null
+ */
+ public function get_dinner_table(): ?int
+ {
+ if(!$this->session->get('dinner_table'))
+ {
+ if($this->config['dinner_table_enable'])
+ {
+ $this->set_dinner_table(1); //TODO: Replace 1 with constant
+ }
+ }
+
+ return $this->session->get('dinner_table');
+ }
+
+ /**
+ * @param int|null $dinner_table
+ * @return void
+ */
+ public function set_dinner_table(?int $dinner_table): void
+ {
+ $this->session->set('dinner_table', $dinner_table);
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_table(): void
+ {
+ $this->session->remove('dinner_table');
+ }
+
+ /**
+ * @return int
+ */
+ public function get_sale_location(): int
+ {
+ if(!$this->session->get('sales_location'))
+ {
+ $this->set_sale_location($this->stock_location->get_default_location_id('sales'));
+ }
+
+ return $this->session->get('sales_location');
+ }
+
+ /**
+ * @param int $location
+ * @return void
+ */
+ public function set_sale_location(int $location): void
+ {
+ $this->session->set('sales_location', $location);
+ }
+
+ /**
+ * @param string $payment_type
+ * @return void
+ */
+ public function set_payment_type(string $payment_type): void
+ {
+ $this->session->set('payment_type', $payment_type);
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_payment_type(): ?string
+ {
+ return $this->session->get('payment_type');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_sale_location(): void
+ {
+ $this->session->remove('sales_location');
+ }
+
+ /**
+ * @param string $value
+ * @return void
+ */
+ public function set_giftcard_remainder(string $value): void
+ {
+ $this->session->set('sales_giftcard_remainder', $value);
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_giftcard_remainder(): ?string
+ {
+ return $this->session->get('sales_giftcard_remainder');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_giftcard_remainder(): void
+ {
+ $this->session->remove('sales_giftcard_remainder');
+ }
+
+ /**
+ * @param string $value
+ * @return void
+ */
+ public function set_rewards_remainder(string $value): void
+ {
+ $this->session->set('sales_rewards_remainder', $value);
+ }
+
+ /**
+ * @return string|null
+ */
+ public function get_rewards_remainder(): ?string
+ {
+ return $this->session->get('sales_rewards_remainder');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_rewards_remainder(): void
+ {
+ $this->session->remove('sales_rewards_remainder');
+ }
+
+ //TODO: this function needs to be reworked... way too many parameters. Also, optional parameters must go after mandatory parameters.
+
+ /**
+ * @param int $item_id
+ * @param int $item_location
+ * @param string $quantity
+ * @param string $discount
+ * @param int $discount_type
+ * @param int $price_mode
+ * @param int|null $kit_price_option
+ * @param int|null $kit_print_option
+ * @param string|null $price_override
+ * @param string|null $description
+ * @param string|null $serialnumber
+ * @param int|null $sale_id
+ * @param bool $include_deleted
+ * @param bool|null $print_option
+ * @param bool|null $line
+ * @return bool
+ */
+ public function add_item(int &$item_id, int $item_location, string $quantity = '1', string &$discount = '0.0', int $discount_type = 0, int $price_mode = PRICE_MODE_STANDARD, int $kit_price_option = null, int $kit_print_option = null, string $price_override = null, string $description = null, string $serialnumber = null, int $sale_id = null, bool $include_deleted = false, bool $print_option = null, bool $line = null): bool
+ {
+ $item_info = $this->item->get_info_by_id_or_number($item_id, $include_deleted);
+
+ //make sure item exists
+ if(empty($item_info))
+ {
+ $item_id = NEW_ENTRY;
+ return false;
+ }
+
+ $applied_discount = $discount;
+ $item_id = $item_info->item_id;
+ $item_type = $item_info->item_type;
+ $stock_type = $item_info->stock_type;
+
+ $price = $item_info->unit_price;
+ $cost_price = $item_info->cost_price;
+ if($price_override != null)
+ {
+ $price = $price_override;
+ }
+
+ if($price_mode == PRICE_MODE_KIT)
+ {
+ if(!($kit_price_option == PRICE_OPTION_ALL
+ || $kit_price_option == PRICE_OPTION_KIT && $item_type == ITEM_KIT
+ || $kit_price_option == PRICE_OPTION_KIT_STOCK && $stock_type == HAS_STOCK)) //TODO: === ?
+ {
+ $price = '0.00';
+ $applied_discount = '0.00';
+ }
+
+ // If price is zero do not include a discount regardless of type
+ if($price == '0.00') //TODO: === ?
+ {
+ $applied_discount = '0.00';
+ }
+
+ // If fixed discount then apply no more than the item price
+ if($discount_type == FIXED) //TODO: === ?
+ {
+ if($applied_discount > $price)
+ {
+ $applied_discount = $price;
+ $discount -= $applied_discount;
+ }
+ else
+ {
+ $discount = 0;
+ }
+ }
+ }
+
+ // Serialization and Description
+
+ //Get all items in the cart so far...
+ $items = $this->get_cart();
+
+ //We need to loop through all items in the cart.
+ //If the item is already there, get it's key($updatekey).
+ //We also need to get the next key that we are going to use in case we need to add the
+ //item to the cart. Since items can be deleted, we can't use a count. we use the highest key + 1.
+
+ $maxkey = 0; //Highest key so far
+ $itemalreadyinsale = false; //We did not find the item yet. //TODO: variable naming here does not match the convention
+ $insertkey = 0; //Key to use for new entry. //TODO: $insertkey is never used
+ $updatekey = 0; //Key to use to update(quantity)
+
+ foreach($items as $item)
+ {
+ //We primed the loop so maxkey is 0 the first time.
+ //Also, we have stored the key in the element itself so we can compare.
+
+ if($maxkey <= $item['line']) //TODO: variable naming here does not match the convention
+ {
+ $maxkey = $item['line'];
+ }
+
+ if($item['item_id'] == $item_id && $item['item_location'] == $item_location) //TODO: === ?
+ {
+ $itemalreadyinsale = true;
+ $updatekey = $item['line'];
+ if(!$item_info->is_serialized)
+ {
+ $quantity = bcadd($quantity, $items[$updatekey]['quantity']);
+ }
+ }
+ }
+
+ $insertkey = $maxkey + 1;//TODO Does not follow naming conventions.
+ //array/cart records are identified by $insertkey and item_id is just another field.
+
+ if($price_mode == PRICE_MODE_KIT) //TODO: === ?
+ {
+ if($kit_print_option == PRINT_ALL) //TODO: === ?
+ {
+ $print_option_selected = PRINT_YES;
+ }
+ elseif($kit_print_option == PRINT_KIT && $item_type == ITEM_KIT) //TODO: === ?
+ {
+ $print_option_selected = PRINT_YES;
+ }
+ elseif($kit_print_option == PRINT_PRICED && $price > 0) //TODO: === ?
+ {
+ $print_option_selected = PRINT_YES;
+ }
+ else
+ {
+ $print_option_selected = PRINT_NO;
+ }
+ }
+ else
+ { //TODO: Convert this to ternary notation
+ if($print_option != null) //TODO: === ?
+ {
+ $print_option_selected = $print_option;
+ }
+ else
+ {
+ $print_option_selected = PRINT_YES;
+ }
+ }
+
+ $total = $this->get_item_total($quantity, $price, $applied_discount, $discount_type);
+ $discounted_total = $this->get_item_total($quantity, $price, $applied_discount, $discount_type, true);
+
+ if($this->config['multi_pack_enabled'])
+ {
+ $item_info->name .= NAME_SEPARATOR . $item_info->pack_name;
+ }
+
+ $attribute_links = $this->attribute->get_link_values($item_id, 'sale_id', $sale_id, Attribute::SHOW_IN_SALES)->getRowObject();
+
+ //Item already exists and is not serialized, add to quantity
+ if(!$itemalreadyinsale || $item_info->is_serialized)
+ {
+ $item = [
+ $insertkey => [
+ 'item_id' => $item_id,
+ 'item_location' => $item_location,
+ 'stock_name' => $this->stock_location->get_location_name($item_location),
+ 'line' => $insertkey,
+ 'name' => $item_info->name,
+ 'item_number' => $item_info->item_number,
+ 'attribute_values' => $attribute_links->attribute_values,
+ 'attribute_dtvalues' => $attribute_links->attribute_dtvalues,
+ 'description' => $description != null ? $description : $item_info->description,
+ 'serialnumber' => $serialnumber != null ? $serialnumber : '',
+ 'allow_alt_description' => $item_info->allow_alt_description,
+ 'is_serialized' => $item_info->is_serialized,
+ 'quantity' => $quantity,
+ 'discount' => $applied_discount,
+ 'discount_type' => $discount_type,
+ 'in_stock' => $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity,
+ 'price' => $price,
+ 'cost_price' => $cost_price,
+ 'total' => $total,
+ 'discounted_total' => $discounted_total,
+ 'print_option' => $print_option_selected,
+ 'stock_type' => $stock_type,
+ 'item_type' => $item_type,
+ 'hsn_code' => $item_info->hsn_code,
+ 'tax_category_id' => $item_info->tax_category_id
+ ]
+ ];
+
+ //add to existing array
+ $items += $item;
+ }
+ else
+ {
+ $line = &$items[$updatekey];
+ $line['quantity'] = $quantity;
+ $line['total'] = $total;
+ $line['discounted_total'] = $discounted_total;
+ }
+
+ $this->set_cart($items);
+
+ return true;
+ }
+
+ /**
+ * @param int $item_id
+ * @param int $item_location
+ * @return string
+ */
+ public function out_of_stock(int $item_id, int $item_location): string
+ {
+ //make sure item exists
+ if($item_id != -1) //TODO: !== ?. Also Replace -1 with a constant
+ {
+ $item_info = $this->item->get_info_by_id_or_number($item_id);
+
+ if($item_info->stock_type == HAS_STOCK) //TODO: === ?
+ {
+ $item_quantity = $this->item_quantity->get_item_quantity($item_id, $item_location)->quantity;
+ $quantity_added = $this->get_quantity_already_added($item_id, $item_location);
+
+ if($item_quantity - $quantity_added < 0)
+ {
+ return lang('Sales.quantity_less_than_zero');
+ }
+ elseif($item_quantity - $quantity_added < $item_info->reorder_level)
+ {
+ return lang('Sales.quantity_less_than_reorder_level');
+ }
+ }
+ }
+
+ return '';
+ }
+
+ /**
+ * @param int $item_id
+ * @param int $item_location
+ * @return string
+ */
+ public function get_quantity_already_added(int $item_id, int $item_location): string
+ {
+ $items = $this->get_cart();
+ $quantity_already_added = '0.0';
+ foreach($items as $item)
+ {
+ if($item['item_id'] == $item_id && $item['item_location'] == $item_location) //TODO: === ?
+ {
+ $quantity_already_added += $item['quantity']; //TODO: for precision we likely need to use bcadd() since we are using that everywhere else for quantity
+ }
+ }
+
+ return $quantity_already_added;
+ }
+
+ /**
+ * @param string $line_to_get
+ * @return int
+ */
+ public function get_item_id(string $line_to_get): int
+ {
+ $items = $this->get_cart();
+
+ foreach($items as $line => $item)
+ {
+ if($line == $line_to_get)
+ {
+ return $item['item_id'];
+ }
+ }
+
+ return -1; //TODO: Replace -1 with constant
+ }
+
+ /* @param string $line
+ * @param string $description
+ * @param string $serialnumber
+ * @param string $quantity
+ * @param string $discount
+ * @param string|null $discount_type
+ * @param string|null $price
+ * @param string|null $discounted_total
+ * @return bool
+ */
+ public function edit_item(string $line, string $description, string $serialnumber, string $quantity, string $discount, ?string $discount_type, ?string $price, ?string $discounted_total = null): bool
+ {
+ $items = $this->get_cart();
+ if(isset($items[$line]))
+ {
+ $line = &$items[$line];
+ if($discounted_total != null && $discounted_total != $line['discounted_total'])
+ {
+ // Note when entered the "discounted_total" is expected to be entered without a discount
+ $quantity = $this->get_quantity_sold($discounted_total, $price);
+ }
+ $line['description'] = $description;
+ $line['serialnumber'] = $serialnumber;
+ $line['quantity'] = $quantity;
+ $line['discount'] = $discount;
+
+ if($discount_type != null)
+ {
+ $line['discount_type'] = $discount_type;
+ }
+
+ $line['price'] = $price;
+ $line['total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type']);
+ $line['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $line['discount_type'], true);
+ $this->set_cart($items);
+ }
+
+ return false; //TODO: This function will always return false.
+ }
+
+ /**
+ * @param int $line
+ * @return void
+ */
+ public function delete_item(int $line): void
+ {
+ $items = $this->get_cart();
+ $item_type = $items[$line]['item_type'];
+
+ if($item_type == ITEM_TEMP)
+ {
+ $item_id = $items[$line]['item_id'];
+ $this->item->delete($item_id);
+ }
+
+ unset($items[$line]);
+ $this->set_cart($items);
+ }
+
+ /**
+ * @param string $receipt_sale_id
+ * @return void
+ */
+ public function return_entire_sale(string $receipt_sale_id): void
+ {
+ //POS #
+ $pieces = explode(' ', $receipt_sale_id);
+ $sale_id = $pieces[1];
+
+ $this->empty_cart();
+ $this->remove_customer();
+
+ foreach($this->sale->get_sale_items_ordered($sale_id)->getResult() as $row)
+ {
+ $this->add_item($row->item_id, $row->item_location, -$row->quantity_purchased, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, null, null, $row->item_unit_price, $row->description, $row->serialnumber, null, true);
+ }
+
+ $this->set_customer($this->sale->get_customer($sale_id)->person_id);
+ }
+
+ /**
+ * @param string $external_item_kit_id
+ * @param int $item_location
+ * @param float $discount
+ * @param string $discount_type
+ * @param bool $kit_price_option
+ * @param bool $kit_print_option
+ * @param string $stock_warning
+ * @return bool
+ */
+ public function add_item_kit(string $external_item_kit_id, int $item_location, float $discount, string $discount_type, bool $kit_price_option, bool $kit_print_option, ?string &$stock_warning): bool
+ {
+ //KIT #
+ $pieces = explode(' ', $external_item_kit_id);
+ $item_kit_id = (count($pieces) > 1) ? $pieces[1] : $external_item_kit_id;
+ $result = true;
+ $applied_discount = $discount;
+
+ foreach($this->item_kit_items->get_info($item_kit_id) as $item_kit_item)
+ {
+ $result &= $this->add_item($item_kit_item['item_id'], $item_location, $item_kit_item['quantity'], $discount, $discount_type, PRICE_MODE_KIT, $kit_price_option, $kit_print_option);
+
+ if($stock_warning == null)
+ {
+ $stock_warning = $this->out_of_stock($item_kit_item['item_id'], $item_location);
+ }
+ }
+
+ return $result;
+ }
+
+ /**
+ * @param int $sale_id
+ * @return void
+ */
+ public function copy_entire_sale(int $sale_id): void
+ {
+ $this->empty_cart();
+ $this->remove_customer();
+
+ foreach($this->sale->get_sale_items_ordered($sale_id)->getResult() as $row)
+ {
+ $this->add_item($row->item_id, $row->item_location, $row->quantity_purchased, $row->discount, $row->discount_type, PRICE_MODE_STANDARD, null, null, $row->item_unit_price, $row->description, $row->serialnumber, $sale_id, true, $row->print_option);
+ }
+
+ $this->session->set('cash_mode', CASH_MODE_FALSE);
+
+ // Establish cash_mode for this sale by inspecting the payments
+ if($this->session->get('cash_rounding'))
+ {
+ $cash_types_only = true;
+ foreach($this->sale->get_sale_payments($sale_id)->getResult() as $row)
+ {
+ if($row->payment_type != lang('Sales.cash') && $row->payment_type != lang('Sales.cash_adjustment'))
+ {
+ $cash_types_only = false;
+ }
+
+ }
+ //TODO: Consider converting to ternary notation.
+ //$cash_types_only
+ // ? $this->session->set('cash_mode', CASH_MODE_TRUE)
+ // : $this->session->set('cash_mode', CASH_MODE_FALSE);
+ if($cash_types_only)
+ {
+ $this->session->set('cash_mode', CASH_MODE_TRUE);
+ }
+ else
+ {
+ $this->session->set('cash_mode', CASH_MODE_FALSE);
+ }
+ }
+
+ // Now load payments
+ foreach($this->sale->get_sale_payments($sale_id)->getResult() as $row)
+ {
+ $this->add_payment($row->payment_type, $row->payment_amount, $row->cash_adjustment);
+ }
+
+ $this->set_customer($this->sale->get_customer($sale_id)->person_id);
+ $this->set_employee($this->sale->get_employee($sale_id)->person_id);
+ $this->set_quote_number($this->sale->get_quote_number($sale_id));
+ $this->set_work_order_number($this->sale->get_work_order_number($sale_id));
+ $this->set_sale_type($this->sale->get_sale_type($sale_id));
+ $this->set_comment($this->sale->get_comment($sale_id));
+ $this->set_dinner_table($this->sale->get_dinner_table($sale_id));
+ $this->session->set('sale_id', $sale_id);
+ }
+
+ /**
+ * @return int
+ */
+ public function get_sale_id(): int
+ {
+ return $this->session->get('sale_id');
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_all(): void
+ {
+ $this->session->set('sale_id', -1); //TODO: Replace -1 with constant
+ $this->clear_mode();
+ $this->clear_table();
+ $this->empty_cart();
+ $this->clear_comment();
+ $this->clear_email_receipt();
+ $this->clear_invoice_number();
+ $this->clear_quote_number();
+ $this->clear_work_order_number();
+ $this->clear_sale_type();
+ $this->clear_giftcard_remainder();
+ $this->empty_payments();
+ $this->remove_customer();
+ $this->clear_cash_flags();
+ }
+
+ /**
+ * @return void
+ */
+ public function clear_cash_flags(): void
+ {
+ $this->session->remove('cash_rounding');
+ $this->session->remove('cash_mode');
+ $this->session->remove('payment_type');
+ }
+
+ /**
+ * Determines if cash rounding should be a consideration for this site
+ * It also set resets the cash mode to disabled which will then be re-evaluated when
+ * retrieving payments.
+ */
+ public function reset_cash_rounding(): int
+ {
+ $cash_rounding_code = $this->config['cash_rounding_code'];
+
+ if(cash_decimals() < totals_decimals() || $cash_rounding_code == Rounding_mode::HALF_FIVE) //TODO: convert to ternary notation.
+ {
+ $cash_rounding = 1; //TODO: Replace with constant
+ }
+ else
+ {
+ $cash_rounding = 0; //TODO: Replace with constant
+ }
+ $this->session->set('cash_rounding', $cash_rounding);
+ $this->session->set('cash_mode', CASH_MODE_FALSE);
+
+ return $cash_rounding;
+ }
+
+ /**
+ * @return bool
+ */
+ public function is_customer_taxable(): bool //TODO: This function is never called in the code
+ {
+ $customer_id = $this->get_customer();
+ $customer = $this->customer->get_info($customer_id);
+
+ //Do not charge sales tax if we have a customer that is not taxable
+ return $customer->taxable or $customer_id == -1; //TODO: Replace with constant. Also, I'm not sure we should be using the or operator instead of || here. $a || $b guarantees that the result of those two get returned. It's possible that return $a or $b could return just the result of $a since `or` has a lower precedence.
+ }
+
+ /**
+ * @param string $discount
+ * @param int $discount_type
+ * @return void
+ */
+ public function apply_customer_discount(string $discount, int $discount_type): void
+ {
+ // Get all items in the cart so far...
+ $items = $this->get_cart();
+
+ foreach($items as &$item)
+ {
+ $quantity = $item['quantity'];
+ $price = $item['price'];
+
+ // set a new discount only if the current one is 0
+ if($item['discount'] == 0.0) //TODO: === ?
+ {
+ $item['discount'] = $discount;
+ $item['total'] = $this->get_item_total($quantity, $price, $discount, $discount_type);
+ $item['discounted_total'] = $this->get_item_total($quantity, $price, $discount, $discount_type, true);
+ }
+ }
+
+ $this->set_cart($items);
+ }
+
+ /**
+ * @return string
+ */
+ public function get_discount(): string
+ {
+ $discount = '0.0';
+ foreach($this->get_cart() as $item)
+ {
+ if($item['discount'] > '0.0')
+ {
+ $item_discount = $this->get_item_discount($item['quantity'], $item['price'], $item['discount'], $item['discount_type']);
+ $discount = bcadd($discount, $item_discount);
+ }
+ }
+
+ return $discount;
+ }
+
+ /**
+ * @param bool $include_discount
+ * @param bool $exclude_tax
+ * @return string
+ */
+ public function get_subtotal(bool $include_discount = false, bool $exclude_tax = false): string
+ {
+ return $this->calculate_subtotal($include_discount, $exclude_tax);
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount
+ * @param int $discount_type
+ * @param bool $include_discount
+ * @return string
+ */
+ public function get_item_total_tax_exclusive(int $item_id, string $quantity, string $price, string $discount, int $discount_type, bool $include_discount = false): string
+ {
+ $tax_info = $this->item_taxes->get_info($item_id);
+ $item_total = $this->get_item_total($quantity, $price, $discount, $discount_type, $include_discount);
+
+ // only additive tax here
+ foreach($tax_info as $tax)
+ {
+ $tax_percentage = $tax['percent'];
+ $item_total = bcsub($item_total, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage));
+ }
+
+ return $item_total;
+ }
+
+ //TODO: This function doesn't seem to be called anywhere in the code.
+
+ /**
+ * @param int $item_id
+ * @param string $discounted_extended_amount
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount
+ * @param int $discount_type
+ * @return string
+ */
+ public function get_extended_total_tax_exclusive(int $item_id, string $discounted_extended_amount, string $quantity, string $price, string $discount = '0.0', int $discount_type = 0): string
+ {
+ $tax_info = $this->item_taxes->get_info($item_id);
+
+ // only additive tax here
+ foreach($tax_info as $tax)
+ {
+ $tax_percentage = $tax['percent'];
+ $discounted_extended_amount = bcsub($discounted_extended_amount, $this->get_item_tax($quantity, $price, $discount, $discount_type, $tax_percentage));
+ }
+
+ return $discounted_extended_amount;
+ }
+
+ /**
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount
+ * @param int $discount_type
+ * @param bool $include_discount
+ * @return string
+ */
+ public function get_item_total(string $quantity, string $price, string $discount, int $discount_type, bool $include_discount = false): string
+ {
+ $total = bcmul($quantity, $price);
+ if($include_discount)
+ {
+ $discount_amount = $this->get_item_discount($quantity, $price, $discount, $discount_type);
+
+ return bcsub($total, $discount_amount);
+ }
+
+ return $total;
+ }
+
+ /**
+ * Derive the quantity sold based on the new total entered, returning the quanitity rounded to the
+ * appropriate decimal positions.
+ * @param string $total
+ * @param string $price
+ * @return string
+ */
+ public function get_quantity_sold(string $total, string $price): string
+ {
+ return bcdiv($total, $price, quantity_decimals());
+ }
+
+ /**
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount_amount
+ * @return string
+ */
+ public function get_extended_amount(string $quantity, string $price, string $discount_amount = '0.0'): string
+ {
+ $extended_amount = bcmul($quantity, $price);
+
+ return bcsub($extended_amount, $discount_amount);
+ }
+
+ /**
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount
+ * @param int $discount_type
+ * @return string
+ */
+ public function get_item_discount(string $quantity, string $price, string $discount, int $discount_type): string
+ {
+ $total = bcmul($quantity, $price);
+ if($discount_type == PERCENT) //TODO: === ?. Also, ternary notation
+ {
+ $discount = bcmul($total, bcdiv($discount, '100'));
+ }
+ else
+ {
+ $discount = bcmul($quantity, $discount);
+ }
+
+ return (string)round((float)$discount, totals_decimals(), PHP_ROUND_HALF_UP); //TODO: is this safe with monetary amounts?
+ }
+
+ /**
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount
+ * @param int $discount_type
+ * @param string $tax_percentage
+ * @return string
+ */
+ public function get_item_tax(string $quantity, string $price, string $discount, int $discount_type, string $tax_percentage): string
+ {
+ $item_total = $this->get_item_total($quantity, $price, $discount, $discount_type, true);
+
+ if($this->config['tax_included'])
+ {
+ $tax_fraction = bcdiv(bcadd('100', $tax_percentage), '100');
+ $price_tax_excl = bcdiv($item_total, $tax_fraction);
+
+ return bcsub($item_total, $price_tax_excl);
+ }
+
+ $tax_fraction = bcdiv($tax_percentage, '100');
+
+ return bcmul($item_total, $tax_fraction);
+ }
+
+ /**
+ * @param bool $include_discount
+ * @param bool $exclude_tax
+ * @return string
+ */
+ public function calculate_subtotal(bool $include_discount = false, bool $exclude_tax = false): string
+ {
+ $subtotal = '0.0';
+ foreach($this->get_cart() as $item)
+ {
+ if($exclude_tax && $this->config['tax_included'])
+ {
+ $subtotal = bcadd($subtotal, $this->get_item_total_tax_exclusive($item['item_id'], $item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount));
+ }
+ else
+ {
+ $subtotal = bcadd($subtotal, $this->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $include_discount));
+ }
+ }
+
+ return $subtotal;
+ }
+
+ /**
+ * Calculates the total sales amount with the default option to include cash rounding
+ * @param bool $include_cash_rounding
+ * @return string
+ */
+ public function get_total(bool $include_cash_rounding = true): string
+ {
+ $total = $this->calculate_subtotal(true);
+
+ $cash_mode = $this->session->get('cash_mode');
+
+ if(!$this->config['tax_included'])
+ {
+ $cart = $this->get_cart();
+ $tax_lib = new Tax_lib();
+
+ foreach($tax_lib->get_taxes($cart)[0] as $tax)
+ {
+ $total = bcadd($total, $tax['sale_tax_amount']);
+ }
+ }
+
+ if($include_cash_rounding && $cash_mode)
+ {
+ $total = $this->check_for_cash_rounding($total);
+ }
+
+ return $total;
+ }
+
+ /**
+ * @param int|null $current_dinner_table_id
+ * @return array
+ */
+ public function get_empty_tables(?int $current_dinner_table_id): array
+ {
+ return $this->dinner_table->get_empty_tables($current_dinner_table_id);
+ }
+
+ /**
+ * @param string $total
+ * @return string
+ */
+ public function check_for_cash_rounding(string $total): string
+ {
+ $cash_decimals = cash_decimals();
+ $cash_rounding_code = $this->config['cash_rounding_code'];
+
+ return Rounding_mode::round_number($cash_rounding_code, (float)$total, $cash_decimals);
+ }
}
diff --git a/app/Libraries/Sms_lib.php b/app/Libraries/Sms_lib.php
index abc5be69e..90cc327ce 100644
--- a/app/Libraries/Sms_lib.php
+++ b/app/Libraries/Sms_lib.php
@@ -16,67 +16,67 @@ use Config\Services;
class Sms_lib
{
- /**
- * SMS sending function
- * Example of use: $response = sendSMS('4477777777', 'My test message');
- */
- public function sendSMS(int $phone, string $message): bool
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * SMS sending function
+ * Example of use: $response = sendSMS('4477777777', 'My test message');
+ */
+ public function sendSMS(int $phone, string $message): bool
+ {
+ $config = config(OSPOS::class)->settings;
- $encrypter = Services::encrypter();
+ $encrypter = Services::encrypter();
- $password = $config['msg_pwd'];
- if(!empty($password))
- {
- $password = $encrypter->decrypt($password);
- }
+ $password = $config['msg_pwd'];
+ if(!empty($password))
+ {
+ $password = $encrypter->decrypt($password);
+ }
- $username = $config['msg_uid'];
- $originator = $config['msg_src'];
+ $username = $config['msg_uid'];
+ $originator = $config['msg_src'];
- $response = false;
+ $response = false;
- // if any of the parameters is empty return with a false
- if(empty($username) || empty($password) || empty($phone) || empty($message) || empty($originator)) //TODO: This if/else needs to be flipped. and shortened. No else needed in the code example below.
- //$parameters = [$username, $password, $phone, $message, $originator];
- //if(count(array_filter($parameters)) === 5)
- //{
- // $response = true;
- // $message = rawurlencode($message);
- //}
- {
- //echo $username . ' ' . $password . ' ' . $phone . ' ' . $message . ' ' . $originator;
- }
- else
- {
- $response = true;
+ // if any of the parameters is empty return with a false
+ if(empty($username) || empty($password) || empty($phone) || empty($message) || empty($originator)) //TODO: This if/else needs to be flipped. and shortened. No else needed in the code example below.
+ //$parameters = [$username, $password, $phone, $message, $originator];
+ //if(count(array_filter($parameters)) === 5)
+ //{
+ // $response = true;
+ // $message = rawurlencode($message);
+ //}
+ {
+ //echo $username . ' ' . $password . ' ' . $phone . ' ' . $message . ' ' . $originator;
+ }
+ else
+ {
+ $response = true;
//TODO: These comments should be moved to the documentation. As is, they tend to get out of date.
- // make sure passed string is url encoded
- $message = rawurlencode($message); //TODO: $message needs to be passed by reference if you want this line to actually do anything
+ // make sure passed string is url encoded
+ $message = rawurlencode($message); //TODO: $message needs to be passed by reference if you want this line to actually do anything
- // add call to send a message via 3rd party API here
- // Some examples
+ // add call to send a message via 3rd party API here
+ // Some examples
- /*
- $url = "http://xxx.xxx.xxx.xxx/send_sms?username=$username&password=$password&src=$originator&dst=$phone&msg=$message&dr=1";
+ /*
+ $url = "http://xxx.xxx.xxx.xxx/send_sms?username=$username&password=$password&src=$originator&dst=$phone&msg=$message&dr=1";
- $c = curl_init();
- curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
- curl_setopt($c, CURLOPT_URL, $url);
- $response = curl_exec($c);
- curl_close($c);
- */
+ $c = curl_init();
+ curl_setopt($c, CURLOPT_RETURNTRANSFER, 1);
+ curl_setopt($c, CURLOPT_URL, $url);
+ $response = curl_exec($c);
+ curl_close($c);
+ */
- // This is a textmarketer.co.uk API call, see: http://wiki.textmarketer.co.uk/display/DevDoc/Text+Marketer+Developer+Documentation+-+Wiki+Home
- /*
- $url = 'https://api.textmarketer.co.uk/gateway/'."?username=$username&password=$password&option=xml";
- $url .= "&to=$phone&message=".urlencode($message).'&orig='.urlencode($originator);
- $fp = fopen($url, 'r');
- $response = fread($fp, 1024);
- */
- }
+ // This is a textmarketer.co.uk API call, see: http://wiki.textmarketer.co.uk/display/DevDoc/Text+Marketer+Developer+Documentation+-+Wiki+Home
+ /*
+ $url = 'https://api.textmarketer.co.uk/gateway/'."?username=$username&password=$password&option=xml";
+ $url .= "&to=$phone&message=".urlencode($message).'&orig='.urlencode($originator);
+ $fp = fopen($url, 'r');
+ $response = fread($fp, 1024);
+ */
+ }
- return $response;
- }
+ return $response;
+ }
}
diff --git a/app/Libraries/Tax_lib.php b/app/Libraries/Tax_lib.php
index ccd934818..996b901d6 100644
--- a/app/Libraries/Tax_lib.php
+++ b/app/Libraries/Tax_lib.php
@@ -20,517 +20,517 @@ use Config\OSPOS;
*/
class Tax_lib
{
- public const TAX_TYPE_EXCLUDED = '1'; //TODO: These constants need to be moved to constants.php
- public const TAX_TYPE_INCLUDED = '0';
- private Sale_lib $sale_lib;
- private Customer $customer;
- private Item_taxes $item_taxes;
- private Sale $sale;
- private Tax $tax;
- private Tax_category $tax_category;
- private Tax_code $tax_code;
- private Tax_jurisdiction $tax_jurisdiction;
- private array $config;
-
- public function __construct()
- {
- $this->sale_lib = new Sale_lib();
-
- $this->customer = model(Customer::class);
- $this->item_taxes = model(Item_taxes::class);
- $this->sale = model(Sale::class);
- $this->tax = model(Tax::class);
- $this->tax_category = model(Tax_category::class);
- $this->tax_code = model(Tax_code::class);
- $this->tax_jurisdiction = model(Tax_jurisdiction::class);
- $this->config = config(OSPOS::class)->settings;
- }
-
- /**
- * @return array
- */
- public function get_tax_types(): array
- {
- return [
- Tax_lib::TAX_TYPE_EXCLUDED => lang('Taxes.tax_excluded'),
- Tax_lib::TAX_TYPE_INCLUDED => lang('Taxes.tax_included')
- ];
- }
-
- /**
- * Compute the tax basis and returns the tax amount
- */
- public function get_item_sales_tax(string $quantity, string $price, string $discount, int $discount_type, string $tax_percentage, int $rounding_code): string //TODO: It appears this function is never called in the code.
- {
- $decimals = tax_decimals();
-
- // The tax basis should be returned to the currency scale
- $tax_basis = $this->sale_lib->get_item_total($quantity, $price, $discount, $discount_type, true);
-
- return $this->get_tax_for_amount($tax_basis, $tax_percentage, $rounding_code, $decimals);
- }
-
- /**
- * Computes the item level sales tax amount for a given tax basis
- */
- public function get_tax_for_amount(string $tax_basis, string $tax_percentage, int $rounding_mode, int $decimals): string
- {
- $tax_amount = bcmul($tax_basis, bcdiv($tax_percentage, '100'));
-
- return rounding_mode::round_number($rounding_mode, $tax_amount, $decimals);
- }
-
- /**
- * Compute taxes for all items in the cart
- */
- public function get_taxes(array &$cart, int $sale_id = -1): array //TODO: Replace -1 with constant.
- {
- $register_mode = $this->sale_lib->get_mode();
- $tax_decimals = tax_decimals();
- $customer_id = $this->sale_lib->get_customer();
- $customer_info = $this->customer->get_info($customer_id);
- $taxes = [];
- $item_taxes = [];
-
- // Charge sales tax if customer is not selected (walk-in) or customer is flagged as taxable
- if($customer_id == -1 || $customer_info->taxable) //TODO: Replace -1 with constant.
- {
- foreach($cart as $line => $item)
- {
- $taxed = false;
-
- if(!$this->config['use_destination_based_tax'])
- {
- // Start of current Base System tax calculations
-
- if($sale_id == -1) //TODO: Replace -1 with constant. Also, replace with ternary notation.
- {
- $tax_info = $this->item_taxes->get_info($item['item_id']);
- }
- else
- {
- $tax_info = $this->sale->get_sales_item_taxes($sale_id, $item['item_id']);
- }
-
- $tax_group_sequence = 0;
- $cascade_level = 0; //TODO: This variable is set but never used.
- $cascade_basis_level = 0; //TODO: This variable is set but never used.
-
- foreach($tax_info as $tax)
- {
- // This computes tax for each line item and adds it to the tax type total
- $tax_basis = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], true);
- $tax_amount = '0.0';
-
- if($this->config['tax_included'])
- {
- $tax_type = Tax_lib::TAX_TYPE_INCLUDED;
- $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $tax['percent'], $tax_decimals, Rounding_mode::HALF_UP);
- }
- else
- {
- $tax_type = Tax_lib::TAX_TYPE_EXCLUDED;
- $tax_amount = $this->get_tax_for_amount($tax_basis, $tax['percent'], Rounding_mode::HALF_UP, $tax_decimals);
- }
-
- if($tax_amount <> 0)
- {
- $tax_group_sequence++;
- $this->update_taxes($taxes, $tax_type, $tax['name'], $tax['percent'], $tax_basis, $tax_amount, $tax_group_sequence, Rounding_mode::HALF_UP, -1, $tax['name']); //TODO: Replace -1 with constant.
- $tax_group_sequence += 1; //TODO: $tax_group_sequence++;
- $taxed = true;
- }
-
- $items_taxes_detail = [];
- $items_taxes_detail['item_id'] = $item['item_id'];
- $items_taxes_detail['line'] = $item['line'];
- $items_taxes_detail['name'] = $tax['name'];
- $items_taxes_detail['percent'] = $tax['percent'];
- $items_taxes_detail['tax_type'] = $tax_type;
- $items_taxes_detail['rounding_code'] = Rounding_mode::HALF_UP;
- $items_taxes_detail['cascade_sequence'] = 0;
- $items_taxes_detail['item_tax_amount'] = $tax_amount;
- $items_taxes_detail['sales_tax_code_id'] = null;
- $items_taxes_detail['jurisdiction_id'] = null;
- $items_taxes_detail['tax_category_id'] = null;
-
- $item_taxes[] = $items_taxes_detail;
- }
- }
- else
- {
- // Start of destination based tax calculations
- if($item['tax_category_id'] == null) //TODO: === ?
- {
- $item['tax_category_id'] = $this->config['default_tax_category'];
- }
-
- $taxed = $this->apply_destination_tax($item, $customer_info->city, $customer_info->state, $customer_info->sales_tax_code_id, $register_mode, 0, $taxes, $item_taxes, $item['line']);
- }
-
- if($taxed) //TODO: Convert to ternary notation
- {
- $cart[$line]['taxed_flag'] = lang('Sales.taxed_ind');
- }
- else
- {
- $cart[$line]['taxed_flag'] = lang('Sales.nontaxed_ind');
- }
- }
- $this->round_taxes($taxes);
- }
-
- $tax_details = [];
- $tax_details[0] = $taxes;
- $tax_details[1] = $item_taxes;
-
- return $tax_details;
- }
-
- /**
- * @param string $quantity
- * @param string $price
- * @param string $discount_percentage
- * @param int $discount_type
- * @param string $tax_percentage
- * @param $tax_decimal
- * @param $rounding_code
- * @return string
- */
- public function get_included_tax(string $quantity, string $price, string $discount_percentage, int $discount_type, string $tax_percentage, $tax_decimal, $rounding_code): string //TODO: $tax_decimal and $rounding_code are in the signature but never used in the function.
- {
- $item_total = $this->sale_lib->get_item_total($quantity, $price, $discount_percentage, $discount_type, true);
- $tax_fraction = bcdiv(bcadd('100', $tax_percentage), '100');
- $price_tax_excl = bcdiv($item_total, $tax_fraction);
- return bcsub($item_total, $price_tax_excl);
- }
-
- /**
- * Updates the sales_tax array which is later saved to the `sales_taxes` table and used for printing taxes on receipts and invoices
- */
- public function update_taxes(array &$taxes, string $tax_type, string $tax_group, string $tax_rate, string $tax_basis, string $item_tax_amount, int $tax_group_sequence, int $rounding_code, int $sale_id, string $name = '', int $tax_code_id = null, int $jurisdiction_id = null, int $tax_category_id = null): void
- {
- $tax_group_index = $this->clean('X' . (float)$tax_rate . '% ' . $tax_group); //TODO: Not sure we should be casting to a float here. The clean() function takes a string, so it just gets converted back to a string and there's risk of inaccuracies in the value displayed.
-
- if(!array_key_exists($tax_group_index, $taxes))
- {
- $insertkey = $tax_group_index; //TODO: this variable does not follow naming conventions.
-
- $tax = [
- $insertkey => [
- 'sale_id' => $sale_id,
- 'tax_type' => $tax_type,
- 'tax_group' => $tax_group,
- 'sale_tax_basis' => $tax_basis,
- 'sale_tax_amount' => $item_tax_amount,
- 'print_sequence' => $tax_group_sequence,
- 'name' => $name,
- 'tax_rate' => $tax_rate,
- 'sales_tax_code_id' => $tax_code_id,
- 'jurisdiction_id' => $jurisdiction_id,
- 'tax_category_id' => $tax_category_id,
- 'rounding_code' => $rounding_code
- ]
- ];
-
- //add to existing array
- $taxes += $tax;
- }
- else
- {
- // Important ... the sales amounts are accumulated for the group at the maximum configurable scale value of 4
- // but the scale will in reality be the scale specified by the tax_decimal configuration value used for sales_items_taxes
- $taxes[$tax_group_index]['sale_tax_basis'] = bcadd($taxes[$tax_group_index]['sale_tax_basis'], $tax_basis, 4);
- $taxes[$tax_group_index]['sale_tax_amount'] = bcadd($taxes[$tax_group_index]['sale_tax_amount'], $item_tax_amount, 4);
- }
- }
-
- /**
- * If invoice taxing (as opposed to invoice_item_taxing) rules apply then recalculate the sales tax after tax group totals are final
- * This is currently used ONLY for the original sales tax migration.
- */
- public function apply_invoice_taxing(array &$taxes): void
- {
- if(!empty($taxes))
- {
- $sort = [];
- foreach($taxes as $k => $v)
- {
- $sort['print_sequence'][$k] = $v['print_sequence'];
- }
- array_multisort($sort['print_sequence'], SORT_ASC, $taxes);
- }
-
- $decimals = totals_decimals();
-
- foreach($taxes as $row_number => $tax)
- {
- $taxes[$row_number]['sale_tax_amount'] = $this->get_tax_for_amount($tax['sale_tax_basis'], $tax['tax_rate'], $tax['rounding_code'], $decimals);
- }
- }
-
- /**
- * Apply rounding rules to the accumulated sales tax amounts
- */
- public function round_taxes(array &$taxes): void
- {
- if(!empty($taxes))
- {
- $sort = [];
- foreach($taxes as $k => $v)
- {
- $sort['print_sequence'][$k] = $v['print_sequence'];
- }
- array_multisort($sort['print_sequence'], SORT_ASC, $taxes);
- }
-
- // If tax included then round decimal to tax decimals, otherwise round it to currency_decimals
- if($this->config['tax_included']) //TODO: Convert to ternary notation
- {
- $decimals = tax_decimals();
- }
- else
- {
- $decimals = totals_decimals();
- }
-
- foreach($taxes as $row_number => $sales_tax)
- {
- $tax_amount = $sales_tax['sale_tax_amount'];
- $rounding_code = $sales_tax['rounding_code'];
- $rounded_tax_amount = $tax_amount;
-
- if($rounding_code == Rounding_mode::HALF_UP) //TODO: this block needs to be converted to a switch statement
- {
- $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP);
- }
- elseif($rounding_code == Rounding_mode::HALF_DOWN)
- {
- $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_DOWN);
- }
- elseif($rounding_code == Rounding_mode::HALF_EVEN)
- {
- $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_EVEN);
- }
- elseif($rounding_code == Rounding_mode::HALF_ODD)
- {
- $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP);
- }
- elseif($rounding_code == Rounding_mode::ROUND_UP)
- {
- $fig = (int)str_pad('1', $decimals, '0');
- $rounded_tax_amount = ceil($tax_amount * $fig) / $fig;
- }
- elseif($rounding_code == Rounding_mode::ROUND_DOWN)
- {
- $fig = (int)str_pad('1', $decimals, '0');
- $rounded_tax_amount = floor($tax_amount * $fig) / $fig;
- }
- elseif($rounding_code == Rounding_mode::HALF_FIVE)
- {
- $rounded_tax_amount = round($tax_amount / 5) * 5;
- }
-
- $taxes[$row_number]['sale_tax_amount'] = $rounded_tax_amount;
- }
- }
-
- /**
- * Determine the applicable tax code and then determine the tax amount to be applied.
- * If a tax amount was identified then accumulate into the sales_taxes array
- */
- public function apply_destination_tax(array &$item, string $city, string $state, int $sales_tax_code_id, string $register_mode, int $sale_id, array &$taxes, array &$item_taxes, int $line): bool
- {
- $taxed = false;
-
- $tax_code_id = $this->get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code_id);
-
- // If tax code cannot be determined or the price is zero then skip this item
- if($tax_code_id != -1 && $item['price'] != 0) //TODO: Replace -1 with constant. Also === ?
- {
- $tax_decimals = tax_decimals();
-
- $tax_definition = $this->tax->get_taxes($tax_code_id, $item['tax_category_id']);
-
- // The tax basis should be returned to the currency scale
- $tax_basis = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], true);
-
- $row = 0; //TODO: This variable is set but never used.
-
- $last_cascade_sequence = 0;
- $cascade_tax_amount = '0.0';
-
- foreach($tax_definition as $tax)
- {
- $cascade_sequence = $tax['cascade_sequence'];
- if($cascade_sequence != $last_cascade_sequence)
- {
- $last_cascade_sequence = $cascade_sequence;
- $tax_basis = bcadd($tax_basis, $cascade_tax_amount);
- }
-
- $tax_rate = $tax['tax_rate'];
- $rounding_code = $tax['tax_rounding_code'];
-
- // This computes tax for each line item and adds it to the tax type total
- $tax_type = $tax['tax_type'];
-
- if($tax_type == Tax_lib::TAX_TYPE_INCLUDED)
- {
- $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $tax_rate, $tax_decimals, $rounding_code);
- }
- else
- {
- $tax_amount = $this->get_tax_for_amount($tax_basis, $tax_rate, $rounding_code, $tax_decimals);
- $cascade_tax_amount = bcadd($cascade_tax_amount,$tax_amount);
- }
-
- if($tax_amount != 0)
- {
- $taxed = true;
- $this->update_taxes($taxes, $tax_type, $tax['tax_group'], $tax_rate, $tax_basis, $tax_amount, $tax['tax_group_sequence'], $rounding_code, $sale_id, $tax['tax_group'], $tax_code_id, $tax['rate_jurisdiction_id'], $item['tax_category_id']);
- }
-
- $item_taxes_detail = [];
- $item_taxes_detail['line'] = $line;
- $item_taxes_detail['item_id'] = $item['item_id'];
- $item_taxes_detail['name'] = $tax['tax_group'];
- $item_taxes_detail['percent'] = $tax['tax_rate'];
- $item_taxes_detail['tax_type'] = $tax_type;
- $item_taxes_detail['rounding_code'] = $rounding_code;
- $item_taxes_detail['cascade_sequence'] = $cascade_sequence;
- $item_taxes_detail['item_tax_amount'] = $tax_amount;
- $item_taxes_detail['sales_tax_code_id'] = $tax_code_id;
- $item_taxes_detail['jurisdiction_id'] = $tax['rate_jurisdiction_id'];
- $item_taxes_detail['tax_category_id'] = $tax['rate_tax_category_id'];
- $item_taxes_detail['tax_group_sequence'] = $tax['tax_group_sequence'];
-
- $item_taxes[] = $item_taxes_detail;
- }
- }
-
- return $taxed;
- }
-
- /**
- * @param string $register_mode
- * @param string $city
- * @param string $state
- * @param int $sales_tax_code_id
- * @return int
- */
- public function get_applicable_tax_code(string $register_mode, string $city, string $state, int $sales_tax_code_id): int
- {
- if($register_mode == 'sale')
- {
- $sales_tax_code_id = $this->config['default_tax_code']; // overrides customer assigned code
- }
- else
- {
- if($sales_tax_code_id == null || $sales_tax_code_id == 0)
- {
- $sales_tax_code_id = $this->tax_code->get_sales_tax_code($city, $state);
-
- if($sales_tax_code_id == null || $sales_tax_code_id == 0)
- {
- $sales_tax_code_id = $this->config['default_tax_code']; // overrides customer assigned code
- }
- }
- }
-
- return $sales_tax_code_id;
- }
-
- /**
- * @param string $string
- * @return string
- */
- public function clean(string $string): string //TODO: $string is not a good choice of variable name here.
- {
- $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
-
- return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
- }
-
- /**
- * @return array
- */
- public function get_tax_code_options(): array
- {
- $tax_codes = $this->tax_code->get_all()->getResultArray();
- $tax_code_options = [];
- $tax_code_options[''] = '';
-
- foreach($tax_codes as $tax_code)
- {
- $a = $tax_code['tax_code_id']; //TODO: Need to refactor single-letter variables into meaningful variable names
- $b = $tax_code['tax_code_name'];
- $tax_code_options[$a] = $b;
- }
-
- return $tax_code_options;
- }
-
- /**
- * @return array
- */
- public function get_tax_jurisdiction_options(): array
- {
- $tax_jurisdictions = $this->tax_jurisdiction->get_all()->getResultArray();
- $tax_jurisdiction_options = [];
- $tax_jurisdiction_options[0] = '';
-
- foreach($tax_jurisdictions as $tax_jurisdiction) //TODO: Need to refactor single-letter variables into meaningful variable names
- {
- $a = $tax_jurisdiction['jurisdiction_id'];
- $b = $tax_jurisdiction['jurisdiction_name'];
- $tax_jurisdiction_options[$a] = $b;
- }
-
- return $tax_jurisdiction_options;
- }
-
- /**
- * @return array
- */
- public function get_tax_category_options(): array
- {
- $tax_categories = $this->tax_category->get_all()->getResultArray();
- $tax_category_options = [];
- $tax_category_options[0] = '';
-
- foreach($tax_categories as $tax_category)
- {
- $a = $tax_category['tax_category_id']; //TODO: Need to refactor single-letter variables into meaningful variable names
- $b = $tax_category['tax_category'];
-
- $tax_category_options[$a] = $b;
- }
-
- return $tax_category_options;
- }
-
- /**
- * @param string $selected_tax_type
- * @return string
- */
- public function get_tax_type_options(string $selected_tax_type): string
- {
- $selected = 'selected=\"selected\" ';
-
- $s1 = ''; //TODO: Need to refactor short variables into meaningful variable names
- $s2 = '';
-
- if($selected_tax_type === Tax_lib::TAX_TYPE_EXCLUDED)
- {
- $s1 = $selected;
- }
- else if($selected_tax_type === Tax_lib::TAX_TYPE_INCLUDED)
- {
- $s2 = $selected;
- }
-
- return ''
- . '';
- }
+ public const TAX_TYPE_EXCLUDED = '1'; //TODO: These constants need to be moved to constants.php
+ public const TAX_TYPE_INCLUDED = '0';
+ private Sale_lib $sale_lib;
+ private Customer $customer;
+ private Item_taxes $item_taxes;
+ private Sale $sale;
+ private Tax $tax;
+ private Tax_category $tax_category;
+ private Tax_code $tax_code;
+ private Tax_jurisdiction $tax_jurisdiction;
+ private array $config;
+
+ public function __construct()
+ {
+ $this->sale_lib = new Sale_lib();
+
+ $this->customer = model(Customer::class);
+ $this->item_taxes = model(Item_taxes::class);
+ $this->sale = model(Sale::class);
+ $this->tax = model(Tax::class);
+ $this->tax_category = model(Tax_category::class);
+ $this->tax_code = model(Tax_code::class);
+ $this->tax_jurisdiction = model(Tax_jurisdiction::class);
+ $this->config = config(OSPOS::class)->settings;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_tax_types(): array
+ {
+ return [
+ Tax_lib::TAX_TYPE_EXCLUDED => lang('Taxes.tax_excluded'),
+ Tax_lib::TAX_TYPE_INCLUDED => lang('Taxes.tax_included')
+ ];
+ }
+
+ /**
+ * Compute the tax basis and returns the tax amount
+ */
+ public function get_item_sales_tax(string $quantity, string $price, string $discount, int $discount_type, string $tax_percentage, int $rounding_code): string //TODO: It appears this function is never called in the code.
+ {
+ $decimals = tax_decimals();
+
+ // The tax basis should be returned to the currency scale
+ $tax_basis = $this->sale_lib->get_item_total($quantity, $price, $discount, $discount_type, true);
+
+ return $this->get_tax_for_amount($tax_basis, $tax_percentage, $rounding_code, $decimals);
+ }
+
+ /**
+ * Computes the item level sales tax amount for a given tax basis
+ */
+ public function get_tax_for_amount(string $tax_basis, string $tax_percentage, int $rounding_mode, int $decimals): string
+ {
+ $tax_amount = bcmul($tax_basis, bcdiv($tax_percentage, '100'));
+
+ return rounding_mode::round_number($rounding_mode, $tax_amount, $decimals);
+ }
+
+ /**
+ * Compute taxes for all items in the cart
+ */
+ public function get_taxes(array &$cart, int $sale_id = -1): array //TODO: Replace -1 with constant.
+ {
+ $register_mode = $this->sale_lib->get_mode();
+ $tax_decimals = tax_decimals();
+ $customer_id = $this->sale_lib->get_customer();
+ $customer_info = $this->customer->get_info($customer_id);
+ $taxes = [];
+ $item_taxes = [];
+
+ // Charge sales tax if customer is not selected (walk-in) or customer is flagged as taxable
+ if($customer_id == -1 || $customer_info->taxable) //TODO: Replace -1 with constant.
+ {
+ foreach($cart as $line => $item)
+ {
+ $taxed = false;
+
+ if(!$this->config['use_destination_based_tax'])
+ {
+ // Start of current Base System tax calculations
+
+ if($sale_id == -1) //TODO: Replace -1 with constant. Also, replace with ternary notation.
+ {
+ $tax_info = $this->item_taxes->get_info($item['item_id']);
+ }
+ else
+ {
+ $tax_info = $this->sale->get_sales_item_taxes($sale_id, $item['item_id']);
+ }
+
+ $tax_group_sequence = 0;
+ $cascade_level = 0; //TODO: This variable is set but never used.
+ $cascade_basis_level = 0; //TODO: This variable is set but never used.
+
+ foreach($tax_info as $tax)
+ {
+ // This computes tax for each line item and adds it to the tax type total
+ $tax_basis = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], true);
+ $tax_amount = '0.0';
+
+ if($this->config['tax_included'])
+ {
+ $tax_type = Tax_lib::TAX_TYPE_INCLUDED;
+ $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $tax['percent'], $tax_decimals, Rounding_mode::HALF_UP);
+ }
+ else
+ {
+ $tax_type = Tax_lib::TAX_TYPE_EXCLUDED;
+ $tax_amount = $this->get_tax_for_amount($tax_basis, $tax['percent'], Rounding_mode::HALF_UP, $tax_decimals);
+ }
+
+ if($tax_amount <> 0)
+ {
+ $tax_group_sequence++;
+ $this->update_taxes($taxes, $tax_type, $tax['name'], $tax['percent'], $tax_basis, $tax_amount, $tax_group_sequence, Rounding_mode::HALF_UP, -1, $tax['name']); //TODO: Replace -1 with constant.
+ $tax_group_sequence += 1; //TODO: $tax_group_sequence++;
+ $taxed = true;
+ }
+
+ $items_taxes_detail = [];
+ $items_taxes_detail['item_id'] = $item['item_id'];
+ $items_taxes_detail['line'] = $item['line'];
+ $items_taxes_detail['name'] = $tax['name'];
+ $items_taxes_detail['percent'] = $tax['percent'];
+ $items_taxes_detail['tax_type'] = $tax_type;
+ $items_taxes_detail['rounding_code'] = Rounding_mode::HALF_UP;
+ $items_taxes_detail['cascade_sequence'] = 0;
+ $items_taxes_detail['item_tax_amount'] = $tax_amount;
+ $items_taxes_detail['sales_tax_code_id'] = null;
+ $items_taxes_detail['jurisdiction_id'] = null;
+ $items_taxes_detail['tax_category_id'] = null;
+
+ $item_taxes[] = $items_taxes_detail;
+ }
+ }
+ else
+ {
+ // Start of destination based tax calculations
+ if($item['tax_category_id'] == null) //TODO: === ?
+ {
+ $item['tax_category_id'] = $this->config['default_tax_category'];
+ }
+
+ $taxed = $this->apply_destination_tax($item, $customer_info->city, $customer_info->state, $customer_info->sales_tax_code_id, $register_mode, 0, $taxes, $item_taxes, $item['line']);
+ }
+
+ if($taxed) //TODO: Convert to ternary notation
+ {
+ $cart[$line]['taxed_flag'] = lang('Sales.taxed_ind');
+ }
+ else
+ {
+ $cart[$line]['taxed_flag'] = lang('Sales.nontaxed_ind');
+ }
+ }
+ $this->round_taxes($taxes);
+ }
+
+ $tax_details = [];
+ $tax_details[0] = $taxes;
+ $tax_details[1] = $item_taxes;
+
+ return $tax_details;
+ }
+
+ /**
+ * @param string $quantity
+ * @param string $price
+ * @param string $discount_percentage
+ * @param int $discount_type
+ * @param string $tax_percentage
+ * @param $tax_decimal
+ * @param $rounding_code
+ * @return string
+ */
+ public function get_included_tax(string $quantity, string $price, string $discount_percentage, int $discount_type, string $tax_percentage, $tax_decimal, $rounding_code): string //TODO: $tax_decimal and $rounding_code are in the signature but never used in the function.
+ {
+ $item_total = $this->sale_lib->get_item_total($quantity, $price, $discount_percentage, $discount_type, true);
+ $tax_fraction = bcdiv(bcadd('100', $tax_percentage), '100');
+ $price_tax_excl = bcdiv($item_total, $tax_fraction);
+ return bcsub($item_total, $price_tax_excl);
+ }
+
+ /**
+ * Updates the sales_tax array which is later saved to the `sales_taxes` table and used for printing taxes on receipts and invoices
+ */
+ public function update_taxes(array &$taxes, string $tax_type, string $tax_group, string $tax_rate, string $tax_basis, string $item_tax_amount, int $tax_group_sequence, int $rounding_code, int $sale_id, string $name = '', int $tax_code_id = null, int $jurisdiction_id = null, int $tax_category_id = null): void
+ {
+ $tax_group_index = $this->clean('X' . (float)$tax_rate . '% ' . $tax_group); //TODO: Not sure we should be casting to a float here. The clean() function takes a string, so it just gets converted back to a string and there's risk of inaccuracies in the value displayed.
+
+ if(!array_key_exists($tax_group_index, $taxes))
+ {
+ $insertkey = $tax_group_index; //TODO: this variable does not follow naming conventions.
+
+ $tax = [
+ $insertkey => [
+ 'sale_id' => $sale_id,
+ 'tax_type' => $tax_type,
+ 'tax_group' => $tax_group,
+ 'sale_tax_basis' => $tax_basis,
+ 'sale_tax_amount' => $item_tax_amount,
+ 'print_sequence' => $tax_group_sequence,
+ 'name' => $name,
+ 'tax_rate' => $tax_rate,
+ 'sales_tax_code_id' => $tax_code_id,
+ 'jurisdiction_id' => $jurisdiction_id,
+ 'tax_category_id' => $tax_category_id,
+ 'rounding_code' => $rounding_code
+ ]
+ ];
+
+ //add to existing array
+ $taxes += $tax;
+ }
+ else
+ {
+ // Important ... the sales amounts are accumulated for the group at the maximum configurable scale value of 4
+ // but the scale will in reality be the scale specified by the tax_decimal configuration value used for sales_items_taxes
+ $taxes[$tax_group_index]['sale_tax_basis'] = bcadd($taxes[$tax_group_index]['sale_tax_basis'], $tax_basis, 4);
+ $taxes[$tax_group_index]['sale_tax_amount'] = bcadd($taxes[$tax_group_index]['sale_tax_amount'], $item_tax_amount, 4);
+ }
+ }
+
+ /**
+ * If invoice taxing (as opposed to invoice_item_taxing) rules apply then recalculate the sales tax after tax group totals are final
+ * This is currently used ONLY for the original sales tax migration.
+ */
+ public function apply_invoice_taxing(array &$taxes): void
+ {
+ if(!empty($taxes))
+ {
+ $sort = [];
+ foreach($taxes as $k => $v)
+ {
+ $sort['print_sequence'][$k] = $v['print_sequence'];
+ }
+ array_multisort($sort['print_sequence'], SORT_ASC, $taxes);
+ }
+
+ $decimals = totals_decimals();
+
+ foreach($taxes as $row_number => $tax)
+ {
+ $taxes[$row_number]['sale_tax_amount'] = $this->get_tax_for_amount($tax['sale_tax_basis'], $tax['tax_rate'], $tax['rounding_code'], $decimals);
+ }
+ }
+
+ /**
+ * Apply rounding rules to the accumulated sales tax amounts
+ */
+ public function round_taxes(array &$taxes): void
+ {
+ if(!empty($taxes))
+ {
+ $sort = [];
+ foreach($taxes as $k => $v)
+ {
+ $sort['print_sequence'][$k] = $v['print_sequence'];
+ }
+ array_multisort($sort['print_sequence'], SORT_ASC, $taxes);
+ }
+
+ // If tax included then round decimal to tax decimals, otherwise round it to currency_decimals
+ if($this->config['tax_included']) //TODO: Convert to ternary notation
+ {
+ $decimals = tax_decimals();
+ }
+ else
+ {
+ $decimals = totals_decimals();
+ }
+
+ foreach($taxes as $row_number => $sales_tax)
+ {
+ $tax_amount = $sales_tax['sale_tax_amount'];
+ $rounding_code = $sales_tax['rounding_code'];
+ $rounded_tax_amount = $tax_amount;
+
+ if($rounding_code == Rounding_mode::HALF_UP) //TODO: this block needs to be converted to a switch statement
+ {
+ $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP);
+ }
+ elseif($rounding_code == Rounding_mode::HALF_DOWN)
+ {
+ $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_DOWN);
+ }
+ elseif($rounding_code == Rounding_mode::HALF_EVEN)
+ {
+ $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_EVEN);
+ }
+ elseif($rounding_code == Rounding_mode::HALF_ODD)
+ {
+ $rounded_tax_amount = round($tax_amount, $decimals, PHP_ROUND_HALF_UP);
+ }
+ elseif($rounding_code == Rounding_mode::ROUND_UP)
+ {
+ $fig = (int)str_pad('1', $decimals, '0');
+ $rounded_tax_amount = ceil($tax_amount * $fig) / $fig;
+ }
+ elseif($rounding_code == Rounding_mode::ROUND_DOWN)
+ {
+ $fig = (int)str_pad('1', $decimals, '0');
+ $rounded_tax_amount = floor($tax_amount * $fig) / $fig;
+ }
+ elseif($rounding_code == Rounding_mode::HALF_FIVE)
+ {
+ $rounded_tax_amount = round($tax_amount / 5) * 5;
+ }
+
+ $taxes[$row_number]['sale_tax_amount'] = $rounded_tax_amount;
+ }
+ }
+
+ /**
+ * Determine the applicable tax code and then determine the tax amount to be applied.
+ * If a tax amount was identified then accumulate into the sales_taxes array
+ */
+ public function apply_destination_tax(array &$item, string $city, string $state, int $sales_tax_code_id, string $register_mode, int $sale_id, array &$taxes, array &$item_taxes, int $line): bool
+ {
+ $taxed = false;
+
+ $tax_code_id = $this->get_applicable_tax_code($register_mode, $city, $state, $sales_tax_code_id);
+
+ // If tax code cannot be determined or the price is zero then skip this item
+ if($tax_code_id != -1 && $item['price'] != 0) //TODO: Replace -1 with constant. Also === ?
+ {
+ $tax_decimals = tax_decimals();
+
+ $tax_definition = $this->tax->get_taxes($tax_code_id, $item['tax_category_id']);
+
+ // The tax basis should be returned to the currency scale
+ $tax_basis = $this->sale_lib->get_item_total($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], true);
+
+ $row = 0; //TODO: This variable is set but never used.
+
+ $last_cascade_sequence = 0;
+ $cascade_tax_amount = '0.0';
+
+ foreach($tax_definition as $tax)
+ {
+ $cascade_sequence = $tax['cascade_sequence'];
+ if($cascade_sequence != $last_cascade_sequence)
+ {
+ $last_cascade_sequence = $cascade_sequence;
+ $tax_basis = bcadd($tax_basis, $cascade_tax_amount);
+ }
+
+ $tax_rate = $tax['tax_rate'];
+ $rounding_code = $tax['tax_rounding_code'];
+
+ // This computes tax for each line item and adds it to the tax type total
+ $tax_type = $tax['tax_type'];
+
+ if($tax_type == Tax_lib::TAX_TYPE_INCLUDED)
+ {
+ $tax_amount = $this->get_included_tax($item['quantity'], $item['price'], $item['discount'], $item['discount_type'], $tax_rate, $tax_decimals, $rounding_code);
+ }
+ else
+ {
+ $tax_amount = $this->get_tax_for_amount($tax_basis, $tax_rate, $rounding_code, $tax_decimals);
+ $cascade_tax_amount = bcadd($cascade_tax_amount,$tax_amount);
+ }
+
+ if($tax_amount != 0)
+ {
+ $taxed = true;
+ $this->update_taxes($taxes, $tax_type, $tax['tax_group'], $tax_rate, $tax_basis, $tax_amount, $tax['tax_group_sequence'], $rounding_code, $sale_id, $tax['tax_group'], $tax_code_id, $tax['rate_jurisdiction_id'], $item['tax_category_id']);
+ }
+
+ $item_taxes_detail = [];
+ $item_taxes_detail['line'] = $line;
+ $item_taxes_detail['item_id'] = $item['item_id'];
+ $item_taxes_detail['name'] = $tax['tax_group'];
+ $item_taxes_detail['percent'] = $tax['tax_rate'];
+ $item_taxes_detail['tax_type'] = $tax_type;
+ $item_taxes_detail['rounding_code'] = $rounding_code;
+ $item_taxes_detail['cascade_sequence'] = $cascade_sequence;
+ $item_taxes_detail['item_tax_amount'] = $tax_amount;
+ $item_taxes_detail['sales_tax_code_id'] = $tax_code_id;
+ $item_taxes_detail['jurisdiction_id'] = $tax['rate_jurisdiction_id'];
+ $item_taxes_detail['tax_category_id'] = $tax['rate_tax_category_id'];
+ $item_taxes_detail['tax_group_sequence'] = $tax['tax_group_sequence'];
+
+ $item_taxes[] = $item_taxes_detail;
+ }
+ }
+
+ return $taxed;
+ }
+
+ /**
+ * @param string $register_mode
+ * @param string $city
+ * @param string $state
+ * @param int $sales_tax_code_id
+ * @return int
+ */
+ public function get_applicable_tax_code(string $register_mode, string $city, string $state, int $sales_tax_code_id): int
+ {
+ if($register_mode == 'sale')
+ {
+ $sales_tax_code_id = $this->config['default_tax_code']; // overrides customer assigned code
+ }
+ else
+ {
+ if($sales_tax_code_id == null || $sales_tax_code_id == 0)
+ {
+ $sales_tax_code_id = $this->tax_code->get_sales_tax_code($city, $state);
+
+ if($sales_tax_code_id == null || $sales_tax_code_id == 0)
+ {
+ $sales_tax_code_id = $this->config['default_tax_code']; // overrides customer assigned code
+ }
+ }
+ }
+
+ return $sales_tax_code_id;
+ }
+
+ /**
+ * @param string $string
+ * @return string
+ */
+ public function clean(string $string): string //TODO: $string is not a good choice of variable name here.
+ {
+ $string = str_replace(' ', '-', $string); // Replaces all spaces with hyphens.
+
+ return preg_replace('/[^A-Za-z0-9\-]/', '', $string); // Removes special chars.
+ }
+
+ /**
+ * @return array
+ */
+ public function get_tax_code_options(): array
+ {
+ $tax_codes = $this->tax_code->get_all()->getResultArray();
+ $tax_code_options = [];
+ $tax_code_options[''] = '';
+
+ foreach($tax_codes as $tax_code)
+ {
+ $a = $tax_code['tax_code_id']; //TODO: Need to refactor single-letter variables into meaningful variable names
+ $b = $tax_code['tax_code_name'];
+ $tax_code_options[$a] = $b;
+ }
+
+ return $tax_code_options;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_tax_jurisdiction_options(): array
+ {
+ $tax_jurisdictions = $this->tax_jurisdiction->get_all()->getResultArray();
+ $tax_jurisdiction_options = [];
+ $tax_jurisdiction_options[0] = '';
+
+ foreach($tax_jurisdictions as $tax_jurisdiction) //TODO: Need to refactor single-letter variables into meaningful variable names
+ {
+ $a = $tax_jurisdiction['jurisdiction_id'];
+ $b = $tax_jurisdiction['jurisdiction_name'];
+ $tax_jurisdiction_options[$a] = $b;
+ }
+
+ return $tax_jurisdiction_options;
+ }
+
+ /**
+ * @return array
+ */
+ public function get_tax_category_options(): array
+ {
+ $tax_categories = $this->tax_category->get_all()->getResultArray();
+ $tax_category_options = [];
+ $tax_category_options[0] = '';
+
+ foreach($tax_categories as $tax_category)
+ {
+ $a = $tax_category['tax_category_id']; //TODO: Need to refactor single-letter variables into meaningful variable names
+ $b = $tax_category['tax_category'];
+
+ $tax_category_options[$a] = $b;
+ }
+
+ return $tax_category_options;
+ }
+
+ /**
+ * @param string $selected_tax_type
+ * @return string
+ */
+ public function get_tax_type_options(string $selected_tax_type): string
+ {
+ $selected = 'selected=\"selected\" ';
+
+ $s1 = ''; //TODO: Need to refactor short variables into meaningful variable names
+ $s2 = '';
+
+ if($selected_tax_type === Tax_lib::TAX_TYPE_EXCLUDED)
+ {
+ $s1 = $selected;
+ }
+ else if($selected_tax_type === Tax_lib::TAX_TYPE_INCLUDED)
+ {
+ $s2 = $selected;
+ }
+
+ return ''
+ . '';
+ }
}
diff --git a/app/Libraries/Token_lib.php b/app/Libraries/Token_lib.php
index 8f06258e8..c68913dfb 100644
--- a/app/Libraries/Token_lib.php
+++ b/app/Libraries/Token_lib.php
@@ -14,184 +14,184 @@ use DateTime;
*/
class Token_lib
{
- /**
- * Expands all the tokens found in a given text string and returns the results.
- */
- public function render(string $tokened_text, array $tokens = [], $save = true): string
- {
- // Apply the transformation for the "%" tokens if any are used
- if(strpos($tokened_text, '%') !== false)
- {
- $tokened_text = strftime($tokened_text); //TODO: these need to be converted to IntlDateFormatter::format()
- }
+ /**
+ * Expands all the tokens found in a given text string and returns the results.
+ */
+ public function render(string $tokened_text, array $tokens = [], $save = true): string
+ {
+ // Apply the transformation for the "%" tokens if any are used
+ if(strpos($tokened_text, '%') !== false)
+ {
+ $tokened_text = strftime($tokened_text); //TODO: these need to be converted to IntlDateFormatter::format()
+ }
- // Call scan to build an array of all of the tokens used in the text to be transformed
- $token_tree = $this->scan($tokened_text);
+ // Call scan to build an array of all of the tokens used in the text to be transformed
+ $token_tree = $this->scan($tokened_text);
- if(empty($token_tree))
- {
- if(strpos($tokened_text, '%') !== false)
- {
- return strftime($tokened_text);
- }
- else
- {
- return $tokened_text;
- }
- }
+ if(empty($token_tree))
+ {
+ if(strpos($tokened_text, '%') !== false)
+ {
+ return strftime($tokened_text);
+ }
+ else
+ {
+ return $tokened_text;
+ }
+ }
- $token_values = [];
- $tokens_to_replace = [];
- $this->generate($token_tree, $tokens_to_replace, $token_values, $tokens, $save);
+ $token_values = [];
+ $tokens_to_replace = [];
+ $this->generate($token_tree, $tokens_to_replace, $token_values, $tokens, $save);
- return str_replace($tokens_to_replace, $token_values, $tokened_text);
- }
+ return str_replace($tokens_to_replace, $token_values, $tokened_text);
+ }
- /**
- * Parses out the all the tokens enclosed in braces {} and subparses on the colon : character where supplied
- */
- public function scan(string $text): array
- {
- // Matches tokens with the following pattern: [$token:$length]
- preg_match_all('/
- \{ # [ - pattern start
- ([^\s\{\}:]+) # match $token not containing whitespace : { or }
- (?:
- : # : - separator
- ([^\s\{\}:]+) # match $length not containing whitespace : { or }
- )?
- \} # ] - pattern end
- /x', $text, $matches);
+ /**
+ * Parses out the all the tokens enclosed in braces {} and subparses on the colon : character where supplied
+ */
+ public function scan(string $text): array
+ {
+ // Matches tokens with the following pattern: [$token:$length]
+ preg_match_all('/
+ \{ # [ - pattern start
+ ([^\s\{\}:]+) # match $token not containing whitespace : { or }
+ (?:
+ : # : - separator
+ ([^\s\{\}:]+) # match $length not containing whitespace : { or }
+ )?
+ \} # ] - pattern end
+ /x', $text, $matches);
- $tokens = $matches[1];
- $lengths = $matches[2];
+ $tokens = $matches[1];
+ $lengths = $matches[2];
- $token_tree = [];
- for($i = 0; $i < count($tokens); $i++)
- {
- $token_tree[$tokens[$i]][$lengths[$i]] = $matches[0][$i];
- }
+ $token_tree = [];
+ for($i = 0; $i < count($tokens); $i++)
+ {
+ $token_tree[$tokens[$i]][$lengths[$i]] = $matches[0][$i];
+ }
- return $token_tree;
- }
+ return $token_tree;
+ }
- /**
- * @param string|null $quantity
- * @param string|null $price
- * @param string|null $item_id_or_number_or_item_kit_or_receipt
- * @return void
- */
- public function parse_barcode(?string &$quantity, ?string &$price, ?string &$item_id_or_number_or_item_kit_or_receipt): void
- {
- $config = config(OSPOS::class)->settings;
- $barcode_formats = json_decode($config['barcode_formats']);
- $barcode_tokens = Token::get_barcode_tokens();
+ /**
+ * @param string|null $quantity
+ * @param string|null $price
+ * @param string|null $item_id_or_number_or_item_kit_or_receipt
+ * @return void
+ */
+ public function parse_barcode(?string &$quantity, ?string &$price, ?string &$item_id_or_number_or_item_kit_or_receipt): void
+ {
+ $config = config(OSPOS::class)->settings;
+ $barcode_formats = json_decode($config['barcode_formats']);
+ $barcode_tokens = Token::get_barcode_tokens();
- if(!empty($barcode_formats))
- {
- foreach($barcode_formats as $barcode_format)
- {
- $parsed_results = $this->parse($item_id_or_number_or_item_kit_or_receipt, $barcode_format, $barcode_tokens);
- $quantity = (isset($parsed_results['W'])) ? (int) $parsed_results['W'] / 1000 : 1;
- $item_id_or_number_or_item_kit_or_receipt = (isset($parsed_results['I'])) ?
- $parsed_results['I'] : $item_id_or_number_or_item_kit_or_receipt;
- $price = (isset($parsed_results['P'])) ? (double) $parsed_results['P'] : null;
- }
- }
- else
- {
- $quantity = 1; //TODO: Quantity is handled using bcmath functions so that it is precision safe. This should be '1'
- }
- }
+ if(!empty($barcode_formats))
+ {
+ foreach($barcode_formats as $barcode_format)
+ {
+ $parsed_results = $this->parse($item_id_or_number_or_item_kit_or_receipt, $barcode_format, $barcode_tokens);
+ $quantity = (isset($parsed_results['W'])) ? (int) $parsed_results['W'] / 1000 : 1;
+ $item_id_or_number_or_item_kit_or_receipt = (isset($parsed_results['I'])) ?
+ $parsed_results['I'] : $item_id_or_number_or_item_kit_or_receipt;
+ $price = (isset($parsed_results['P'])) ? (double) $parsed_results['P'] : null;
+ }
+ }
+ else
+ {
+ $quantity = 1; //TODO: Quantity is handled using bcmath functions so that it is precision safe. This should be '1'
+ }
+ }
- /**
- * @param string $string
- * @param string $pattern
- * @param array $tokens
- * @return array
- */
- public function parse(string $string, string $pattern, array $tokens = []): array //TODO: $string is a poor name for this parameter.
- {
- $token_tree = $this->scan($pattern);
+ /**
+ * @param string $string
+ * @param string $pattern
+ * @param array $tokens
+ * @return array
+ */
+ public function parse(string $string, string $pattern, array $tokens = []): array //TODO: $string is a poor name for this parameter.
+ {
+ $token_tree = $this->scan($pattern);
- $found_tokens = [];
- foreach ($token_tree as $token_id => $token_length)
- {
- foreach ($tokens as $token)
- {
- if ($token->token_id() == $token_id)
- {
- $found_tokens[] = $token;
- $keys = array_keys($token_length);
- $length = array_shift($keys);
- $pattern = str_replace(array_shift($token_length), "({$token->get_value()}{".$length."})", $pattern);
- }
- }
- }
+ $found_tokens = [];
+ foreach ($token_tree as $token_id => $token_length)
+ {
+ foreach ($tokens as $token)
+ {
+ if ($token->token_id() == $token_id)
+ {
+ $found_tokens[] = $token;
+ $keys = array_keys($token_length);
+ $length = array_shift($keys);
+ $pattern = str_replace(array_shift($token_length), "({$token->get_value()}{".$length."})", $pattern);
+ }
+ }
+ }
- $results = [];
+ $results = [];
- if (preg_match("/$pattern/", $string, $matches))
- {
- foreach($found_tokens as $token)
- {
- $index = array_search($token, $found_tokens);
- $match = $matches[$index+1];
- $results[$token->token_id()] = $match;
- }
- }
+ if (preg_match("/$pattern/", $string, $matches))
+ {
+ foreach($found_tokens as $token)
+ {
+ $index = array_search($token, $found_tokens);
+ $match = $matches[$index+1];
+ $results[$token->token_id()] = $match;
+ }
+ }
- return $results;
- }
+ return $results;
+ }
- /**
- * @param array $used_tokens
- * @param array $tokens_to_replace
- * @param array $token_values
- * @param array $tokens
- * @param bool $save
- * @return array
- */
- public function generate(array $used_tokens, array &$tokens_to_replace, array &$token_values, array $tokens, bool $save = true): array //TODO: $tokens
- {
- foreach($used_tokens as $token_code => $token_info)
- {
- // Generate value here based on the key value
- $token_value = $this->resolve_token($token_code, [], $save);
+ /**
+ * @param array $used_tokens
+ * @param array $tokens_to_replace
+ * @param array $token_values
+ * @param array $tokens
+ * @param bool $save
+ * @return array
+ */
+ public function generate(array $used_tokens, array &$tokens_to_replace, array &$token_values, array $tokens, bool $save = true): array //TODO: $tokens
+ {
+ foreach($used_tokens as $token_code => $token_info)
+ {
+ // Generate value here based on the key value
+ $token_value = $this->resolve_token($token_code, [], $save);
- foreach($token_info as $length => $token_spec)
- {
- $tokens_to_replace[] = $token_spec;
- if(!empty($length))
- {
- $token_values[] = str_pad($token_value, $length, '0', STR_PAD_LEFT);
- }
- else
- {
- $token_values[] = $token_value;
- }
- }
- }
+ foreach($token_info as $length => $token_spec)
+ {
+ $tokens_to_replace[] = $token_spec;
+ if(!empty($length))
+ {
+ $token_values[] = str_pad($token_value, $length, '0', STR_PAD_LEFT);
+ }
+ else
+ {
+ $token_values[] = $token_value;
+ }
+ }
+ }
- return $token_values;
- }
+ return $token_values;
+ }
- /**
- * @param $token_code
- * @param array $tokens
- * @param bool $save
- * @return string
- */
- private function resolve_token($token_code, array $tokens = [], bool $save = true): string
- {
- foreach(array_merge($tokens, Token::get_tokens()) as $token)
- {
- if($token->token_id() == $token_code)
- {
- return $token->get_value($save);
- }
- }
+ /**
+ * @param $token_code
+ * @param array $tokens
+ * @param bool $save
+ * @return string
+ */
+ private function resolve_token($token_code, array $tokens = [], bool $save = true): string
+ {
+ foreach(array_merge($tokens, Token::get_tokens()) as $token)
+ {
+ if($token->token_id() == $token_code)
+ {
+ return $token->get_value($save);
+ }
+ }
- return '';
- }
+ return '';
+ }
}
diff --git a/app/Libraries/index.html b/app/Libraries/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Libraries/index.html
+++ b/app/Libraries/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Models/Appconfig.php b/app/Models/Appconfig.php
index 4251ce35e..2699dc090 100644
--- a/app/Models/Appconfig.php
+++ b/app/Models/Appconfig.php
@@ -14,172 +14,172 @@ use ReflectionException;
*/
class Appconfig extends Model
{
- protected $table = 'app_config';
- protected $primaryKey = 'key';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'key',
- 'value'
- ];
+ protected $table = 'app_config';
+ protected $primaryKey = 'key';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'key',
+ 'value'
+ ];
- /**
- * Checks to see if a given configuration exists in the database.
- *
- * @param string $key Key name to be searched.
- * @return bool True if the key is found in the database or false if it does not exist.
- */
- public function exists(string $key): bool
- {
- $builder = $this->db->table('app_config');
- $builder->where('key', $key);
+ /**
+ * Checks to see if a given configuration exists in the database.
+ *
+ * @param string $key Key name to be searched.
+ * @return bool True if the key is found in the database or false if it does not exist.
+ */
+ public function exists(string $key): bool
+ {
+ $builder = $this->db->table('app_config');
+ $builder->where('key', $key);
- return ($builder->get()->getNumRows() === 1);
- }
+ return ($builder->get()->getNumRows() === 1);
+ }
- /**
- * Get all OpenSourcePOS configuration values from the database.
- *
- * @return ResultInterface
- */
- public function get_all(): ResultInterface
- {
- $builder = $this->db->table('app_config');
- $builder->orderBy('key', 'asc');
+ /**
+ * Get all OpenSourcePOS configuration values from the database.
+ *
+ * @return ResultInterface
+ */
+ public function get_all(): ResultInterface
+ {
+ $builder = $this->db->table('app_config');
+ $builder->orderBy('key', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $key
- * @param string $default
- * @return string
- */
- public function get_value(string $key, string $default = ''): string
- {
- $builder = $this->db->table('app_config');
- $query = $builder->getWhere(['key' => $key], 1);
+ /**
+ * @param string $key
+ * @param string $default
+ * @return string
+ */
+ public function get_value(string $key, string $default = ''): string
+ {
+ $builder = $this->db->table('app_config');
+ $query = $builder->getWhere(['key' => $key], 1);
- if($query->getNumRows() === 1)
- {
- return $query->getRow()->value;
- }
+ if($query->getNumRows() === 1)
+ {
+ return $query->getRow()->value;
+ }
- return $default;
- }
+ return $default;
+ }
- /**
- * Calls the parent save() from BaseModel and updates the cached reference.
- *
- * @param array|object $data
- * @return bool true when the save was successful and false if the save failed.
- * @throws ReflectionException
- */
- public function save($data): bool
- {
- $key = array_keys($data)[0];
- $value = $data[$key];
- $save_data = ['key' => $key, 'value' => $value];
+ /**
+ * Calls the parent save() from BaseModel and updates the cached reference.
+ *
+ * @param array|object $data
+ * @return bool true when the save was successful and false if the save failed.
+ * @throws ReflectionException
+ */
+ public function save($data): bool
+ {
+ $key = array_keys($data)[0];
+ $value = $data[$key];
+ $save_data = ['key' => $key, 'value' => $value];
- $success = parent::save($save_data);
+ $success = parent::save($save_data);
- if($success)
- {
- config(OSPOS::class)->update_settings();
- }
+ if($success)
+ {
+ config(OSPOS::class)->update_settings();
+ }
- return $success;
- }
+ return $success;
+ }
- /**
- * @throws ReflectionException
- */
- public function batch_save(array $data): bool
- {
- $success = true;
+ /**
+ * @throws ReflectionException
+ */
+ public function batch_save(array $data): bool
+ {
+ $success = true;
- $this->db->transStart();
+ $this->db->transStart();
- foreach($data as $key => $value)
- {
- $success &= $this->save([$key => $value]);
- }
+ foreach($data as $key => $value)
+ {
+ $success &= $this->save([$key => $value]);
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Deletes a row from the Appconfig table given the name of the setting to delete.
- *
- * @param ?string $id The field name to be deleted in the Appconfig table.
- * @param bool $purge A hard delete is conducted if true and soft delete on false.
- * @return bool Result of the delete operation.
- */
- public function delete($id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('app_config');
- return $builder->delete(['key' => $id]);
- }
+ /**
+ * Deletes a row from the Appconfig table given the name of the setting to delete.
+ *
+ * @param ?string $id The field name to be deleted in the Appconfig table.
+ * @param bool $purge A hard delete is conducted if true and soft delete on false.
+ * @return bool Result of the delete operation.
+ */
+ public function delete($id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('app_config');
+ return $builder->delete(['key' => $id]);
+ }
- /**
- * @return bool
- */
- public function delete_all(): bool //TODO: This function is never used in the code. Consider removing it.
- {
- $builder = $this->db->table('app_config');
- return $builder->emptyTable();
- }
+ /**
+ * @return bool
+ */
+ public function delete_all(): bool //TODO: This function is never used in the code. Consider removing it.
+ {
+ $builder = $this->db->table('app_config');
+ return $builder->emptyTable();
+ }
- /**
- * @throws ReflectionException
- */
- public function acquire_next_invoice_sequence(bool $save = true): string
- {
- $config = config(OSPOS::class)->settings;
- $last_used = (int)$config['last_used_invoice_number'] + 1;
+ /**
+ * @throws ReflectionException
+ */
+ public function acquire_next_invoice_sequence(bool $save = true): string
+ {
+ $config = config(OSPOS::class)->settings;
+ $last_used = (int)$config['last_used_invoice_number'] + 1;
- if($save)
- {
- $this->save(['last_used_invoice_number'=> $last_used]);
- }
+ if($save)
+ {
+ $this->save(['last_used_invoice_number'=> $last_used]);
+ }
- return $last_used;
- }
+ return $last_used;
+ }
- /**
- * @throws ReflectionException
- */
- public function acquire_next_quote_sequence(bool $save = true): string
- {
- $config = config(OSPOS::class)->settings;
- $last_used = (int)$config['last_used_quote_number'] + 1;
+ /**
+ * @throws ReflectionException
+ */
+ public function acquire_next_quote_sequence(bool $save = true): string
+ {
+ $config = config(OSPOS::class)->settings;
+ $last_used = (int)$config['last_used_quote_number'] + 1;
- if($save)
- {
- $this->save(['last_used_quote_number' => $last_used]);
- }
+ if($save)
+ {
+ $this->save(['last_used_quote_number' => $last_used]);
+ }
- return $last_used;
- }
+ return $last_used;
+ }
- /**
- * @throws ReflectionException
- */
- public function acquire_next_work_order_sequence(bool $save = true): string
- {
- $config = config(OSPOS::class)->settings;
- $last_used = (int)$config['last_used_work_order_number'] + 1;
+ /**
+ * @throws ReflectionException
+ */
+ public function acquire_next_work_order_sequence(bool $save = true): string
+ {
+ $config = config(OSPOS::class)->settings;
+ $last_used = (int)$config['last_used_work_order_number'] + 1;
- if($save)
- {
- $this->save(['last_used_work_order_number' => $last_used]);
- }
+ if($save)
+ {
+ $this->save(['last_used_work_order_number' => $last_used]);
+ }
- return $last_used;
- }
+ return $last_used;
+ }
}
diff --git a/app/Models/Attribute.php b/app/Models/Attribute.php
index 18708972b..2ccc2a156 100644
--- a/app/Models/Attribute.php
+++ b/app/Models/Attribute.php
@@ -17,1037 +17,1037 @@ use ReflectionClass;
*/
class Attribute extends Model
{
- protected $table = 'attribute_definitions';
- protected $primaryKey = 'definition_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [ //TODO: This model may not be well designed... The model accesses three different tables (attribute_definitions, attribute_links, attribute_values). Should that be more than one model? According to CodeIgniter, these are meant to model a single table https://codeigniter.com/user_guide/models/model.html#models
- 'definition_name',
- 'definition_type',
- 'definition_unit',
- 'definition_flags',
- 'deleted',
- 'attribute_id',
- 'definition_id',
- 'item_id',
- 'sale_id',
- 'receiving_id',
- 'attribute_value',
- 'attribute_date',
- 'attribute_decimal'
- ];
-
- public const SHOW_IN_ITEMS = 1; //TODO: These need to be moved to constants.php
- public const SHOW_IN_SALES = 2;
- public const SHOW_IN_RECEIVINGS = 4;
-
- /**
- * @return array
- */
- public static function get_definition_flags(): array
- {
- $class = new ReflectionClass(__CLASS__);
-
- return array_flip($class->getConstants());
- }
-
- /**
- * Determines if a given definition_id is an attribute
- */
- public function exists(int $definition_id, bool $deleted = false): bool
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('definition_id', $definition_id);
- $builder->where('deleted', $deleted);
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Returns whether an attribute_link row exists given an item_id and optionally a definition_id
- *
- * @param int $item_id ID of the item to check for an associated attribute.
- * @param int|bool $definition_id Attribute definition ID to check.
- * @return bool returns true if at least one attribute_link exists or false if no attributes exist for that item and attribute.
- */
- public function attributeLinkExists(?int $item_id, int|bool $definition_id = false): bool
- {
- $builder = $this->db->table('attribute_links');
- $builder->where('item_id', $item_id);
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
-
- if($definition_id)
- {
- $builder->where('definition_id', $definition_id);
- }
- else
- {
- $builder->where('definition_id IS NOT NULL');
- $builder->where('attribute_id', null);
- }
- $results = $builder->countAllResults();
- return $results > 0;
- }
-
- /**
- * Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does
- *
- * @param float|string $attributeValue The value to search for in the attribute values table.
- * @param string $definitionType The definition type which will dictate which column is searched.
- * @return int|bool The attribute ID of the found row or false if no attribute value was found.
- */
- public function attributeValueExists(float|string $attributeValue, string $definitionType = TEXT): bool|int
- {
- $config = config(OSPOS::class)->settings;
-
- switch($definitionType)
- {
- case DATE:
- $dataType = 'date';
- $attributeDateValue = DateTime::createFromFormat($config['dateformat'], $attributeValue);
- $attributeValue = $attributeDateValue ? $attributeDateValue->format('Y-m-d') : $attributeValue;
- break;
- case DECIMAL:
- $dataType = 'decimal';
- break;
- default:
- $dataType = 'value';
- break;
- }
-
- $builder = $this->db->table('attribute_values');
- $builder->select('attribute_id');
- $builder->where("attribute_$dataType", $attributeValue);
- $query = $builder->get();
-
- return $query->getNumRows() > 0
- ? $query->getRow()->attribute_id
- : false;
- }
-
- /**
- * Gets information about a particular attribute definition
- */
- public function getAttributeInfo(int $definition_id): object
- {
- $builder = $this->db->table('attribute_definitions AS definition');
- $builder->select('parent_definition.definition_name AS definition_group, definition.*');
- $builder->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left');
- $builder->where('definition.definition_id', $definition_id);
-
- $query = $builder->get();
-
- if($query->getNumRows() === 1)
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object, as $item_id is NOT an item
- $item_obj = new stdClass();
-
- //Get all the fields from attribute_definitions table
- foreach($this->db->getFieldNames('attribute_definitions') as $field)
- {
- $item_obj->$field = '';
- }
-
- return $item_obj;
- }
- }
-
- /**
- * Performs a search on attribute definitions
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'definition.definition_name', ?string $order = 'asc'): ResultInterface
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'definition.definition_name';
- if($order == null) $order = 'asc';
-
- $builder = $this->db->table('attribute_definitions AS definition');
- $builder->select('parent_definition.definition_name AS definition_group, definition.*');
- $builder->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left');
-
- $builder->groupStart();
- $builder->like('definition.definition_name', $search);
- $builder->orLike('definition.definition_type', $search);
- $builder->groupEnd();
-
- $builder->where('definition.deleted', 0);
- $builder->orderBy($sort, $order);
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
-
- /**
- * Gets all attributes connected to an item given the item_id
- *
- * @param int $item_id Item to retrieve attributes for.
- * @return array Attributes for the item.
- */
- public function get_attributes_by_item(int $item_id): array
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id');
- $builder->where('item_id', $item_id);
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
- $builder->where('deleted', 0);
- $builder->orderBy('definition_name', 'ASC');
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'definition_id');
- }
-
- /**
- * @param array|null $definition_ids
- * @return array
- */
- public function get_values_by_definitions(?array $definition_ids): array
- {
- if(count($definition_ids ? : []))
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->groupStart();
- $builder->whereIn('definition_fk', array_keys($definition_ids));
- $builder->orWhereIn('definition_id', array_keys($definition_ids));
- $builder->where('definition_type !=', GROUP);
- $builder->groupEnd();
-
- $builder->where('deleted', 0);
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'definition_id');
- }
-
- return [];
- }
-
- /**
- * @param string $attribute_type
- * @param int $definition_id
- * @return array
- */
- public function get_definitions_by_type(string $attribute_type, int $definition_id = NO_DEFINITION_ID): array
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('definition_type', $attribute_type);
- $builder->where('deleted', 0);
- $builder->where('definition_fk');
-
- if($definition_id != CATEGORY_DEFINITION_ID)
- {
- $builder->where('definition_id <>', $definition_id);
- }
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'definition_id', 'definition_name');
- }
-
- /**
- * @param int $definition_flags
- * @return array
- */
- public function get_definitions_by_flags(int $definition_flags): array
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where(new RawSql("definition_flags & $definition_flags")); //TODO: we need to heed CI warnings to escape properly
- $builder->where('deleted', 0);
- $builder->where('definition_type <>', GROUP);
- $builder->orderBy('definition_id');
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'definition_id', 'definition_name');
- }
-
- /**
- * Returns an array of attribute definition names and IDs
- *
- * @param boolean $groups If false does not return GROUP type attributes in the array
- * @return array Array containing definition IDs, attribute names and -1 index with the local language '[SELECT]' line.
- */
- public function get_definition_names(bool $groups = true): array
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('deleted', 0);
- $builder->orderBy('definition_name','ASC');
-
- if(!$groups)
- {
- $builder->whereNotIn('definition_type',GROUP);
- }
-
- $results = $builder->get()->getResultArray();
- $definition_name = [-1 => lang('Common.none_selected_text')];
-
- return $definition_name + $this->to_array($results, 'definition_id', 'definition_name');
- }
-
- /**
- * @param int $definition_id
- * @return array
- */
- public function get_definition_values(int $definition_id): array
- {
- $attribute_values = [];
-
- if($definition_id > 0 || $definition_id == CATEGORY_DEFINITION_ID)
- {
- $builder = $this->db->table('attribute_links');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->where('item_id', null);
- $builder->where('definition_id', $definition_id);
- $builder->orderBy('attribute_value','ASC');
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'attribute_id', 'attribute_value');
- }
-
- return $attribute_values;
- }
-
- /**
- * @param array $results
- * @param string $key
- * @param string $value
- * @return array
- */
- private function to_array(array $results, string $key, string $value = ''): array
- {
- return array_column(array_map(function($result) use ($key, $value){
- return [$result[$key], empty($value) ? $result : $result[$value]];
- }, $results), 1, 0);
- }
-
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('deleted', 0);
-
- return $builder->countAllResults();
- }
-
- /**
- * Get number of rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search)->getNumRows();
- }
-
- /**
- * @param int $definition_id
- * @param string $from
- * @param string $to
- * @return bool
- */
- private function check_data_validity(int $definition_id, string $from, string $to): bool
- {
- $success = false;
-
- if($from === TEXT)
- {
- $success = true;
-
- $builder = $this->db->table('attribute_values');
- $builder->distinct()->select('attribute_value');
- $builder->join('attribute_links', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->where('definition_id', $definition_id);
-
- foreach($builder->get()->getResult() as $attribute)
- {
- switch($to)
- {
- case DATE:
- $success = valid_date($attribute->attribute_value);
- break;
- case DECIMAL:
- $success = valid_decimal($attribute->attribute_value);
- break;
- }
-
- if(!$success)
- {
- $affected_items = $this->get_items_by_value($attribute->attribute_value, $definition_id);
- foreach($affected_items as $affected_item)
- {
- $affected_items[] = $affected_item['item_id'];
- }
-
- log_message('error', "Attribute_value: '$attribute->attribute_value' cannot be converted to $to. Affected Items: ". implode(',', $affected_items));
- unset($affected_items);
- }
- }
- }
- return $success;
- }
-
- /**
- * Returns all item_ids with a specific attribute_value and attribute_definition
- *
- * @param string $attribute_value Attribute value to be searched
- * @param int $definition_id ID of the specific attribute to return items for.
- * @return array Item_ids matching the given parameters
- */
- private function get_items_by_value(string $attribute_value, int $definition_id): array
- {
- $builder = $this->db->table('attribute_links');
- $builder->select('item_id');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->where('definition_id', $definition_id);
- $builder->where('attribute_value', $attribute_value);
-
- return $builder->get()->getResultArray();
- }
-
- /**
- * Converts data in attribute_values and attribute_links tables associated with the conversion of one attribute type to another.
- *
- * @param int $definition_id
- * @param string $from_type
- * @param string $to_type
- * @return boolean
- */
- private function convert_definition_data(int $definition_id, string $from_type, string $to_type): bool
- {
- $success = false;
-
- if($from_type === TEXT)
- {
- if(in_array($to_type, [DATE, DECIMAL], true))
- {
- if($this->check_data_validity($definition_id, $from_type, $to_type))
- {
- $attributes_to_convert = $this->get_attributes_by_definition($definition_id);
- $success = $this->attribute_cleanup($attributes_to_convert, $definition_id, $to_type);
- }
- }
- else if($to_type === DROPDOWN)
- {
- $success = true;
- }
- else if($to_type === CHECKBOX) //TODO: duplicated code.
- {
- $checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
-
- $this->db->transStart();
-
- $query = 'UPDATE '. $this->db->prefixTable('attribute_links') .' links ';
- $query .= 'JOIN '. $this->db->prefixTable('attribute_values') .' vals ';
- $query .= 'ON vals.attribute_id = links.attribute_id ';
- $query .= "SET links.attribute_id = IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
- $query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
- $success = $this->db->query($query);
-
- //TODO: In order to convert this query to QueryBuilder, CI needs to fix their issue with JOINs being ignored in UPDATE queries and ideally fix their issue with backticks and dbprefix not being prepended when SQL functions are used.
- //Replace the code above with the code below when it's fixed.
-// $db_prefix = $this->db->getPrefix();
-// $builder = $this->db->table('attribute_links');
-// $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'inner');
-// $builder->set('attribute_links.attribute_id', "IF((`$db_prefix" . "attribute_values`.`attribute_value` IN('false','0','') OR (`". $db_prefix ."attribute_values`.`attribute_value` IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1])", false);
-// $builder->where('attribute_links.definition_id', $definition_id);
-// $success = $builder->update();
-
- $this->db->transComplete();
- }
- }
- else if($from_type === DROPDOWN)
- {
- if(in_array($to_type, [TEXT, CHECKBOX], true))
- {
- if($to_type === CHECKBOX) //TODO: Duplicated code.
- {
- $checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
-
- $this->db->transStart();
-
- $query = 'UPDATE '. $this->db->prefixTable('attribute_links') .' links ';
- $query .= 'JOIN '. $this->db->prefixTable('attribute_values') .' vals ';
- $query .= 'ON vals.attribute_id = links.attribute_id ';
- $query .= "SET links.attribute_id = IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
- $query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
- $success = $this->db->query($query);
-
- //TODO: Same issue here. Replace the code above with the code below when it's fixed.
-// $builder = $this->db->table('attribute_links');
-// $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'inner');
-// $builder->set('attribute_links.attribute_id', "IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1])", false);
-// $builder->where('definition_id', $definition_id);
-// $success = $builder->update();
+ protected $table = 'attribute_definitions';
+ protected $primaryKey = 'definition_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [ //TODO: This model may not be well designed... The model accesses three different tables (attribute_definitions, attribute_links, attribute_values). Should that be more than one model? According to CodeIgniter, these are meant to model a single table https://codeigniter.com/user_guide/models/model.html#models
+ 'definition_name',
+ 'definition_type',
+ 'definition_unit',
+ 'definition_flags',
+ 'deleted',
+ 'attribute_id',
+ 'definition_id',
+ 'item_id',
+ 'sale_id',
+ 'receiving_id',
+ 'attribute_value',
+ 'attribute_date',
+ 'attribute_decimal'
+ ];
+
+ public const SHOW_IN_ITEMS = 1; //TODO: These need to be moved to constants.php
+ public const SHOW_IN_SALES = 2;
+ public const SHOW_IN_RECEIVINGS = 4;
+
+ /**
+ * @return array
+ */
+ public static function get_definition_flags(): array
+ {
+ $class = new ReflectionClass(__CLASS__);
+
+ return array_flip($class->getConstants());
+ }
+
+ /**
+ * Determines if a given definition_id is an attribute
+ */
+ public function exists(int $definition_id, bool $deleted = false): bool
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('definition_id', $definition_id);
+ $builder->where('deleted', $deleted);
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Returns whether an attribute_link row exists given an item_id and optionally a definition_id
+ *
+ * @param int $item_id ID of the item to check for an associated attribute.
+ * @param int|bool $definition_id Attribute definition ID to check.
+ * @return bool returns true if at least one attribute_link exists or false if no attributes exist for that item and attribute.
+ */
+ public function attributeLinkExists(?int $item_id, int|bool $definition_id = false): bool
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->where('item_id', $item_id);
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+
+ if($definition_id)
+ {
+ $builder->where('definition_id', $definition_id);
+ }
+ else
+ {
+ $builder->where('definition_id IS NOT NULL');
+ $builder->where('attribute_id', null);
+ }
+ $results = $builder->countAllResults();
+ return $results > 0;
+ }
+
+ /**
+ * Determines if a given attribute_value exists in the attribute_values table and returns the attribute_id if it does
+ *
+ * @param float|string $attributeValue The value to search for in the attribute values table.
+ * @param string $definitionType The definition type which will dictate which column is searched.
+ * @return int|bool The attribute ID of the found row or false if no attribute value was found.
+ */
+ public function attributeValueExists(float|string $attributeValue, string $definitionType = TEXT): bool|int
+ {
+ $config = config(OSPOS::class)->settings;
+
+ switch($definitionType)
+ {
+ case DATE:
+ $dataType = 'date';
+ $attributeDateValue = DateTime::createFromFormat($config['dateformat'], $attributeValue);
+ $attributeValue = $attributeDateValue ? $attributeDateValue->format('Y-m-d') : $attributeValue;
+ break;
+ case DECIMAL:
+ $dataType = 'decimal';
+ break;
+ default:
+ $dataType = 'value';
+ break;
+ }
+
+ $builder = $this->db->table('attribute_values');
+ $builder->select('attribute_id');
+ $builder->where("attribute_$dataType", $attributeValue);
+ $query = $builder->get();
+
+ return $query->getNumRows() > 0
+ ? $query->getRow()->attribute_id
+ : false;
+ }
+
+ /**
+ * Gets information about a particular attribute definition
+ */
+ public function getAttributeInfo(int $definition_id): object
+ {
+ $builder = $this->db->table('attribute_definitions AS definition');
+ $builder->select('parent_definition.definition_name AS definition_group, definition.*');
+ $builder->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left');
+ $builder->where('definition.definition_id', $definition_id);
+
+ $query = $builder->get();
+
+ if($query->getNumRows() === 1)
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object, as $item_id is NOT an item
+ $item_obj = new stdClass();
+
+ //Get all the fields from attribute_definitions table
+ foreach($this->db->getFieldNames('attribute_definitions') as $field)
+ {
+ $item_obj->$field = '';
+ }
+
+ return $item_obj;
+ }
+ }
+
+ /**
+ * Performs a search on attribute definitions
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'definition.definition_name', ?string $order = 'asc'): ResultInterface
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'definition.definition_name';
+ if($order == null) $order = 'asc';
+
+ $builder = $this->db->table('attribute_definitions AS definition');
+ $builder->select('parent_definition.definition_name AS definition_group, definition.*');
+ $builder->join('attribute_definitions AS parent_definition', 'parent_definition.definition_id = definition.definition_fk', 'left');
+
+ $builder->groupStart();
+ $builder->like('definition.definition_name', $search);
+ $builder->orLike('definition.definition_type', $search);
+ $builder->groupEnd();
+
+ $builder->where('definition.deleted', 0);
+ $builder->orderBy($sort, $order);
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets all attributes connected to an item given the item_id
+ *
+ * @param int $item_id Item to retrieve attributes for.
+ * @return array Attributes for the item.
+ */
+ public function get_attributes_by_item(int $item_id): array
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id');
+ $builder->where('item_id', $item_id);
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+ $builder->where('deleted', 0);
+ $builder->orderBy('definition_name', 'ASC');
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'definition_id');
+ }
+
+ /**
+ * @param array|null $definition_ids
+ * @return array
+ */
+ public function get_values_by_definitions(?array $definition_ids): array
+ {
+ if(count($definition_ids ? : []))
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->groupStart();
+ $builder->whereIn('definition_fk', array_keys($definition_ids));
+ $builder->orWhereIn('definition_id', array_keys($definition_ids));
+ $builder->where('definition_type !=', GROUP);
+ $builder->groupEnd();
+
+ $builder->where('deleted', 0);
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'definition_id');
+ }
+
+ return [];
+ }
+
+ /**
+ * @param string $attribute_type
+ * @param int $definition_id
+ * @return array
+ */
+ public function get_definitions_by_type(string $attribute_type, int $definition_id = NO_DEFINITION_ID): array
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('definition_type', $attribute_type);
+ $builder->where('deleted', 0);
+ $builder->where('definition_fk');
+
+ if($definition_id != CATEGORY_DEFINITION_ID)
+ {
+ $builder->where('definition_id <>', $definition_id);
+ }
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'definition_id', 'definition_name');
+ }
+
+ /**
+ * @param int $definition_flags
+ * @return array
+ */
+ public function get_definitions_by_flags(int $definition_flags): array
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where(new RawSql("definition_flags & $definition_flags")); //TODO: we need to heed CI warnings to escape properly
+ $builder->where('deleted', 0);
+ $builder->where('definition_type <>', GROUP);
+ $builder->orderBy('definition_id');
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'definition_id', 'definition_name');
+ }
+
+ /**
+ * Returns an array of attribute definition names and IDs
+ *
+ * @param boolean $groups If false does not return GROUP type attributes in the array
+ * @return array Array containing definition IDs, attribute names and -1 index with the local language '[SELECT]' line.
+ */
+ public function get_definition_names(bool $groups = true): array
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('deleted', 0);
+ $builder->orderBy('definition_name','ASC');
+
+ if(!$groups)
+ {
+ $builder->whereNotIn('definition_type',GROUP);
+ }
+
+ $results = $builder->get()->getResultArray();
+ $definition_name = [-1 => lang('Common.none_selected_text')];
+
+ return $definition_name + $this->to_array($results, 'definition_id', 'definition_name');
+ }
+
+ /**
+ * @param int $definition_id
+ * @return array
+ */
+ public function get_definition_values(int $definition_id): array
+ {
+ $attribute_values = [];
+
+ if($definition_id > 0 || $definition_id == CATEGORY_DEFINITION_ID)
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->where('item_id', null);
+ $builder->where('definition_id', $definition_id);
+ $builder->orderBy('attribute_value','ASC');
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'attribute_id', 'attribute_value');
+ }
+
+ return $attribute_values;
+ }
+
+ /**
+ * @param array $results
+ * @param string $key
+ * @param string $value
+ * @return array
+ */
+ private function to_array(array $results, string $key, string $value = ''): array
+ {
+ return array_column(array_map(function($result) use ($key, $value){
+ return [$result[$key], empty($value) ? $result : $result[$value]];
+ }, $results), 1, 0);
+ }
+
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('deleted', 0);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Get number of rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search)->getNumRows();
+ }
+
+ /**
+ * @param int $definition_id
+ * @param string $from
+ * @param string $to
+ * @return bool
+ */
+ private function check_data_validity(int $definition_id, string $from, string $to): bool
+ {
+ $success = false;
+
+ if($from === TEXT)
+ {
+ $success = true;
+
+ $builder = $this->db->table('attribute_values');
+ $builder->distinct()->select('attribute_value');
+ $builder->join('attribute_links', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->where('definition_id', $definition_id);
+
+ foreach($builder->get()->getResult() as $attribute)
+ {
+ switch($to)
+ {
+ case DATE:
+ $success = valid_date($attribute->attribute_value);
+ break;
+ case DECIMAL:
+ $success = valid_decimal($attribute->attribute_value);
+ break;
+ }
+
+ if(!$success)
+ {
+ $affected_items = $this->get_items_by_value($attribute->attribute_value, $definition_id);
+ foreach($affected_items as $affected_item)
+ {
+ $affected_items[] = $affected_item['item_id'];
+ }
+
+ log_message('error', "Attribute_value: '$attribute->attribute_value' cannot be converted to $to. Affected Items: ". implode(',', $affected_items));
+ unset($affected_items);
+ }
+ }
+ }
+ return $success;
+ }
+
+ /**
+ * Returns all item_ids with a specific attribute_value and attribute_definition
+ *
+ * @param string $attribute_value Attribute value to be searched
+ * @param int $definition_id ID of the specific attribute to return items for.
+ * @return array Item_ids matching the given parameters
+ */
+ private function get_items_by_value(string $attribute_value, int $definition_id): array
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->select('item_id');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->where('definition_id', $definition_id);
+ $builder->where('attribute_value', $attribute_value);
+
+ return $builder->get()->getResultArray();
+ }
+
+ /**
+ * Converts data in attribute_values and attribute_links tables associated with the conversion of one attribute type to another.
+ *
+ * @param int $definition_id
+ * @param string $from_type
+ * @param string $to_type
+ * @return boolean
+ */
+ private function convert_definition_data(int $definition_id, string $from_type, string $to_type): bool
+ {
+ $success = false;
+
+ if($from_type === TEXT)
+ {
+ if(in_array($to_type, [DATE, DECIMAL], true))
+ {
+ if($this->check_data_validity($definition_id, $from_type, $to_type))
+ {
+ $attributes_to_convert = $this->get_attributes_by_definition($definition_id);
+ $success = $this->attribute_cleanup($attributes_to_convert, $definition_id, $to_type);
+ }
+ }
+ else if($to_type === DROPDOWN)
+ {
+ $success = true;
+ }
+ else if($to_type === CHECKBOX) //TODO: duplicated code.
+ {
+ $checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
+
+ $this->db->transStart();
+
+ $query = 'UPDATE '. $this->db->prefixTable('attribute_links') .' links ';
+ $query .= 'JOIN '. $this->db->prefixTable('attribute_values') .' vals ';
+ $query .= 'ON vals.attribute_id = links.attribute_id ';
+ $query .= "SET links.attribute_id = IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
+ $query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
+ $success = $this->db->query($query);
+
+ //TODO: In order to convert this query to QueryBuilder, CI needs to fix their issue with JOINs being ignored in UPDATE queries and ideally fix their issue with backticks and dbprefix not being prepended when SQL functions are used.
+ //Replace the code above with the code below when it's fixed.
+// $db_prefix = $this->db->getPrefix();
+// $builder = $this->db->table('attribute_links');
+// $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'inner');
+// $builder->set('attribute_links.attribute_id', "IF((`$db_prefix" . "attribute_values`.`attribute_value` IN('false','0','') OR (`". $db_prefix ."attribute_values`.`attribute_value` IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1])", false);
+// $builder->where('attribute_links.definition_id', $definition_id);
+// $success = $builder->update();
+
+ $this->db->transComplete();
+ }
+ }
+ else if($from_type === DROPDOWN)
+ {
+ if(in_array($to_type, [TEXT, CHECKBOX], true))
+ {
+ if($to_type === CHECKBOX) //TODO: Duplicated code.
+ {
+ $checkbox_attribute_values = $this->checkbox_attribute_values($definition_id);
+
+ $this->db->transStart();
+
+ $query = 'UPDATE '. $this->db->prefixTable('attribute_links') .' links ';
+ $query .= 'JOIN '. $this->db->prefixTable('attribute_values') .' vals ';
+ $query .= 'ON vals.attribute_id = links.attribute_id ';
+ $query .= "SET links.attribute_id = IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1]) ";
+ $query .= 'WHERE definition_id = '. $this->db->escape($definition_id);
+ $success = $this->db->query($query);
+
+ //TODO: Same issue here. Replace the code above with the code below when it's fixed.
+// $builder = $this->db->table('attribute_links');
+// $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'inner');
+// $builder->set('attribute_links.attribute_id', "IF((attribute_value IN('false','0','') OR (attribute_value IS NULL)), $checkbox_attribute_values[0], $checkbox_attribute_values[1])", false);
+// $builder->where('definition_id', $definition_id);
+// $success = $builder->update();
//
-// $this->db->transComplete();
- }
- }
- }
- else
- {
- $success = true;
- }
-
- $this->delete_orphaned_links($definition_id);
- $this->delete_orphaned_values();
- return $success;
- }
-
- /**
- * @param int $definition_id
- * @return array
- */
- private function checkbox_attribute_values(int $definition_id): array
- {
- $zero_attribute_id = $this->attributeValueExists('0');
- $one_attribute_id = $this->attributeValueExists('1');
-
- if(!$zero_attribute_id)
- {
- $zero_attribute_id = $this->saveAttributeValue('0', $definition_id, false, false, CHECKBOX);
- }
-
- if(!$one_attribute_id)
- {
- $one_attribute_id = $this->saveAttributeValue('1', $definition_id, false, false, CHECKBOX);
- $one_attribute_id = $this->saveAttributeValue('1', $definition_id, false, false, CHECKBOX);
- }
-
- return [$zero_attribute_id, $one_attribute_id];
- }
-
- /**
- * Inserts or updates a definition
- */
- public function save_definition(array &$definition_data, int $definition_id = NO_DEFINITION_ID): bool
- {
- $this->db->transStart();
-
- //Definition doesn't exist
- if($definition_id === NO_DEFINITION_ID || !$this->exists($definition_id))
- {
- if($this->exists($definition_id,true))
- {
- $success = $this->undelete($definition_id);
- }
- else
- {
- $builder = $this->db->table('attribute_definitions');
- $success = $builder->insert($definition_data);
- $definition_data['definition_id'] = $this->db->insertID();
- }
- }
-
- //Definition already exists
- else
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->select('definition_type');
- $builder->where('definition_id', $definition_id);
- $builder->where('deleted', ACTIVE);
- $query = $builder->get();
- $row = $query->getRow();
-
- $from_definition_type = $row->definition_type;
- $to_definition_type = $definition_data['definition_type'];
-
- //Update the definition values
- $builder->where('definition_id', $definition_id);
-
- $success = $builder->update($definition_data);
- $definition_data['definition_id'] = $definition_id;
-
- if($from_definition_type !== $to_definition_type)
- {
- if(!$this->convert_definition_data($definition_id, $from_definition_type, $to_definition_type))
- {
- return false;
- }
- }
- }
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * @param string $definition_name
- * @param $definition_type
- * @return array
- */
- public function get_definition_by_name(string $definition_name, $definition_type = false): array
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('definition_name', $definition_name);
- $builder->where('deleted', 0);
-
- if($definition_type)
- {
- $builder->where('definition_type', $definition_type);
- }
-
- return $builder->get()->getResultArray();
- }
-
- /**
- * Inserts or updates an attribute link
- *
- * @param int $itemId
- * @param int $definitionId
- * @param int $attributeId
- * @return bool True if the attribute link was saved successfully, false otherwise.
- */
- public function saveAttributeLink(int $itemId, int $definitionId, int $attributeId): bool
- {
- $this->db->transStart();
-
- $builder = $this->db->table('attribute_links');
-
- if($this->attributeLinkExists($itemId, $definitionId))
- {
- $builder->set(['attribute_id' => $attributeId]);
- $builder->where('definition_id', $definitionId);
- $builder->where('item_id', $itemId);
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
- $builder->update();
- }
- else
- {
- $data = [
- 'attribute_id' => $attributeId,
- 'item_id' => $itemId,
- 'definition_id' => $definitionId
- ];
- $builder->insert($data);
- }
-
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- /**
- * @param int $item_id
- * @param int|bool $definition_id
- * @return bool
- */
- public function deleteAttributeLinks(int $item_id, int|bool $definition_id = false): bool
- {
- $delete_data = ['item_id' => $item_id];
-
- //Exclude rows where sale_id or receiving_id has a value
- $builder = $this->db->table('attribute_links');
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
-
- if(!empty($definition_id))
- {
- $delete_data += ['definition_id' => $definition_id];
- }
-
- return $builder->delete($delete_data);
- }
-
- /**
- * @param int $item_id
- * @param int|null $definition_id
- * @return object|null
- */
- public function get_link_value(int $item_id, ?int $definition_id): ?object
- {
- $builder = $this->db->table('attribute_links');
- $builder->where('item_id', $item_id);
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
- if($definition_id != null)
- {
- $builder->where('definition_id', $definition_id);
- }
-
- return $builder->get()->getRowObject();
- }
-
- /**
- * @param int $item_id
- * @param string $sale_receiving_fk
- * @param int|null $id
- * @param int|null $definition_flags
- * @return ResultInterface
- */
- public function get_link_values(int $item_id, string $sale_receiving_fk, ?int $id, ?int $definition_flags): ResultInterface
- {
- $format = $this->db->escape(dateformat_mysql());
-
- $builder = $this->db->table('attribute_links');
- $builder->select("GROUP_CONCAT(attribute_value SEPARATOR ', ') AS attribute_values");
- $builder->select("GROUP_CONCAT(DATE_FORMAT(attribute_date, $format) SEPARATOR ', ') AS attribute_dtvalues");
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
- $builder->where('definition_type <>', GROUP);
- $builder->where('deleted', ACTIVE);
- $builder->where('item_id', $item_id);
-
- if(!empty($id))
- {
- $builder->where($sale_receiving_fk, $id);
- }
- else
- {
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
- }
-
- if(!empty($id))
- {
- $builder->where(new RawSql("definition_flags & $definition_flags"));
- }
- return $builder->get();
- }
-
- /**
- * @param int $item_id
- * @param int $definition_id
- * @return object|null
- */
- public function get_attribute_value(int $item_id, int $definition_id): ?object
- {
- $builder = $this->db->table('attribute_values');
- $builder->join('attribute_links', 'attribute_links.attribute_id = attribute_values.attribute_id');
- $builder->where('item_id', $item_id);
- $builder->where('sale_id', null);
- $builder->where('receiving_id', null);
- $builder->where('definition_id', $definition_id);
- $query = $builder->get();
-
- if($query->getNumRows() == 1)
- {
- return $query->getRow();
- }
-
- return $this->getEmptyObject('attribute_values');
- }
-
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
-
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
-
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
-
- return $empty_obj;
- }
-
-
- /**
- * @param int $item_id
- * @return array
- */
- public function get_attribute_values(int $item_id): array //TODO: Is this function used anywhere in the code?
- {
- $builder = $this->db->table('attribute_links');
- $builder->select('attribute_values.attribute_value, attribute_values.attribute_decimal, attribute_values.attribute_date, attribute_links.definition_id');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
- $builder->where('item_id', $item_id);
-
- $results = $builder->get()->getResultArray();
-
- return $this->to_array($results, 'definition_id');
- }
-
- /**
- * @param int $item_id
- * @param string $sale_receiving_fk
- * @param int $id
- * @return void
- */
- public function copy_attribute_links(int $item_id, string $sale_receiving_fk, int $id): void
- {
- $query = 'SELECT ' . $this->db->escape($item_id) . ', definition_id, attribute_id, ' . $this->db->escape($id);
- $query .= ' FROM ' . $this->db->prefixTable('attribute_links');
- $query .= ' WHERE item_id = ' . $this->db->escape($item_id);
- $query .=' AND sale_id IS NULL AND receiving_id IS NULL';
-
- $builder = $this->db->table('attribute_links');
- $builder->ignore(true)->setQueryAsData(new RawSql($query), null, 'item_id, definition_id, attribute_id, '. $sale_receiving_fk )->insertBatch();
- }
-
- /**
- * Gets search suggestions (attribute values) for a specific attribute definition given a search term and definition_id
- *
- * @param int $definition_id
- * @param string $term
- * @return array
- */
- public function get_suggestions(int $definition_id, string $term): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('attribute_definitions AS definition');
- $builder->distinct()->select('attribute_value, attribute_values.attribute_id');
- $builder->join('attribute_links', 'attribute_links.definition_id = definition.definition_id');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->like('attribute_value', $term);
- $builder->where('deleted', ACTIVE);
- $builder->where('definition.definition_id', $definition_id);
- $builder->orderBy('attribute_value','ASC');
-
- foreach($builder->get()->getResult('array') as $suggestion)
- {
- $suggestions[] = ['value' => $suggestion['attribute_id'], 'label' => $suggestion['attribute_value']];
- }
-
- return $suggestions;
- }
-
- /**
- * @param string $attribute_value
- * @param int $definition_id
- * @param $item_id
- * @param $attribute_id
- * @param string $definition_type
- * @return int
- */
- public function saveAttributeValue(string $attribute_value, int $definition_id, int|bool $item_id = false, int|bool $attribute_id = false, string $definition_type = DROPDOWN): int
- {
- $config = config(OSPOS::class)->settings;
-
- $this->db->transStart();
-
- switch($definition_type)
- {
- case DATE:
- $data_type = 'date';
- $attribute_date_value = DateTime::createFromFormat($config['dateformat'], $attribute_value);
- $attribute_value = $attribute_date_value->format('Y-m-d');
- break;
- case DECIMAL:
- $data_type = 'decimal';
- break;
- default:
- $data_type = 'value';
- break;
- }
-
- //New Attribute
- if(empty($attribute_id) || empty($item_id))
- {
- $attribute_id = $this->attributeValueExists($attribute_value, $definition_type);
-
- if(!$attribute_id)
- {
-
- $builder = $this->db->table('attribute_values');
- $builder->set(["attribute_$data_type" => $attribute_value]);
- $builder->insert();
-
- $attribute_id = $this->db->insertID();
- }
-
- $data = [
- 'attribute_id' => empty($attribute_id) ? null : $attribute_id,
- 'item_id' => empty($item_id) ? null : $item_id,
- 'definition_id' => $definition_id
- ];
-
- $builder = $this->db->table('attribute_links');
- $builder->set($data);
- $builder->insert();
- }
- //Existing Attribute
- else
- {
- $builder = $this->db->table('attribute_values');
- $builder->set(["attribute_$data_type" => $attribute_value]);
- $builder->where('attribute_id', $attribute_id);
- $builder->update();
- }
-
- $this->db->transComplete();
-
- return $attribute_id;
- }
-
- /**
- * @param string $attribute_value
- * @param int $definition_id
- * @return bool
- */
- public function delete_value(string $attribute_value, int $definition_id): bool
- {
- //QueryBuilder does not support multi-table delete.
- $query = 'DELETE atrv, atrl ';
- $query .= 'FROM ' . $this->db->prefixTable('attribute_values') . ' atrv, ' . $this->db->prefixTable('attribute_links') . ' atrl ';
- $query .= 'WHERE atrl.attribute_id = atrv.attribute_id AND atrv.attribute_value = ' . $this->db->escape($attribute_value);
- $query .= ' AND atrl.definition_id = ' . $this->db->escape($definition_id);
- return $this->db->query($query);
- }
-
- /**
- * Deletes an Attribute definition from the database and associated column in the items_import.csv
- *
- * @param int $definition_id Attribute definition ID to remove.
- * @return boolean true if successful and false if there is a failure
- */
- public function delete_definition(int $definition_id): bool
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('definition_id', $definition_id);
-
- return $builder->update(['deleted' => DELETED]);
- }
-
- /**
- * @param array $definition_ids
- * @return bool
- */
- public function delete_definition_list(array $definition_ids): bool
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->whereIn('definition_id', $definition_ids);
-
- return $builder->update(['deleted' => DELETED]);
- }
-
- /**
- * Deletes any attribute_links for a specific definition that do not have an item_id associated with them and are not DROPDOWN types
- *
- * @param int $definition_id
- * @return boolean true is returned if the delete was successful or false if there were any failures
- */
- public function delete_orphaned_links(int $definition_id): bool
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->select('definition_type');
- $builder->where('definition_id', $definition_id);
-
- $definition = $builder->get()->getRow();
-
- if($definition->definition_type != DROPDOWN)
- {
- $this->db->transStart();
-
- $builder = $this->db->table('attribute_links');
- $builder->where('item_id', null);
- $builder->where('definition_id', $definition_id);
- $builder->delete();
-
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- return true; //Return true when definition_type is DROPDOWN
- }
-
- /**
- * Deletes any orphaned values that do not have associated links
- *
- * @return boolean true is returned if the delete was successful or false if there were any failures
- */
- public function delete_orphaned_values(): bool
- {
- $subquery = $this->db->table('attribute_links')
- ->distinct()
- ->select('attribute_id');
-
- $this->db->transStart();
-
- $builder = $this->db->table('attribute_values');
- $builder->whereNotIn('attribute_id', $subquery, false);
- $builder->delete();
-
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- /**
- * Undeletes one attribute definition
- */
- public function undelete(int $definition_id): bool
- {
- $builder = $this->db->table('attribute_definitions');
- $builder->where('definition_id', $definition_id);
-
- return $builder->update(['deleted' => ACTIVE]);
- }
-
- /**
- *
- * @param array $attributes attributes that need to be fixed
- * @param int $definition_id
- * @param string $definition_type This dictates what column should be populated in any new attribute_values that are created
- * @return bool
- */
- public function attribute_cleanup(array $attributes, int $definition_id, string $definition_type): bool
- {
- $this->db->transBegin();
-
- foreach($attributes as $attribute)
- {
- $new_attribute_id = $this->saveAttributeValue($attribute['attribute_value'], $definition_id, false, $attribute['attribute_id'], $definition_type);
-
- if(!$this->saveAttributeLink($attribute['item_id'], $definition_id, $new_attribute_id))
- {
- log_message('error', 'Transaction failed');
- $this->db->transRollback();
- return false;
- }
- }
- $success = $this->delete_orphaned_links($definition_id);
-
- $this->db->transCommit();
- return $success;
- }
-
- /**
- * Returns all attribute_ids and item_ids assigned to that definition_id
- *
- * @param int $definition_id
- * @return array All attribute_id and item_id pairs in the attribute_links table with that attribute definition_id
- */
- public function get_attributes_by_definition(int $definition_id): array
- {
- $builder = $this->db->table('attribute_links');
- $builder->select('attribute_links.attribute_id, item_id, attribute_value, attribute_decimal, attribute_date');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
- $builder->where('definition_id', $definition_id);
-
- return $builder->get()->getResultArray();
- }
+// $this->db->transComplete();
+ }
+ }
+ }
+ else
+ {
+ $success = true;
+ }
+
+ $this->delete_orphaned_links($definition_id);
+ $this->delete_orphaned_values();
+ return $success;
+ }
+
+ /**
+ * @param int $definition_id
+ * @return array
+ */
+ private function checkbox_attribute_values(int $definition_id): array
+ {
+ $zero_attribute_id = $this->attributeValueExists('0');
+ $one_attribute_id = $this->attributeValueExists('1');
+
+ if(!$zero_attribute_id)
+ {
+ $zero_attribute_id = $this->saveAttributeValue('0', $definition_id, false, false, CHECKBOX);
+ }
+
+ if(!$one_attribute_id)
+ {
+ $one_attribute_id = $this->saveAttributeValue('1', $definition_id, false, false, CHECKBOX);
+ $one_attribute_id = $this->saveAttributeValue('1', $definition_id, false, false, CHECKBOX);
+ }
+
+ return [$zero_attribute_id, $one_attribute_id];
+ }
+
+ /**
+ * Inserts or updates a definition
+ */
+ public function save_definition(array &$definition_data, int $definition_id = NO_DEFINITION_ID): bool
+ {
+ $this->db->transStart();
+
+ //Definition doesn't exist
+ if($definition_id === NO_DEFINITION_ID || !$this->exists($definition_id))
+ {
+ if($this->exists($definition_id,true))
+ {
+ $success = $this->undelete($definition_id);
+ }
+ else
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $success = $builder->insert($definition_data);
+ $definition_data['definition_id'] = $this->db->insertID();
+ }
+ }
+
+ //Definition already exists
+ else
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->select('definition_type');
+ $builder->where('definition_id', $definition_id);
+ $builder->where('deleted', ACTIVE);
+ $query = $builder->get();
+ $row = $query->getRow();
+
+ $from_definition_type = $row->definition_type;
+ $to_definition_type = $definition_data['definition_type'];
+
+ //Update the definition values
+ $builder->where('definition_id', $definition_id);
+
+ $success = $builder->update($definition_data);
+ $definition_data['definition_id'] = $definition_id;
+
+ if($from_definition_type !== $to_definition_type)
+ {
+ if(!$this->convert_definition_data($definition_id, $from_definition_type, $to_definition_type))
+ {
+ return false;
+ }
+ }
+ }
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * @param string $definition_name
+ * @param $definition_type
+ * @return array
+ */
+ public function get_definition_by_name(string $definition_name, $definition_type = false): array
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('definition_name', $definition_name);
+ $builder->where('deleted', 0);
+
+ if($definition_type)
+ {
+ $builder->where('definition_type', $definition_type);
+ }
+
+ return $builder->get()->getResultArray();
+ }
+
+ /**
+ * Inserts or updates an attribute link
+ *
+ * @param int $itemId
+ * @param int $definitionId
+ * @param int $attributeId
+ * @return bool True if the attribute link was saved successfully, false otherwise.
+ */
+ public function saveAttributeLink(int $itemId, int $definitionId, int $attributeId): bool
+ {
+ $this->db->transStart();
+
+ $builder = $this->db->table('attribute_links');
+
+ if($this->attributeLinkExists($itemId, $definitionId))
+ {
+ $builder->set(['attribute_id' => $attributeId]);
+ $builder->where('definition_id', $definitionId);
+ $builder->where('item_id', $itemId);
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+ $builder->update();
+ }
+ else
+ {
+ $data = [
+ 'attribute_id' => $attributeId,
+ 'item_id' => $itemId,
+ 'definition_id' => $definitionId
+ ];
+ $builder->insert($data);
+ }
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ /**
+ * @param int $item_id
+ * @param int|bool $definition_id
+ * @return bool
+ */
+ public function deleteAttributeLinks(int $item_id, int|bool $definition_id = false): bool
+ {
+ $delete_data = ['item_id' => $item_id];
+
+ //Exclude rows where sale_id or receiving_id has a value
+ $builder = $this->db->table('attribute_links');
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+
+ if(!empty($definition_id))
+ {
+ $delete_data += ['definition_id' => $definition_id];
+ }
+
+ return $builder->delete($delete_data);
+ }
+
+ /**
+ * @param int $item_id
+ * @param int|null $definition_id
+ * @return object|null
+ */
+ public function get_link_value(int $item_id, ?int $definition_id): ?object
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->where('item_id', $item_id);
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+ if($definition_id != null)
+ {
+ $builder->where('definition_id', $definition_id);
+ }
+
+ return $builder->get()->getRowObject();
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $sale_receiving_fk
+ * @param int|null $id
+ * @param int|null $definition_flags
+ * @return ResultInterface
+ */
+ public function get_link_values(int $item_id, string $sale_receiving_fk, ?int $id, ?int $definition_flags): ResultInterface
+ {
+ $format = $this->db->escape(dateformat_mysql());
+
+ $builder = $this->db->table('attribute_links');
+ $builder->select("GROUP_CONCAT(attribute_value SEPARATOR ', ') AS attribute_values");
+ $builder->select("GROUP_CONCAT(DATE_FORMAT(attribute_date, $format) SEPARATOR ', ') AS attribute_dtvalues");
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
+ $builder->where('definition_type <>', GROUP);
+ $builder->where('deleted', ACTIVE);
+ $builder->where('item_id', $item_id);
+
+ if(!empty($id))
+ {
+ $builder->where($sale_receiving_fk, $id);
+ }
+ else
+ {
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+ }
+
+ if(!empty($id))
+ {
+ $builder->where(new RawSql("definition_flags & $definition_flags"));
+ }
+ return $builder->get();
+ }
+
+ /**
+ * @param int $item_id
+ * @param int $definition_id
+ * @return object|null
+ */
+ public function get_attribute_value(int $item_id, int $definition_id): ?object
+ {
+ $builder = $this->db->table('attribute_values');
+ $builder->join('attribute_links', 'attribute_links.attribute_id = attribute_values.attribute_id');
+ $builder->where('item_id', $item_id);
+ $builder->where('sale_id', null);
+ $builder->where('receiving_id', null);
+ $builder->where('definition_id', $definition_id);
+ $query = $builder->get();
+
+ if($query->getNumRows() == 1)
+ {
+ return $query->getRow();
+ }
+
+ return $this->getEmptyObject('attribute_values');
+ }
+
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
+
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
+
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
+
+ return $empty_obj;
+ }
+
+
+ /**
+ * @param int $item_id
+ * @return array
+ */
+ public function get_attribute_values(int $item_id): array //TODO: Is this function used anywhere in the code?
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->select('attribute_values.attribute_value, attribute_values.attribute_decimal, attribute_values.attribute_date, attribute_links.definition_id');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
+ $builder->where('item_id', $item_id);
+
+ $results = $builder->get()->getResultArray();
+
+ return $this->to_array($results, 'definition_id');
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $sale_receiving_fk
+ * @param int $id
+ * @return void
+ */
+ public function copy_attribute_links(int $item_id, string $sale_receiving_fk, int $id): void
+ {
+ $query = 'SELECT ' . $this->db->escape($item_id) . ', definition_id, attribute_id, ' . $this->db->escape($id);
+ $query .= ' FROM ' . $this->db->prefixTable('attribute_links');
+ $query .= ' WHERE item_id = ' . $this->db->escape($item_id);
+ $query .=' AND sale_id IS NULL AND receiving_id IS NULL';
+
+ $builder = $this->db->table('attribute_links');
+ $builder->ignore(true)->setQueryAsData(new RawSql($query), null, 'item_id, definition_id, attribute_id, '. $sale_receiving_fk )->insertBatch();
+ }
+
+ /**
+ * Gets search suggestions (attribute values) for a specific attribute definition given a search term and definition_id
+ *
+ * @param int $definition_id
+ * @param string $term
+ * @return array
+ */
+ public function get_suggestions(int $definition_id, string $term): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('attribute_definitions AS definition');
+ $builder->distinct()->select('attribute_value, attribute_values.attribute_id');
+ $builder->join('attribute_links', 'attribute_links.definition_id = definition.definition_id');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->like('attribute_value', $term);
+ $builder->where('deleted', ACTIVE);
+ $builder->where('definition.definition_id', $definition_id);
+ $builder->orderBy('attribute_value','ASC');
+
+ foreach($builder->get()->getResult('array') as $suggestion)
+ {
+ $suggestions[] = ['value' => $suggestion['attribute_id'], 'label' => $suggestion['attribute_value']];
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * @param string $attribute_value
+ * @param int $definition_id
+ * @param $item_id
+ * @param $attribute_id
+ * @param string $definition_type
+ * @return int
+ */
+ public function saveAttributeValue(string $attribute_value, int $definition_id, int|bool $item_id = false, int|bool $attribute_id = false, string $definition_type = DROPDOWN): int
+ {
+ $config = config(OSPOS::class)->settings;
+
+ $this->db->transStart();
+
+ switch($definition_type)
+ {
+ case DATE:
+ $data_type = 'date';
+ $attribute_date_value = DateTime::createFromFormat($config['dateformat'], $attribute_value);
+ $attribute_value = $attribute_date_value->format('Y-m-d');
+ break;
+ case DECIMAL:
+ $data_type = 'decimal';
+ break;
+ default:
+ $data_type = 'value';
+ break;
+ }
+
+ //New Attribute
+ if(empty($attribute_id) || empty($item_id))
+ {
+ $attribute_id = $this->attributeValueExists($attribute_value, $definition_type);
+
+ if(!$attribute_id)
+ {
+
+ $builder = $this->db->table('attribute_values');
+ $builder->set(["attribute_$data_type" => $attribute_value]);
+ $builder->insert();
+
+ $attribute_id = $this->db->insertID();
+ }
+
+ $data = [
+ 'attribute_id' => empty($attribute_id) ? null : $attribute_id,
+ 'item_id' => empty($item_id) ? null : $item_id,
+ 'definition_id' => $definition_id
+ ];
+
+ $builder = $this->db->table('attribute_links');
+ $builder->set($data);
+ $builder->insert();
+ }
+ //Existing Attribute
+ else
+ {
+ $builder = $this->db->table('attribute_values');
+ $builder->set(["attribute_$data_type" => $attribute_value]);
+ $builder->where('attribute_id', $attribute_id);
+ $builder->update();
+ }
+
+ $this->db->transComplete();
+
+ return $attribute_id;
+ }
+
+ /**
+ * @param string $attribute_value
+ * @param int $definition_id
+ * @return bool
+ */
+ public function delete_value(string $attribute_value, int $definition_id): bool
+ {
+ //QueryBuilder does not support multi-table delete.
+ $query = 'DELETE atrv, atrl ';
+ $query .= 'FROM ' . $this->db->prefixTable('attribute_values') . ' atrv, ' . $this->db->prefixTable('attribute_links') . ' atrl ';
+ $query .= 'WHERE atrl.attribute_id = atrv.attribute_id AND atrv.attribute_value = ' . $this->db->escape($attribute_value);
+ $query .= ' AND atrl.definition_id = ' . $this->db->escape($definition_id);
+ return $this->db->query($query);
+ }
+
+ /**
+ * Deletes an Attribute definition from the database and associated column in the items_import.csv
+ *
+ * @param int $definition_id Attribute definition ID to remove.
+ * @return boolean true if successful and false if there is a failure
+ */
+ public function delete_definition(int $definition_id): bool
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('definition_id', $definition_id);
+
+ return $builder->update(['deleted' => DELETED]);
+ }
+
+ /**
+ * @param array $definition_ids
+ * @return bool
+ */
+ public function delete_definition_list(array $definition_ids): bool
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->whereIn('definition_id', $definition_ids);
+
+ return $builder->update(['deleted' => DELETED]);
+ }
+
+ /**
+ * Deletes any attribute_links for a specific definition that do not have an item_id associated with them and are not DROPDOWN types
+ *
+ * @param int $definition_id
+ * @return boolean true is returned if the delete was successful or false if there were any failures
+ */
+ public function delete_orphaned_links(int $definition_id): bool
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->select('definition_type');
+ $builder->where('definition_id', $definition_id);
+
+ $definition = $builder->get()->getRow();
+
+ if($definition->definition_type != DROPDOWN)
+ {
+ $this->db->transStart();
+
+ $builder = $this->db->table('attribute_links');
+ $builder->where('item_id', null);
+ $builder->where('definition_id', $definition_id);
+ $builder->delete();
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ return true; //Return true when definition_type is DROPDOWN
+ }
+
+ /**
+ * Deletes any orphaned values that do not have associated links
+ *
+ * @return boolean true is returned if the delete was successful or false if there were any failures
+ */
+ public function delete_orphaned_values(): bool
+ {
+ $subquery = $this->db->table('attribute_links')
+ ->distinct()
+ ->select('attribute_id');
+
+ $this->db->transStart();
+
+ $builder = $this->db->table('attribute_values');
+ $builder->whereNotIn('attribute_id', $subquery, false);
+ $builder->delete();
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ /**
+ * Undeletes one attribute definition
+ */
+ public function undelete(int $definition_id): bool
+ {
+ $builder = $this->db->table('attribute_definitions');
+ $builder->where('definition_id', $definition_id);
+
+ return $builder->update(['deleted' => ACTIVE]);
+ }
+
+ /**
+ *
+ * @param array $attributes attributes that need to be fixed
+ * @param int $definition_id
+ * @param string $definition_type This dictates what column should be populated in any new attribute_values that are created
+ * @return bool
+ */
+ public function attribute_cleanup(array $attributes, int $definition_id, string $definition_type): bool
+ {
+ $this->db->transBegin();
+
+ foreach($attributes as $attribute)
+ {
+ $new_attribute_id = $this->saveAttributeValue($attribute['attribute_value'], $definition_id, false, $attribute['attribute_id'], $definition_type);
+
+ if(!$this->saveAttributeLink($attribute['item_id'], $definition_id, $new_attribute_id))
+ {
+ log_message('error', 'Transaction failed');
+ $this->db->transRollback();
+ return false;
+ }
+ }
+ $success = $this->delete_orphaned_links($definition_id);
+
+ $this->db->transCommit();
+ return $success;
+ }
+
+ /**
+ * Returns all attribute_ids and item_ids assigned to that definition_id
+ *
+ * @param int $definition_id
+ * @return array All attribute_id and item_id pairs in the attribute_links table with that attribute definition_id
+ */
+ public function get_attributes_by_definition(int $definition_id): array
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->select('attribute_links.attribute_id, item_id, attribute_value, attribute_decimal, attribute_date');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id');
+ $builder->where('definition_id', $definition_id);
+
+ return $builder->get()->getResultArray();
+ }
}
diff --git a/app/Models/Cashup.php b/app/Models/Cashup.php
index f47fb6b53..0461a1994 100644
--- a/app/Models/Cashup.php
+++ b/app/Models/Cashup.php
@@ -13,268 +13,268 @@ use stdClass;
*/
class Cashup extends Model
{
- protected $table = 'cash_up';
- protected $primaryKey = 'cashup_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'open_date',
- 'close_date',
- 'open_cash_amount',
- 'transfer_cash_amount',
- 'note',
- 'closed_amount_cash',
- 'closed_amount_card',
- 'closed_amount_check',
- 'closed_amount_total',
- 'description',
- 'open_employee_id',
- 'close_employee_id',
- 'deleted',
- 'closed_amount_due'
- ];
+ protected $table = 'cash_up';
+ protected $primaryKey = 'cashup_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'open_date',
+ 'close_date',
+ 'open_cash_amount',
+ 'transfer_cash_amount',
+ 'note',
+ 'closed_amount_cash',
+ 'closed_amount_card',
+ 'closed_amount_check',
+ 'closed_amount_total',
+ 'description',
+ 'open_employee_id',
+ 'close_employee_id',
+ 'deleted',
+ 'closed_amount_due'
+ ];
- /**
- * Determines if a given Cashup_id is a Cashup
- */
- public function exists(int $cashup_id): bool
- {
- $builder = $this->db->table('cash_up');
- $builder->where('cashup_id', $cashup_id);
+ /**
+ * Determines if a given Cashup_id is a Cashup
+ */
+ public function exists(int $cashup_id): bool
+ {
+ $builder = $this->db->table('cash_up');
+ $builder->where('cashup_id', $cashup_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets employee info
- */
- public function get_employee(int $cashup_id): object //TODO: This function is never called and if it were called, would not yield proper results. There is no employee_id field in the cash_up table.
- {
- $builder = $this->db->table('cash_up');
- $builder->where('cashup_id', $cashup_id);
+ /**
+ * Gets employee info
+ */
+ public function get_employee(int $cashup_id): object //TODO: This function is never called and if it were called, would not yield proper results. There is no employee_id field in the cash_up table.
+ {
+ $builder = $this->db->table('cash_up');
+ $builder->where('cashup_id', $cashup_id);
- $employee = model(Employee::class);
+ $employee = model(Employee::class);
- return $employee->get_info($builder->get()->getRow()->employee_id);
- }
+ return $employee->get_info($builder->get()->getRow()->employee_id);
+ }
- /**
- * @param string $cashup_ids
- * @return ResultInterface
- */
- public function get_multiple_info(string $cashup_ids): ResultInterface
- {
- $builder = $this->db->table('cash_up');
- $builder->whereIn('cashup_id', $cashup_ids);
- $builder->orderBy('cashup_id', 'asc');
+ /**
+ * @param string $cashup_ids
+ * @return ResultInterface
+ */
+ public function get_multiple_info(string $cashup_ids): ResultInterface
+ {
+ $builder = $this->db->table('cash_up');
+ $builder->whereIn('cashup_id', $cashup_ids);
+ $builder->orderBy('cashup_id', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search, array $filters): int
- {
- return $this->search($search, $filters, 0, 0, 'cashup_id', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search, array $filters): int
+ {
+ return $this->search($search, $filters, 0, 0, 'cashup_id', 'asc', true);
+ }
- /**
- * Searches cashups
- */
- public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'cashup_id', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'cashup_id';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Searches cashups
+ */
+ public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'cashup_id', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'cashup_id';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('cash_up AS cash_up');
+ $config = config(OSPOS::class)->settings;
+ $builder = $this->db->table('cash_up AS cash_up');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(cash_up.cashup_id) as count');
- }
- else
- {
- $builder->select('
- cash_up.cashup_id,
- MAX(cash_up.open_date) AS open_date,
- MAX(cash_up.close_date) AS close_date,
- MAX(cash_up.open_amount_cash) AS open_amount_cash,
- MAX(cash_up.transfer_amount_cash) AS transfer_amount_cash,
- MAX(cash_up.closed_amount_cash) AS closed_amount_cash,
- MAX(cash_up.closed_amount_due) AS closed_amount_due,
- MAX(cash_up.closed_amount_card) AS closed_amount_card,
- MAX(cash_up.closed_amount_check) AS closed_amount_check,
- MAX(cash_up.closed_amount_total) AS closed_amount_total,
- MAX(cash_up.description) AS description,
- MAX(cash_up.note) AS note,
- MAX(cash_up.open_employee_id) AS open_employee_id,
- MAX(cash_up.close_employee_id) AS close_employee_id,
- MAX(open_employees.first_name) AS open_first_name,
- MAX(open_employees.last_name) AS open_last_name,
- MAX(close_employees.first_name) AS close_first_name,
- MAX(close_employees.last_name) AS close_last_name
- ');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(cash_up.cashup_id) as count');
+ }
+ else
+ {
+ $builder->select('
+ cash_up.cashup_id,
+ MAX(cash_up.open_date) AS open_date,
+ MAX(cash_up.close_date) AS close_date,
+ MAX(cash_up.open_amount_cash) AS open_amount_cash,
+ MAX(cash_up.transfer_amount_cash) AS transfer_amount_cash,
+ MAX(cash_up.closed_amount_cash) AS closed_amount_cash,
+ MAX(cash_up.closed_amount_due) AS closed_amount_due,
+ MAX(cash_up.closed_amount_card) AS closed_amount_card,
+ MAX(cash_up.closed_amount_check) AS closed_amount_check,
+ MAX(cash_up.closed_amount_total) AS closed_amount_total,
+ MAX(cash_up.description) AS description,
+ MAX(cash_up.note) AS note,
+ MAX(cash_up.open_employee_id) AS open_employee_id,
+ MAX(cash_up.close_employee_id) AS close_employee_id,
+ MAX(open_employees.first_name) AS open_first_name,
+ MAX(open_employees.last_name) AS open_last_name,
+ MAX(close_employees.first_name) AS close_first_name,
+ MAX(close_employees.last_name) AS close_last_name
+ ');
+ }
- $builder->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT');
- $builder->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT');
+ $builder->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT');
+ $builder->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT');
- $builder->groupStart();
- $builder->like('cash_up.open_date', $search);
- $builder->orLike('open_employees.first_name', $search);
- $builder->orLike('open_employees.last_name', $search);
- $builder->orLike('close_employees.first_name', $search);
- $builder->orLike('close_employees.last_name', $search);
- $builder->orLike('cash_up.closed_amount_total', $search);
- $builder->orLike('CONCAT(open_employees.first_name, " ", open_employees.last_name)', $search);
- $builder->orLike('CONCAT(close_employees.first_name, " ", close_employees.last_name)', $search);
- $builder->groupEnd();
+ $builder->groupStart();
+ $builder->like('cash_up.open_date', $search);
+ $builder->orLike('open_employees.first_name', $search);
+ $builder->orLike('open_employees.last_name', $search);
+ $builder->orLike('close_employees.first_name', $search);
+ $builder->orLike('close_employees.last_name', $search);
+ $builder->orLike('cash_up.closed_amount_total', $search);
+ $builder->orLike('CONCAT(open_employees.first_name, " ", open_employees.last_name)', $search);
+ $builder->orLike('CONCAT(close_employees.first_name, " ", close_employees.last_name)', $search);
+ $builder->groupEnd();
- $builder->where('cash_up.deleted', $filters['is_deleted']);
+ $builder->where('cash_up.deleted', $filters['is_deleted']);
- if(empty($config['date_or_time_format'])) //TODO: convert this to ternary notation.
- {
- $builder->where('DATE_FORMAT(cash_up.open_date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
- }
- else
- {
- $builder->where('cash_up.open_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
- }
+ if(empty($config['date_or_time_format'])) //TODO: convert this to ternary notation.
+ {
+ $builder->where('DATE_FORMAT(cash_up.open_date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
+ }
+ else
+ {
+ $builder->where('cash_up.open_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
+ }
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
- else
- {
- $builder->groupBy('cashup_id');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
+ else
+ {
+ $builder->groupBy('cashup_id');
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets information about a particular cashup
- */
- public function get_info(int $cashup_id): object
- {
- $builder = $this->db->table('cash_up AS cash_up');
- $builder->select('
- cash_up.cashup_id AS cashup_id,
- cash_up.open_date AS open_date,
- cash_up.close_date AS close_date,
- cash_up.open_amount_cash AS open_amount_cash,
- cash_up.transfer_amount_cash AS transfer_amount_cash,
- cash_up.closed_amount_cash AS closed_amount_cash,
- cash_up.closed_amount_due AS closed_amount_due,
- cash_up.closed_amount_card AS closed_amount_card,
- cash_up.closed_amount_check AS closed_amount_check,
- cash_up.closed_amount_total AS closed_amount_total,
- cash_up.description AS description,
- cash_up.note AS note,
- cash_up.open_employee_id AS open_employee_id,
- cash_up.close_employee_id AS close_employee_id,
- cash_up.deleted AS deleted,
- open_employees.first_name AS open_first_name,
- open_employees.last_name AS open_last_name,
- close_employees.first_name AS close_first_name,
- close_employees.last_name AS close_last_name
- ');
- $builder->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT');
- $builder->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT');
- $builder->where('cashup_id', $cashup_id);
+ /**
+ * Gets information about a particular cashup
+ */
+ public function get_info(int $cashup_id): object
+ {
+ $builder = $this->db->table('cash_up AS cash_up');
+ $builder->select('
+ cash_up.cashup_id AS cashup_id,
+ cash_up.open_date AS open_date,
+ cash_up.close_date AS close_date,
+ cash_up.open_amount_cash AS open_amount_cash,
+ cash_up.transfer_amount_cash AS transfer_amount_cash,
+ cash_up.closed_amount_cash AS closed_amount_cash,
+ cash_up.closed_amount_due AS closed_amount_due,
+ cash_up.closed_amount_card AS closed_amount_card,
+ cash_up.closed_amount_check AS closed_amount_check,
+ cash_up.closed_amount_total AS closed_amount_total,
+ cash_up.description AS description,
+ cash_up.note AS note,
+ cash_up.open_employee_id AS open_employee_id,
+ cash_up.close_employee_id AS close_employee_id,
+ cash_up.deleted AS deleted,
+ open_employees.first_name AS open_first_name,
+ open_employees.last_name AS open_last_name,
+ close_employees.first_name AS close_first_name,
+ close_employees.last_name AS close_last_name
+ ');
+ $builder->join('people AS open_employees', 'open_employees.person_id = cash_up.open_employee_id', 'LEFT');
+ $builder->join('people AS close_employees', 'close_employees.person_id = cash_up.close_employee_id', 'LEFT');
+ $builder->where('cashup_id', $cashup_id);
- $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else
- {
- return $this->getEmptyObject('cash_up');
- }
- }
+ $query = $builder->get();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ return $this->getEmptyObject('cash_up');
+ }
+ }
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
- return $empty_obj;
- }
+ return $empty_obj;
+ }
- /**
- * Inserts or updates a cashup
- */
- public function save_value(array &$cash_up_data, $cashup_id = NEW_ENTRY): bool
- {
- if(!$cashup_id == NEW_ENTRY || !$this->exists($cashup_id))
- {
- $builder = $this->db->table('cash_up');
- if($builder->insert($cash_up_data))
- {
- $cash_up_data['cashup_id'] = $this->db->insertID();
+ /**
+ * Inserts or updates a cashup
+ */
+ public function save_value(array &$cash_up_data, $cashup_id = NEW_ENTRY): bool
+ {
+ if(!$cashup_id == NEW_ENTRY || !$this->exists($cashup_id))
+ {
+ $builder = $this->db->table('cash_up');
+ if($builder->insert($cash_up_data))
+ {
+ $cash_up_data['cashup_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder = $this->db->table('cash_up');
- $builder->where('cashup_id', $cashup_id);
+ $builder = $this->db->table('cash_up');
+ $builder->where('cashup_id', $cashup_id);
- return $builder->update($cash_up_data);
- }
+ return $builder->update($cash_up_data);
+ }
- /**
- * Deletes a list of cashups
- */
- public function delete_list(array $cashup_ids): bool
- {
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
- $builder = $this->db->table('cash_up');
- $builder->whereIn('cashup_id', $cashup_ids);
- $success = $builder->update(['deleted' => 1]);
- $this->db->transComplete();
+ /**
+ * Deletes a list of cashups
+ */
+ public function delete_list(array $cashup_ids): bool
+ {
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+ $builder = $this->db->table('cash_up');
+ $builder->whereIn('cashup_id', $cashup_ids);
+ $success = $builder->update(['deleted' => 1]);
+ $this->db->transComplete();
- return $success;
- }
+ return $success;
+ }
}
diff --git a/app/Models/Customer.php b/app/Models/Customer.php
index e9cebb1b0..ee99ef73b 100644
--- a/app/Models/Customer.php
+++ b/app/Models/Customer.php
@@ -10,459 +10,459 @@ use Config\OSPOS;
*/
class Customer extends Person
{
- protected $table = 'customers';
- protected $primaryKey = 'person_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'account_number',
- 'taxable',
- 'tax_id',
- 'sales_tax_code_id',
- 'deleted',
- 'discount',
- 'discount_type',
- 'company_name',
- 'package_id',
- 'points',
- 'date',
- 'employee_id',
- 'consent'
- ];
-
-
- /**
- * Determines if a given person_id is a customer
- */
- public function exists(int $person_id): bool
- {
- $builder = $this->db->table('customers');
- $builder->join('people', 'people.person_id = customers.person_id');
- $builder->where('customers.person_id', $person_id);
- return ($builder->get()->getNumRows() == 1);
- }
-
- /**
- * Checks if account number exists
- */
- public function check_account_number_exists(string $account_number, string $person_id = ''): bool
- {
- $builder = $this->db->table('customers');
- $builder->where('account_number', $account_number);
-
- if(!empty($person_id))
- {
- $builder->where('person_id !=', $person_id);
- }
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('customers');
- $builder->where('deleted', 0);
-
- return $builder->countAllResults();
- }
-
- /**
- * Returns all the customers
- */
- public function get_all(int $limit = 0, int $offset = 0): ResultInterface
- {
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->orderBy('last_name', 'asc');
-
- if($limit > 0)
- {
- $builder->limit($limit, $offset);
- }
-
- return $builder->get();
- }
-
- /**
- * Gets information about a particular customer
- */
- public function get_info(?int $person_id): object
- {
- $builder = $this->db->table('customers');
- $builder->join('people', 'people.person_id = customers.person_id');
- $builder->where('customers.person_id', $person_id);
- $query = $builder->get();
-
- return $query->getNumRows() === 1
- ? $query->getRow()
- : $this->getEmptyObject('customers');
- }
-
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = parent::get_info(NEW_ENTRY);
-
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
-
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
-
- return $empty_obj;
- }
-
-
- /**
- * Gets stats about a particular customer
- */
- public function get_stats(int $customer_id)
- {
- $db_prefix = $this->db->getPrefix();
- $totals_decimals = totals_decimals();
- $quantity_decimals = quantity_decimals();
-
- //Temp Table
- $builder = $this->db->table('sales');
- $builder->select('sales.sale_id AS sale_id, AVG(`' . $db_prefix . 'sales_items`.`discount`) AS avg_discount, SUM(`' . $db_prefix . 'sales_items`.`quantity_purchased`) AS quantity');
- $builder->join('sales_items', 'sales_items.sale_id = sales.sale_id');
- $builder->where('sales.customer_id', $customer_id);
- $builder->groupBy('sale_id');
- $selectQuery = $builder->getCompiledSelect();
-
- $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp');
- $sql .= ' (INDEX(sale_id)) ENGINE=MEMORY (' . $selectQuery . ')';
- $this->db->query($sql);
-
- //Get data
- $builder = $this->db->table('sales');
- $builder->select([
- 'SUM(sales_payments.payment_amount - sales_payments.cash_refund) AS total',
- 'MIN(sales_payments.payment_amount - sales_payments.cash_refund) AS min',
- 'MAX(sales_payments.payment_amount - sales_payments.cash_refund) AS max',
- 'AVG(sales_payments.payment_amount - sales_payments.cash_refund) AS average',
- "ROUND(AVG(sales_items_temp.avg_discount), $totals_decimals) AS avg_discount",
- "ROUND(SUM(sales_items_temp.quantity), $quantity_decimals) AS quantity"
- ]);
- $builder->join('sales_payments AS sales_payments', 'sales.sale_id = sales_payments.sale_id');
- $builder->join('sales_items_temp AS sales_items_temp', 'sales.sale_id = sales_items_temp.sale_id');
- $builder->where('sales.customer_id', $customer_id);
- $builder->where('sales.sale_status', COMPLETED);
- $builder->groupBy('sales.customer_id');
-
- $stat = $builder->get()->getRow();
-
- //Drop Temp Table
- $sql = 'DROP TEMPORARY TABLE IF EXISTS ' . $this->db->prefixTable('sales_items_temp');
- $this->db->query($sql);
-
- return $stat;
- }
-
- /**
- * Gets information about multiple customers
- */
- public function get_multiple_info(array $person_ids): ResultInterface
- {
- $builder = $this->db->table('customers');
- $builder->join('people', 'people.person_id = customers.person_id');
- $builder->whereIn('customers.person_id', $person_ids);
- $builder->orderBy('last_name', 'asc');
-
- return $builder->get();
- }
-
- /**
- * Checks if customer email exists
- */
- public function check_email_exists(string $email, string $customer_id = ''): bool
- {
- // if the email is empty return like it is not existing
- if(empty($email))
- {
- return false;
- }
-
- $builder = $this->db->table('customers');
- $builder->join('people', 'people.person_id = customers.person_id');
- $builder->where('people.email', $email);
- $builder->where('customers.deleted', 0);
-
- if(!empty($customer_id))
- {
- $builder->where('customers.person_id !=', $customer_id);
- }
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Inserts or updates a customer
- */
- public function save_customer(array &$person_data, array &$customer_data, int $customer_id = NEW_ENTRY): bool
- {
- $success = false;
- $this->db->transStart();
-
- if(parent::save_value($person_data, $customer_id))
- {
- $builder = $this->db->table('customers');
- if($customer_id == NEW_ENTRY || !$customer_id || !$this->exists($customer_id))
- {
- $customer_data['person_id'] = $person_data['person_id'];
- $success = $builder->insert($customer_data);
- }
- else
- {
- $builder->where('person_id', $customer_id);
- $success = $builder->update($customer_data);
- }
- }
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * Updates reward points value
- */
- public function update_reward_points_value(int $customer_id, int $value): void
- {
- $builder = $this->db->table('customers');
- $builder->where('person_id', $customer_id);
- $builder->update(['points' => $value]);
- }
-
- /**
- * @param $customer_id
- * @param bool $purge
- * @return bool
- */
- public function delete($customer_id = null, bool $purge = false): bool
- {
- $result = true;
- $config = config(OSPOS::class)->settings;
-
- // if privacy enforcement is selected scramble customer data
- if($config['enforce_privacy'])
- {
- $builder = $this->db->table('people');
- $builder->where('person_id', $customer_id);
- $result &= $builder->update([
- 'first_name' => $customer_id,
- 'last_name' => $customer_id,
- 'phone_number' => '',
- 'email' => '',
- 'gender' => null,
- 'address_1' => '',
- 'address_2' => '',
- 'city' => '',
- 'state' => '',
- 'zip' => '',
- 'country' => '',
- 'comments' => ''
- ]);
-
- $builder = $this->db->table('customers');
- $builder->where('person_id', $customer_id);
- $result &= $builder->update([
- 'consent' => 0,
- 'company_name' => null,
- 'account_number' => null,
- 'tax_id' => '',
- 'taxable' => 0,
- 'discount' => 0.00,
- 'discount_type' => 0,
- 'package_id' => null,
- 'points' => null,
- 'sales_tax_code_id' => null,
- 'deleted' => 1
- ]);
- }
- else
- {
- $builder = $this->db->table('customers');
- $builder->where('person_id', $customer_id);
-
- $result &= $builder->update(['deleted' => 1]);
- }
-
- return $result;
- }
-
- /**
- * Deletes a list of customers
- */
- public function delete_list(array $person_ids): bool
- {
- $builder = $this->db->table('customers');
- $builder->whereIn('person_id', $person_ids);
-
- return $builder->update(['deleted' => 1]);
- }
-
- /**
- * Get search suggestions to find customers
- */
- public function get_search_suggestions(string $search, int $limit = 25, bool $unique = true): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
-
- if($unique)
- {
- $builder->orLike('email', $search);
- $builder->orLike('phone_number', $search);
- $builder->orLike('company_name', $search);
- }
- $builder->groupEnd();
- $builder->where('deleted', 0);
- $builder->orderBy('last_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = [
- 'value' => $row->person_id,
- 'label' => $row->first_name . ' ' . $row->last_name . (!empty($row->company_name) ? ' [' . $row->company_name . ']' : ''). (!empty($row->phone_number) ? ' [' . $row->phone_number . ']' : '')
- ];
- }
-
- if(!$unique)
- {
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('email', $search);
- $builder->orderBy('email', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
- }
-
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('phone_number', $search);
- $builder->orderBy('phone_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
- }
-
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('account_number', $search);
- $builder->orderBy('account_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->account_number];
- }
-
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('company_name', $search);
- $builder->orderBy('company_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->company_name];
- }
- }
-
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
-
- return $suggestions;
- }
-
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'last_name', 'asc', true);
- }
-
- /**
- * Performs a search on customers
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'last_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
-
- $builder = $this->db->table('customers AS customers');
-
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(customers.person_id) as count');
- }
-
- $builder->join('people', 'customers.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('email', $search);
- $builder->orLike('phone_number', $search);
- $builder->orLike('account_number', $search);
- $builder->orLike('company_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search); //TODO: Duplicated code.
- $builder->groupEnd();
- $builder->where('deleted', 0);
-
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
-
- $builder->orderBy($sort, $order);
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
+ protected $table = 'customers';
+ protected $primaryKey = 'person_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'account_number',
+ 'taxable',
+ 'tax_id',
+ 'sales_tax_code_id',
+ 'deleted',
+ 'discount',
+ 'discount_type',
+ 'company_name',
+ 'package_id',
+ 'points',
+ 'date',
+ 'employee_id',
+ 'consent'
+ ];
+
+
+ /**
+ * Determines if a given person_id is a customer
+ */
+ public function exists(int $person_id): bool
+ {
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'people.person_id = customers.person_id');
+ $builder->where('customers.person_id', $person_id);
+ return ($builder->get()->getNumRows() == 1);
+ }
+
+ /**
+ * Checks if account number exists
+ */
+ public function check_account_number_exists(string $account_number, string $person_id = ''): bool
+ {
+ $builder = $this->db->table('customers');
+ $builder->where('account_number', $account_number);
+
+ if(!empty($person_id))
+ {
+ $builder->where('person_id !=', $person_id);
+ }
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('customers');
+ $builder->where('deleted', 0);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Returns all the customers
+ */
+ public function get_all(int $limit = 0, int $offset = 0): ResultInterface
+ {
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->orderBy('last_name', 'asc');
+
+ if($limit > 0)
+ {
+ $builder->limit($limit, $offset);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets information about a particular customer
+ */
+ public function get_info(?int $person_id): object
+ {
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'people.person_id = customers.person_id');
+ $builder->where('customers.person_id', $person_id);
+ $query = $builder->get();
+
+ return $query->getNumRows() === 1
+ ? $query->getRow()
+ : $this->getEmptyObject('customers');
+ }
+
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = parent::get_info(NEW_ENTRY);
+
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
+
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
+
+ return $empty_obj;
+ }
+
+
+ /**
+ * Gets stats about a particular customer
+ */
+ public function get_stats(int $customer_id)
+ {
+ $db_prefix = $this->db->getPrefix();
+ $totals_decimals = totals_decimals();
+ $quantity_decimals = quantity_decimals();
+
+ //Temp Table
+ $builder = $this->db->table('sales');
+ $builder->select('sales.sale_id AS sale_id, AVG(`' . $db_prefix . 'sales_items`.`discount`) AS avg_discount, SUM(`' . $db_prefix . 'sales_items`.`quantity_purchased`) AS quantity');
+ $builder->join('sales_items', 'sales_items.sale_id = sales.sale_id');
+ $builder->where('sales.customer_id', $customer_id);
+ $builder->groupBy('sale_id');
+ $selectQuery = $builder->getCompiledSelect();
+
+ $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp');
+ $sql .= ' (INDEX(sale_id)) ENGINE=MEMORY (' . $selectQuery . ')';
+ $this->db->query($sql);
+
+ //Get data
+ $builder = $this->db->table('sales');
+ $builder->select([
+ 'SUM(sales_payments.payment_amount - sales_payments.cash_refund) AS total',
+ 'MIN(sales_payments.payment_amount - sales_payments.cash_refund) AS min',
+ 'MAX(sales_payments.payment_amount - sales_payments.cash_refund) AS max',
+ 'AVG(sales_payments.payment_amount - sales_payments.cash_refund) AS average',
+ "ROUND(AVG(sales_items_temp.avg_discount), $totals_decimals) AS avg_discount",
+ "ROUND(SUM(sales_items_temp.quantity), $quantity_decimals) AS quantity"
+ ]);
+ $builder->join('sales_payments AS sales_payments', 'sales.sale_id = sales_payments.sale_id');
+ $builder->join('sales_items_temp AS sales_items_temp', 'sales.sale_id = sales_items_temp.sale_id');
+ $builder->where('sales.customer_id', $customer_id);
+ $builder->where('sales.sale_status', COMPLETED);
+ $builder->groupBy('sales.customer_id');
+
+ $stat = $builder->get()->getRow();
+
+ //Drop Temp Table
+ $sql = 'DROP TEMPORARY TABLE IF EXISTS ' . $this->db->prefixTable('sales_items_temp');
+ $this->db->query($sql);
+
+ return $stat;
+ }
+
+ /**
+ * Gets information about multiple customers
+ */
+ public function get_multiple_info(array $person_ids): ResultInterface
+ {
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'people.person_id = customers.person_id');
+ $builder->whereIn('customers.person_id', $person_ids);
+ $builder->orderBy('last_name', 'asc');
+
+ return $builder->get();
+ }
+
+ /**
+ * Checks if customer email exists
+ */
+ public function check_email_exists(string $email, string $customer_id = ''): bool
+ {
+ // if the email is empty return like it is not existing
+ if(empty($email))
+ {
+ return false;
+ }
+
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'people.person_id = customers.person_id');
+ $builder->where('people.email', $email);
+ $builder->where('customers.deleted', 0);
+
+ if(!empty($customer_id))
+ {
+ $builder->where('customers.person_id !=', $customer_id);
+ }
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Inserts or updates a customer
+ */
+ public function save_customer(array &$person_data, array &$customer_data, int $customer_id = NEW_ENTRY): bool
+ {
+ $success = false;
+ $this->db->transStart();
+
+ if(parent::save_value($person_data, $customer_id))
+ {
+ $builder = $this->db->table('customers');
+ if($customer_id == NEW_ENTRY || !$customer_id || !$this->exists($customer_id))
+ {
+ $customer_data['person_id'] = $person_data['person_id'];
+ $success = $builder->insert($customer_data);
+ }
+ else
+ {
+ $builder->where('person_id', $customer_id);
+ $success = $builder->update($customer_data);
+ }
+ }
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * Updates reward points value
+ */
+ public function update_reward_points_value(int $customer_id, int $value): void
+ {
+ $builder = $this->db->table('customers');
+ $builder->where('person_id', $customer_id);
+ $builder->update(['points' => $value]);
+ }
+
+ /**
+ * @param $customer_id
+ * @param bool $purge
+ * @return bool
+ */
+ public function delete($customer_id = null, bool $purge = false): bool
+ {
+ $result = true;
+ $config = config(OSPOS::class)->settings;
+
+ // if privacy enforcement is selected scramble customer data
+ if($config['enforce_privacy'])
+ {
+ $builder = $this->db->table('people');
+ $builder->where('person_id', $customer_id);
+ $result &= $builder->update([
+ 'first_name' => $customer_id,
+ 'last_name' => $customer_id,
+ 'phone_number' => '',
+ 'email' => '',
+ 'gender' => null,
+ 'address_1' => '',
+ 'address_2' => '',
+ 'city' => '',
+ 'state' => '',
+ 'zip' => '',
+ 'country' => '',
+ 'comments' => ''
+ ]);
+
+ $builder = $this->db->table('customers');
+ $builder->where('person_id', $customer_id);
+ $result &= $builder->update([
+ 'consent' => 0,
+ 'company_name' => null,
+ 'account_number' => null,
+ 'tax_id' => '',
+ 'taxable' => 0,
+ 'discount' => 0.00,
+ 'discount_type' => 0,
+ 'package_id' => null,
+ 'points' => null,
+ 'sales_tax_code_id' => null,
+ 'deleted' => 1
+ ]);
+ }
+ else
+ {
+ $builder = $this->db->table('customers');
+ $builder->where('person_id', $customer_id);
+
+ $result &= $builder->update(['deleted' => 1]);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Deletes a list of customers
+ */
+ public function delete_list(array $person_ids): bool
+ {
+ $builder = $this->db->table('customers');
+ $builder->whereIn('person_id', $person_ids);
+
+ return $builder->update(['deleted' => 1]);
+ }
+
+ /**
+ * Get search suggestions to find customers
+ */
+ public function get_search_suggestions(string $search, int $limit = 25, bool $unique = true): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+
+ if($unique)
+ {
+ $builder->orLike('email', $search);
+ $builder->orLike('phone_number', $search);
+ $builder->orLike('company_name', $search);
+ }
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
+ $builder->orderBy('last_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = [
+ 'value' => $row->person_id,
+ 'label' => $row->first_name . ' ' . $row->last_name . (!empty($row->company_name) ? ' [' . $row->company_name . ']' : ''). (!empty($row->phone_number) ? ' [' . $row->phone_number . ']' : '')
+ ];
+ }
+
+ if(!$unique)
+ {
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('email', $search);
+ $builder->orderBy('email', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
+ }
+
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('phone_number', $search);
+ $builder->orderBy('phone_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
+ }
+
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('account_number', $search);
+ $builder->orderBy('account_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->account_number];
+ }
+
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('company_name', $search);
+ $builder->orderBy('company_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->company_name];
+ }
+ }
+
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'last_name', 'asc', true);
+ }
+
+ /**
+ * Performs a search on customers
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'last_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
+
+ $builder = $this->db->table('customers AS customers');
+
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(customers.person_id) as count');
+ }
+
+ $builder->join('people', 'customers.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('email', $search);
+ $builder->orLike('phone_number', $search);
+ $builder->orLike('account_number', $search);
+ $builder->orLike('company_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search); //TODO: Duplicated code.
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
+
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
+
+ $builder->orderBy($sort, $order);
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
}
diff --git a/app/Models/Customer_rewards.php b/app/Models/Customer_rewards.php
index 115c3d93f..adeb55a7b 100644
--- a/app/Models/Customer_rewards.php
+++ b/app/Models/Customer_rewards.php
@@ -10,96 +10,96 @@ use CodeIgniter\Model;
*/
class Customer_rewards extends Model
{
- protected $table = 'customer_packages';
- protected $primaryKey = 'package_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'package_name',
- 'points_percent',
- 'deleted'
- ];
+ protected $table = 'customer_packages';
+ protected $primaryKey = 'package_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'package_name',
+ 'points_percent',
+ 'deleted'
+ ];
- /**
- * @param int $package_id
- * @return bool
- */
- public function exists(int $package_id): bool
- {
- $builder = $this->db->table('customers_packages');
- $builder->where('package_id', $package_id);
+ /**
+ * @param int $package_id
+ * @return bool
+ */
+ public function exists(int $package_id): bool
+ {
+ $builder = $this->db->table('customers_packages');
+ $builder->where('package_id', $package_id);
- return ($builder->get()->getNumRows() >= 1);
- }
+ return ($builder->get()->getNumRows() >= 1);
+ }
- /**
- * @param array $package_data
- * @param int $package_id
- * @return bool
- */
- public function save_value(array $package_data, int $package_id): bool
- {
- $package_data_to_save = [
- 'package_name' => $package_data['package_name'],
- 'deleted' => 0,
- 'points_percent' => $package_data['points_percent']
- ];
+ /**
+ * @param array $package_data
+ * @param int $package_id
+ * @return bool
+ */
+ public function save_value(array $package_data, int $package_id): bool
+ {
+ $package_data_to_save = [
+ 'package_name' => $package_data['package_name'],
+ 'deleted' => 0,
+ 'points_percent' => $package_data['points_percent']
+ ];
- if(!$this->exists($package_id))
- {
- $builder = $this->db->table('customers_packages');
- return $builder->insert($package_data_to_save);
- }
+ if(!$this->exists($package_id))
+ {
+ $builder = $this->db->table('customers_packages');
+ return $builder->insert($package_data_to_save);
+ }
- $builder = $this->db->table('customers_packages');
- $builder->where('package_id', $package_id);
+ $builder = $this->db->table('customers_packages');
+ $builder->where('package_id', $package_id);
- return $builder->update($package_data_to_save);
- }
+ return $builder->update($package_data_to_save);
+ }
- /**
- * @param int $package_id
- * @return string
- */
- public function get_name(int $package_id): string
- {
- $builder = $this->db->table('customers_packages');
- $builder->where('package_id', $package_id);
+ /**
+ * @param int $package_id
+ * @return string
+ */
+ public function get_name(int $package_id): string
+ {
+ $builder = $this->db->table('customers_packages');
+ $builder->where('package_id', $package_id);
- return $builder->get()->getRow()->package_name;
- }
+ return $builder->get()->getRow()->package_name;
+ }
- /**
- * @param int $package_id
- * @return float
- */
- public function get_points_percent(int $package_id): float
- {
- $builder = $this->db->table('customers_packages');
- $builder->where('package_id', $package_id);
+ /**
+ * @param int $package_id
+ * @return float
+ */
+ public function get_points_percent(int $package_id): float
+ {
+ $builder = $this->db->table('customers_packages');
+ $builder->where('package_id', $package_id);
- return $builder->get()->getRow()->points_percent;
- }
+ return $builder->get()->getRow()->points_percent;
+ }
- /**
- * @return ResultInterface
- */
- public function get_all(): ResultInterface
- {
- $builder = $this->db->table('customers_packages');
- $builder->where('deleted', 0);
+ /**
+ * @return ResultInterface
+ */
+ public function get_all(): ResultInterface
+ {
+ $builder = $this->db->table('customers_packages');
+ $builder->where('deleted', 0);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Deletes one reward package
- */
- public function delete($package_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('customers_packages');
- $builder->where('package_id', $package_id);
+ /**
+ * Deletes one reward package
+ */
+ public function delete($package_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('customers_packages');
+ $builder->where('package_id', $package_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
}
diff --git a/app/Models/Dinner_table.php b/app/Models/Dinner_table.php
index dbafbec4f..2d9843f3c 100644
--- a/app/Models/Dinner_table.php
+++ b/app/Models/Dinner_table.php
@@ -10,169 +10,169 @@ use CodeIgniter\Model;
*/
class Dinner_table extends Model
{
- protected $table = 'dinner_tables';
- protected $primaryKey = 'dinner_table_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'name',
- 'status',
- 'deleted'
- ];
+ protected $table = 'dinner_tables';
+ protected $primaryKey = 'dinner_table_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'name',
+ 'status',
+ 'deleted'
+ ];
- /**
- * @param int $dinner_table_id
- * @return bool
- */
- public function exists(int $dinner_table_id): bool
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
+ /**
+ * @param int $dinner_table_id
+ * @return bool
+ */
+ public function exists(int $dinner_table_id): bool
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
- return ($builder->get()->getNumRows() >= 1);
- }
+ return ($builder->get()->getNumRows() >= 1);
+ }
- /**
- * @param array $table_data
- * @param int $dinner_table_id
- * @return bool
- */
- public function save_value(array $table_data, int $dinner_table_id): bool
- {
- $table_data_to_save = ['name' => $table_data['name'], 'deleted' => 0];
+ /**
+ * @param array $table_data
+ * @param int $dinner_table_id
+ * @return bool
+ */
+ public function save_value(array $table_data, int $dinner_table_id): bool
+ {
+ $table_data_to_save = ['name' => $table_data['name'], 'deleted' => 0];
- $builder = $this->db->table('dinner_tables');
- if(!$this->exists($dinner_table_id))
- {
- return $builder->insert($table_data_to_save);
- }
+ $builder = $this->db->table('dinner_tables');
+ if(!$this->exists($dinner_table_id))
+ {
+ return $builder->insert($table_data_to_save);
+ }
- $builder->where('dinner_table_id', $dinner_table_id);
+ $builder->where('dinner_table_id', $dinner_table_id);
- return $builder->update($table_data_to_save);
- }
+ return $builder->update($table_data_to_save);
+ }
- /**
- * Get empty tables
- */
- public function get_empty_tables(?int $current_dinner_table_id): array
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('status', 0);
- $builder->orWhere('dinner_table_id', $current_dinner_table_id);
- $builder->where('deleted', 0);
+ /**
+ * Get empty tables
+ */
+ public function get_empty_tables(?int $current_dinner_table_id): array
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('status', 0);
+ $builder->orWhere('dinner_table_id', $current_dinner_table_id);
+ $builder->where('deleted', 0);
- $empty_tables = $builder->get()->getResultArray();
+ $empty_tables = $builder->get()->getResultArray();
- $empty_tables_array = []; //TODO: Variable names should not contain the name of the datatype.
- foreach($empty_tables as $empty_table)
- {
- $empty_tables_array[$empty_table['dinner_table_id']] = $empty_table['name'];
- }
+ $empty_tables_array = []; //TODO: Variable names should not contain the name of the datatype.
+ foreach($empty_tables as $empty_table)
+ {
+ $empty_tables_array[$empty_table['dinner_table_id']] = $empty_table['name'];
+ }
- return $empty_tables_array;
- }
+ return $empty_tables_array;
+ }
- /**
- * @param int $dinner_table_id
- * @return string
- */
- public function get_name(int $dinner_table_id): string
- {
- if(empty($dinner_table_id))
- {
- return '';
- }
- else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
+ /**
+ * @param int $dinner_table_id
+ * @return string
+ */
+ public function get_name(int $dinner_table_id): string
+ {
+ if(empty($dinner_table_id))
+ {
+ return '';
+ }
+ else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
- return $builder->get()->getRow()->name;
- }
- }
+ return $builder->get()->getRow()->name;
+ }
+ }
- /**
- * @param int $dinner_table_id
- * @return bool
- */
- public function is_occupied(int $dinner_table_id): bool
- {
- if(empty($dinner_table_id))
- {
- return false;
- }
- else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
+ /**
+ * @param int $dinner_table_id
+ * @return bool
+ */
+ public function is_occupied(int $dinner_table_id): bool
+ {
+ if(empty($dinner_table_id))
+ {
+ return false;
+ }
+ else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
- return ($builder->get()->getRow()->status == 1); //TODO: === ?
- }
- }
+ return ($builder->get()->getRow()->status == 1); //TODO: === ?
+ }
+ }
- /**
- * @return ResultInterface
- */
- public function get_all(): ResultInterface
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('deleted', 0);
+ /**
+ * @return ResultInterface
+ */
+ public function get_all(): ResultInterface
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('deleted', 0);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Deletes one dinner table
- */
- public function delete($dinner_table_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
+ /**
+ * Deletes one dinner table
+ */
+ public function delete($dinner_table_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Occupy table
- * Ignore the Delivery and Takeaway "tables". They should never be occupied.
- */
- public function occupy(int $dinner_table_id): bool
- {
- if($dinner_table_id > 2 )
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
- return $builder->update(['status' => 1]);
- }
- else//TODO: THIS ELSE STATEMENT ISN'T NEEDED. JUST DO THE IF AND THEN RETURN true AFTER IT.
- {
- return true;
- }
- }
+ /**
+ * Occupy table
+ * Ignore the Delivery and Takeaway "tables". They should never be occupied.
+ */
+ public function occupy(int $dinner_table_id): bool
+ {
+ if($dinner_table_id > 2 )
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
+ return $builder->update(['status' => 1]);
+ }
+ else//TODO: THIS ELSE STATEMENT ISN'T NEEDED. JUST DO THE IF AND THEN RETURN true AFTER IT.
+ {
+ return true;
+ }
+ }
- /**
- * Release table
- */
- public function release(int $dinner_table_id): bool
- {
- if($dinner_table_id > 2 )
- {
- $builder = $this->db->table('dinner_tables');
- $builder->where('dinner_table_id', $dinner_table_id);
- return $builder->update(['status' => 0]);
- }
- else
- {
- return true;
- }
- }
+ /**
+ * Release table
+ */
+ public function release(int $dinner_table_id): bool
+ {
+ if($dinner_table_id > 2 )
+ {
+ $builder = $this->db->table('dinner_tables');
+ $builder->where('dinner_table_id', $dinner_table_id);
+ return $builder->update(['status' => 0]);
+ }
+ else
+ {
+ return true;
+ }
+ }
- /**
- * Swap tables
- */
- public function swap_tables(int $release_dinner_table_id, int $occupy_dinner_table_id): bool
- {
- return $this->release($release_dinner_table_id) && $this->occupy($occupy_dinner_table_id);
- }
+ /**
+ * Swap tables
+ */
+ public function swap_tables(int $release_dinner_table_id, int $occupy_dinner_table_id): bool
+ {
+ return $this->release($release_dinner_table_id) && $this->occupy($occupy_dinner_table_id);
+ }
}
diff --git a/app/Models/Employee.php b/app/Models/Employee.php
index c2d49354f..ee220255f 100644
--- a/app/Models/Employee.php
+++ b/app/Models/Employee.php
@@ -13,564 +13,564 @@ use CodeIgniter\Session\Session;
*/
class Employee extends Person
{
- public Session $session;
- protected $table = 'Employees';
- protected $primaryKey = 'person_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'username',
- 'password',
- 'deleted',
- 'hashversion',
- 'language',
- 'language_code'
- ];
-
- public function __construct()
- {
- parent::__construct();
- $this->session = session();
- }
-
- /**
- * Determines if a given person_id is an employee
- */
- public function exists(int $person_id): bool
- {
- $builder = $this->db->table('employees');
- $builder->join('people', 'people.person_id = employees.person_id');
- $builder->where('employees.person_id', $person_id);
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * @param int $employee_id
- * @param string $username
- * @return bool
- */
- public function username_exists(int $employee_id, string $username): bool
- {
- $builder = $this->db->table('employees');
- $builder->where('employees.username', $username);
- $builder->where('employees.person_id <>', $employee_id);
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('employees');
- $builder->where('deleted', 0);
-
- return $builder->countAllResults();
- }
-
- /**
- * Returns all the employees
- */
- public function get_all(int $limit = 10000, int $offset = 0): ResultInterface
- {
- $builder = $this->db->table('employees');
- $builder->where('deleted', 0);
- $builder->join('people', 'employees.person_id = people.person_id');
- $builder->orderBy('last_name', 'asc');
- $builder->limit($limit);
- $builder->offset($offset);
-
- return $builder->get();
- }
-
- /**
- * Gets information about a particular employee
- */
- public function get_info(int $person_id): object
- {
- $builder = $this->db->table('employees');
- $builder->join('people', 'people.person_id = employees.person_id');
- $builder->where('employees.person_id', $person_id);
- $query = $builder->get();
-
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
-
- //Get empty base parent object, as $employee_id is NOT an employee
- $person_obj = parent::get_info(NEW_ITEM);
-
- //Get all the fields from employee table
- //append those fields to base parent object, we have a complete empty object
- foreach($this->db->getFieldNames('employees') as $field)
- {
- $person_obj->$field = null;
- }
-
- return $person_obj;
- }
-
- /**
- * Gets information about multiple employees
- */
- public function get_multiple_info(array $person_ids): ResultInterface
- {
- $builder = $this->db->table('employees');
- $builder->join('people', 'people.person_id = employees.person_id');
- $builder->whereIn('employees.person_id', $person_ids);
- $builder->orderBy('last_name', 'asc');
-
- return $builder->get();
- }
-
- /**
- * Inserts or updates an employee
- */
- public function save_employee(array &$person_data, array &$employee_data, array &$grants_data, int $employee_id = NEW_ENTRY): bool
- {
- $success = false;
-
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- if(ENVIRONMENT != 'testing' && parent::save_value($person_data, $employee_id))
- {
- $builder = $this->db->table('employees');
- if($employee_id == NEW_ENTRY || !$this->exists($employee_id))
- {
- $employee_data['person_id'] = $employee_id = $person_data['person_id'];
- $success = $builder->insert($employee_data);
- }
- else
- {
- $builder->where('person_id', $employee_id);
- $success = $builder->update($employee_data);
- }
-
- //We have either inserted or updated a new employee, now lets set permissions.
- if($success)
- {
- //First lets clear out any grants the employee currently has.
- $builder = $this->db->table('grants');
- $success = $builder->delete(['person_id' => $employee_id]);
-
- //Now insert the new grants
- if($success)
- {
- foreach($grants_data as $grant)
- {
- $data = [
- 'permission_id' => $grant['permission_id'],
- 'person_id' => $employee_id,
- 'menu_group' => $grant['menu_group']
- ];
-
- $builder = $this->db->table('grants');
- $success = $builder->insert($data);
- }
- }
- }
- }
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * Deletes one employee
- */
- public function delete($employee_id = null, bool $purge = false): bool
- {
- $success = false;
-
- //Don't let employees delete themselves
- if($employee_id == $this->get_logged_in_employee_info()->person_id)
- {
- return false;
- }
-
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- //Delete permissions
- $builder = $this->db->table('grants');
-
- if($builder->delete(['person_id' => $employee_id]))
- {
- $builder = $this->db->table('employees');
- $builder->where('person_id', $employee_id);
- $success = $builder->update(['deleted' => 1]);
- }
-
- $this->db->transComplete();
-
- return $success;
- }
-
- /**
- * Deletes a list of employees
- */
- public function delete_list(array $person_ids): bool
- {
- $success = false;
-
- //Don't let employees delete themselves
- if(in_array($this->get_logged_in_employee_info()->person_id, $person_ids))
- {
- return false;
- }
-
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- $builder = $this->db->table('grants');
- $builder->whereIn('person_id', $person_ids);
- //Delete permissions
- if($builder->delete())
- {
- //delete from employee table
- $builder = $this->db->table('employees');
- $builder->whereIn('person_id', $person_ids);
- $success = $builder->update(['deleted' => 1]);
- }
-
- $this->db->transComplete();
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * Get search suggestions to find employees
- */
- public function get_search_suggestions(string $search, int $limit = 25, bool $unique = false): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('employees');
- $builder->join('people', 'employees.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
- $builder->groupEnd();
-
- if(!$unique)
- {
- $builder->where('deleted', 0);
- }
-
- $builder->orderBy('last_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->first_name.' '.$row->last_name];
- }
-
- $builder = $this->db->table('employees');
- $builder->join('people', 'employees.person_id = people.person_id');
-
- if(!$unique)
- {
- $builder->where('deleted', 0);
- }
-
- $builder->like('email', $search);
- $builder->orderBy('email', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
- }
-
- $builder = $this->db->table('employees');
- $builder->join('people', 'employees.person_id = people.person_id');
-
- if(!$unique)
- {
- $builder->where('deleted', 0);
- }
-
- $builder->like('username', $search);
- $builder->orderBy('username', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->username];
- }
-
- $builder = $this->db->table('employees');
- $builder->join('people', 'employees.person_id = people.person_id');
-
- if(!$unique)
- {
- $builder->where('deleted', 0);
- }
-
- $builder->like('phone_number', $search);
- $builder->orderBy('phone_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
- }
-
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
-
- return $suggestions;
- }
-
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'last_name', 'asc', true);
- }
-
- /**
- * Performs a search on employees
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'last_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
-
- $builder = $this->db->table('employees AS employees');
-
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(employees.person_id) as count');
- }
-
- $builder->join('people', 'employees.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('email', $search);
- $builder->orLike('phone_number', $search);
- $builder->orLike('username', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
-
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
-
- $builder->orderBy($sort, $order);
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
-
- /**
- * Attempts to log in employee and set session. Returns boolean based on outcome.
- */
- public function login(string $username, string $password): bool
- {
- $builder = $this->db->table('employees');
- $query = $builder->getWhere(['username' => $username, 'deleted' => 0], 1);
-
- if($query->getNumRows() === 1)
- {
- $row = $query->getRow();
-
- // compare passwords depending on the hash version
- if($row->hash_version === '1' && $row->password === md5($password))
- {
- $builder->where('person_id', $row->person_id);
- $this->session->set('person_id', $row->person_id);
- $password_hash = password_hash($password, PASSWORD_DEFAULT);
-
- return $builder->update(['hash_version' => 2, 'password' => $password_hash]);
- }
- elseif($row->hash_version === '2' && password_verify($password, $row->password))
- {
- $this->session->set('person_id', $row->person_id);
-
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Logs out a user by destroying all session data and redirect to log in
- */
- public function logout(): void
- {
- session()->destroy();
- }
-
- /**
- * Determines if an employee is logged in
- */
- public function is_logged_in(): bool
- {
- return ($this->session->get('person_id') != false);
- }
-
- /**
- * Gets information about the currently logged in employee.
- */
- public function get_logged_in_employee_info()
- {
- if($this->is_logged_in())
- {
- return $this->get_info($this->session->get('person_id'));
- }
-
- return false;
- }
-
- /**
- * Determines whether the employee has access to at least one submodule
- */
- public function has_module_grant(string $permission_id, int $person_id): bool
- {
- $builder = $this->db->table('grants');
- $builder->like('permission_id', $permission_id, 'after');
- $builder->where('person_id', $person_id);
- $result_count = $builder->get()->getNumRows();
-
- if($result_count != 1)
- {
- return ($result_count != 0);
- }
-
- return $this->has_subpermissions($permission_id);
- }
-
- /**
- * Checks permissions
- */
- public function has_subpermissions(string $permission_id): bool
- {
- $builder = $this->db->table('permissions');
- $builder->like('permission_id', $permission_id.'_', 'after');
-
- return ($builder->get()->getNumRows() == 0); //TODO: ===
- }
-
- /**
- * Determines whether the employee specified employee has access the specific module.
- */
- public function has_grant(?string $permission_id, ?int $person_id): bool
- {
- //if no module_id is null, allow access
- if($permission_id == null)
- {
- return true;
- }
- if($person_id == null)
- {
- return false;
- }
-
- $builder = $this->db->table('grants');
- $query = $builder->getWhere(['person_id' => $person_id, 'permission_id' => $permission_id], 1);
-
- return ($query->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Returns the menu group designation that this module is to appear in
- */
- public function get_menu_group(string $permission_id, ?int $person_id): string
- {
- $builder = $this->db->table('grants');
- $builder->select('menu_group');
- $builder->where('permission_id', $permission_id);
- $builder->where('person_id', $person_id);
-
- $row = $builder->get()->getRow();
-
- // If no grants are assigned yet then set the default to 'home'
- if($row == null)
- {
- return 'home';
- }
- else
- {
- return $row->menu_group;
- }
- }
-
- /**
- * Gets employee permission grants
- */
- public function get_employee_grants(int $person_id): array
- {
- $builder = $this->db->table('grants');
- $builder->where('person_id', $person_id);
-
- return $builder->get()->getResultArray();
- }
-
- /**
- * Attempts to log in employee and set session. Returns boolean based on outcome.
- */
- public function check_password(string $username, string $password): bool
- {
- $builder = $this->db->table('employees');
- $query = $builder->getWhere(['username' => $username, 'deleted' => 0], 1);
-
- if($query->getNumRows() == 1) //TODO: ===
- {
- $row = $query->getRow();
-
- if(password_verify($password, $row->password))
- {
- return true;
- }
- }
-
- return false;
- }
-
- /**
- * Change password for the employee
- */
- public function change_password(array $employee_data, $employee_id = false): bool
- {
- $success = false;
-
- if(ENVIRONMENT != 'testing')
- {
- $this->db->transStart();
-
- $builder = $this->db->table('employees');
- $builder->where('person_id', $employee_id);
- $success = $builder->update($employee_data);
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
- }
-
- return $success;
- }
+ public Session $session;
+ protected $table = 'Employees';
+ protected $primaryKey = 'person_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'username',
+ 'password',
+ 'deleted',
+ 'hashversion',
+ 'language',
+ 'language_code'
+ ];
+
+ public function __construct()
+ {
+ parent::__construct();
+ $this->session = session();
+ }
+
+ /**
+ * Determines if a given person_id is an employee
+ */
+ public function exists(int $person_id): bool
+ {
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'people.person_id = employees.person_id');
+ $builder->where('employees.person_id', $person_id);
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * @param int $employee_id
+ * @param string $username
+ * @return bool
+ */
+ public function username_exists(int $employee_id, string $username): bool
+ {
+ $builder = $this->db->table('employees');
+ $builder->where('employees.username', $username);
+ $builder->where('employees.person_id <>', $employee_id);
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('employees');
+ $builder->where('deleted', 0);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Returns all the employees
+ */
+ public function get_all(int $limit = 10000, int $offset = 0): ResultInterface
+ {
+ $builder = $this->db->table('employees');
+ $builder->where('deleted', 0);
+ $builder->join('people', 'employees.person_id = people.person_id');
+ $builder->orderBy('last_name', 'asc');
+ $builder->limit($limit);
+ $builder->offset($offset);
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets information about a particular employee
+ */
+ public function get_info(int $person_id): object
+ {
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'people.person_id = employees.person_id');
+ $builder->where('employees.person_id', $person_id);
+ $query = $builder->get();
+
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+
+ //Get empty base parent object, as $employee_id is NOT an employee
+ $person_obj = parent::get_info(NEW_ITEM);
+
+ //Get all the fields from employee table
+ //append those fields to base parent object, we have a complete empty object
+ foreach($this->db->getFieldNames('employees') as $field)
+ {
+ $person_obj->$field = null;
+ }
+
+ return $person_obj;
+ }
+
+ /**
+ * Gets information about multiple employees
+ */
+ public function get_multiple_info(array $person_ids): ResultInterface
+ {
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'people.person_id = employees.person_id');
+ $builder->whereIn('employees.person_id', $person_ids);
+ $builder->orderBy('last_name', 'asc');
+
+ return $builder->get();
+ }
+
+ /**
+ * Inserts or updates an employee
+ */
+ public function save_employee(array &$person_data, array &$employee_data, array &$grants_data, int $employee_id = NEW_ENTRY): bool
+ {
+ $success = false;
+
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ if(ENVIRONMENT != 'testing' && parent::save_value($person_data, $employee_id))
+ {
+ $builder = $this->db->table('employees');
+ if($employee_id == NEW_ENTRY || !$this->exists($employee_id))
+ {
+ $employee_data['person_id'] = $employee_id = $person_data['person_id'];
+ $success = $builder->insert($employee_data);
+ }
+ else
+ {
+ $builder->where('person_id', $employee_id);
+ $success = $builder->update($employee_data);
+ }
+
+ //We have either inserted or updated a new employee, now lets set permissions.
+ if($success)
+ {
+ //First lets clear out any grants the employee currently has.
+ $builder = $this->db->table('grants');
+ $success = $builder->delete(['person_id' => $employee_id]);
+
+ //Now insert the new grants
+ if($success)
+ {
+ foreach($grants_data as $grant)
+ {
+ $data = [
+ 'permission_id' => $grant['permission_id'],
+ 'person_id' => $employee_id,
+ 'menu_group' => $grant['menu_group']
+ ];
+
+ $builder = $this->db->table('grants');
+ $success = $builder->insert($data);
+ }
+ }
+ }
+ }
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * Deletes one employee
+ */
+ public function delete($employee_id = null, bool $purge = false): bool
+ {
+ $success = false;
+
+ //Don't let employees delete themselves
+ if($employee_id == $this->get_logged_in_employee_info()->person_id)
+ {
+ return false;
+ }
+
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ //Delete permissions
+ $builder = $this->db->table('grants');
+
+ if($builder->delete(['person_id' => $employee_id]))
+ {
+ $builder = $this->db->table('employees');
+ $builder->where('person_id', $employee_id);
+ $success = $builder->update(['deleted' => 1]);
+ }
+
+ $this->db->transComplete();
+
+ return $success;
+ }
+
+ /**
+ * Deletes a list of employees
+ */
+ public function delete_list(array $person_ids): bool
+ {
+ $success = false;
+
+ //Don't let employees delete themselves
+ if(in_array($this->get_logged_in_employee_info()->person_id, $person_ids))
+ {
+ return false;
+ }
+
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ $builder = $this->db->table('grants');
+ $builder->whereIn('person_id', $person_ids);
+ //Delete permissions
+ if($builder->delete())
+ {
+ //delete from employee table
+ $builder = $this->db->table('employees');
+ $builder->whereIn('person_id', $person_ids);
+ $success = $builder->update(['deleted' => 1]);
+ }
+
+ $this->db->transComplete();
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * Get search suggestions to find employees
+ */
+ public function get_search_suggestions(string $search, int $limit = 25, bool $unique = false): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'employees.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+ $builder->groupEnd();
+
+ if(!$unique)
+ {
+ $builder->where('deleted', 0);
+ }
+
+ $builder->orderBy('last_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->first_name.' '.$row->last_name];
+ }
+
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'employees.person_id = people.person_id');
+
+ if(!$unique)
+ {
+ $builder->where('deleted', 0);
+ }
+
+ $builder->like('email', $search);
+ $builder->orderBy('email', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
+ }
+
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'employees.person_id = people.person_id');
+
+ if(!$unique)
+ {
+ $builder->where('deleted', 0);
+ }
+
+ $builder->like('username', $search);
+ $builder->orderBy('username', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->username];
+ }
+
+ $builder = $this->db->table('employees');
+ $builder->join('people', 'employees.person_id = people.person_id');
+
+ if(!$unique)
+ {
+ $builder->where('deleted', 0);
+ }
+
+ $builder->like('phone_number', $search);
+ $builder->orderBy('phone_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
+ }
+
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'last_name', 'asc', true);
+ }
+
+ /**
+ * Performs a search on employees
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'last_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
+
+ $builder = $this->db->table('employees AS employees');
+
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(employees.person_id) as count');
+ }
+
+ $builder->join('people', 'employees.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('email', $search);
+ $builder->orLike('phone_number', $search);
+ $builder->orLike('username', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
+
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
+
+ $builder->orderBy($sort, $order);
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Attempts to log in employee and set session. Returns boolean based on outcome.
+ */
+ public function login(string $username, string $password): bool
+ {
+ $builder = $this->db->table('employees');
+ $query = $builder->getWhere(['username' => $username, 'deleted' => 0], 1);
+
+ if($query->getNumRows() === 1)
+ {
+ $row = $query->getRow();
+
+ // compare passwords depending on the hash version
+ if($row->hash_version === '1' && $row->password === md5($password))
+ {
+ $builder->where('person_id', $row->person_id);
+ $this->session->set('person_id', $row->person_id);
+ $password_hash = password_hash($password, PASSWORD_DEFAULT);
+
+ return $builder->update(['hash_version' => 2, 'password' => $password_hash]);
+ }
+ elseif($row->hash_version === '2' && password_verify($password, $row->password))
+ {
+ $this->session->set('person_id', $row->person_id);
+
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Logs out a user by destroying all session data and redirect to log in
+ */
+ public function logout(): void
+ {
+ session()->destroy();
+ }
+
+ /**
+ * Determines if an employee is logged in
+ */
+ public function is_logged_in(): bool
+ {
+ return ($this->session->get('person_id') != false);
+ }
+
+ /**
+ * Gets information about the currently logged in employee.
+ */
+ public function get_logged_in_employee_info()
+ {
+ if($this->is_logged_in())
+ {
+ return $this->get_info($this->session->get('person_id'));
+ }
+
+ return false;
+ }
+
+ /**
+ * Determines whether the employee has access to at least one submodule
+ */
+ public function has_module_grant(string $permission_id, int $person_id): bool
+ {
+ $builder = $this->db->table('grants');
+ $builder->like('permission_id', $permission_id, 'after');
+ $builder->where('person_id', $person_id);
+ $result_count = $builder->get()->getNumRows();
+
+ if($result_count != 1)
+ {
+ return ($result_count != 0);
+ }
+
+ return $this->has_subpermissions($permission_id);
+ }
+
+ /**
+ * Checks permissions
+ */
+ public function has_subpermissions(string $permission_id): bool
+ {
+ $builder = $this->db->table('permissions');
+ $builder->like('permission_id', $permission_id.'_', 'after');
+
+ return ($builder->get()->getNumRows() == 0); //TODO: ===
+ }
+
+ /**
+ * Determines whether the employee specified employee has access the specific module.
+ */
+ public function has_grant(?string $permission_id, ?int $person_id): bool
+ {
+ //if no module_id is null, allow access
+ if($permission_id == null)
+ {
+ return true;
+ }
+ if($person_id == null)
+ {
+ return false;
+ }
+
+ $builder = $this->db->table('grants');
+ $query = $builder->getWhere(['person_id' => $person_id, 'permission_id' => $permission_id], 1);
+
+ return ($query->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Returns the menu group designation that this module is to appear in
+ */
+ public function get_menu_group(string $permission_id, ?int $person_id): string
+ {
+ $builder = $this->db->table('grants');
+ $builder->select('menu_group');
+ $builder->where('permission_id', $permission_id);
+ $builder->where('person_id', $person_id);
+
+ $row = $builder->get()->getRow();
+
+ // If no grants are assigned yet then set the default to 'home'
+ if($row == null)
+ {
+ return 'home';
+ }
+ else
+ {
+ return $row->menu_group;
+ }
+ }
+
+ /**
+ * Gets employee permission grants
+ */
+ public function get_employee_grants(int $person_id): array
+ {
+ $builder = $this->db->table('grants');
+ $builder->where('person_id', $person_id);
+
+ return $builder->get()->getResultArray();
+ }
+
+ /**
+ * Attempts to log in employee and set session. Returns boolean based on outcome.
+ */
+ public function check_password(string $username, string $password): bool
+ {
+ $builder = $this->db->table('employees');
+ $query = $builder->getWhere(['username' => $username, 'deleted' => 0], 1);
+
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ $row = $query->getRow();
+
+ if(password_verify($password, $row->password))
+ {
+ return true;
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Change password for the employee
+ */
+ public function change_password(array $employee_data, $employee_id = false): bool
+ {
+ $success = false;
+
+ if(ENVIRONMENT != 'testing')
+ {
+ $this->db->transStart();
+
+ $builder = $this->db->table('employees');
+ $builder->where('person_id', $employee_id);
+ $success = $builder->update($employee_data);
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+ }
+
+ return $success;
+ }
}
diff --git a/app/Models/Enums/Rounding_mode.php b/app/Models/Enums/Rounding_mode.php
index 27e49557f..1773571ed 100644
--- a/app/Models/Enums/Rounding_mode.php
+++ b/app/Models/Enums/Rounding_mode.php
@@ -6,91 +6,91 @@ use ReflectionClass;
class Rounding_mode
{
- public const HALF_UP = PHP_ROUND_HALF_UP; //TODO: These constants need to be moved to constants.php
- public const HALF_DOWN = PHP_ROUND_HALF_DOWN;
- public const HALF_EVEN = PHP_ROUND_HALF_EVEN;
- public const HALF_ODD = PHP_ROUND_HALF_ODD;
- public const ROUND_UP = 5;
- public const ROUND_DOWN = 6;
- public const HALF_FIVE = 7;
+ public const HALF_UP = PHP_ROUND_HALF_UP; //TODO: These constants need to be moved to constants.php
+ public const HALF_DOWN = PHP_ROUND_HALF_DOWN;
+ public const HALF_EVEN = PHP_ROUND_HALF_EVEN;
+ public const HALF_ODD = PHP_ROUND_HALF_ODD;
+ public const ROUND_UP = 5;
+ public const ROUND_DOWN = 6;
+ public const HALF_FIVE = 7;
- public function __construct()
- {
- helper('language');
- }
+ public function __construct()
+ {
+ helper('language');
+ }
- /**
- * @return array
- */
- public static function get_rounding_options(): array
- {
- $class = new ReflectionClass(__CLASS__);
- $result = [];
+ /**
+ * @return array
+ */
+ public static function get_rounding_options(): array
+ {
+ $class = new ReflectionClass(__CLASS__);
+ $result = [];
- foreach($class->getConstants() as $key => $value)
- {
- $result[$value] = lang('Enum.' . strtolower($key));
- }
+ foreach($class->getConstants() as $key => $value)
+ {
+ $result[$value] = lang('Enum.' . strtolower($key));
+ }
- return $result;
- }
+ return $result;
+ }
- /**
- * @param int $code
- * @return string
- */
- public static function get_rounding_code_name(int $code): string
- {
- if(empty($code))
- {
- return lang('Common.unknown');
- }
+ /**
+ * @param int $code
+ * @return string
+ */
+ public static function get_rounding_code_name(int $code): string
+ {
+ if(empty($code))
+ {
+ return lang('Common.unknown');
+ }
- return Rounding_mode::get_rounding_options()[$code];
- }
+ return Rounding_mode::get_rounding_options()[$code];
+ }
- /**
- * @return string
- */
- public static function get_html_rounding_options(): string
- {
- $x = '';
+ /**
+ * @return string
+ */
+ public static function get_html_rounding_options(): string
+ {
+ $x = '';
- foreach(Rounding_mode::get_rounding_options() as $option => $label)
- {
- $x .= "";
- }
+ foreach(Rounding_mode::get_rounding_options() as $option => $label)
+ {
+ $x .= "";
+ }
- return $x;
- }
+ return $x;
+ }
- /**
- * @param int $rounding_mode
- * @param float $amount
- * @param int $decimals
- * @return string
- */
- public static function round_number(int $rounding_mode, float $amount, int $decimals): string
- {//TODO: this needs to be replaced with a switch statement
- if($rounding_mode == Rounding_mode::ROUND_UP)
- {
- $fig = pow(10, $decimals);
- $rounded_total = (ceil($fig*$amount) + ceil($fig*$amount - ceil($fig*$amount)))/$fig;
- }
- elseif($rounding_mode == Rounding_mode::ROUND_DOWN)
- {
- $fig = pow(10, $decimals);
- $rounded_total = (floor($fig*$amount) + floor($fig*$amount - floor($fig*$amount)))/$fig;
- }
- elseif($rounding_mode == Rounding_mode::HALF_FIVE)
- {
- $rounded_total = round($amount / 5, $decimals, Rounding_mode::HALF_EVEN) * 5;
- }
- else
- {
- $rounded_total = round ( $amount, $decimals, $rounding_mode);
- }
+ /**
+ * @param int $rounding_mode
+ * @param float $amount
+ * @param int $decimals
+ * @return string
+ */
+ public static function round_number(int $rounding_mode, float $amount, int $decimals): string
+ {//TODO: this needs to be replaced with a switch statement
+ if($rounding_mode == Rounding_mode::ROUND_UP)
+ {
+ $fig = pow(10, $decimals);
+ $rounded_total = (ceil($fig*$amount) + ceil($fig*$amount - ceil($fig*$amount)))/$fig;
+ }
+ elseif($rounding_mode == Rounding_mode::ROUND_DOWN)
+ {
+ $fig = pow(10, $decimals);
+ $rounded_total = (floor($fig*$amount) + floor($fig*$amount - floor($fig*$amount)))/$fig;
+ }
+ elseif($rounding_mode == Rounding_mode::HALF_FIVE)
+ {
+ $rounded_total = round($amount / 5, $decimals, Rounding_mode::HALF_EVEN) * 5;
+ }
+ else
+ {
+ $rounded_total = round ( $amount, $decimals, $rounding_mode);
+ }
- return $rounded_total;
- }
+ return $rounded_total;
+ }
}
diff --git a/app/Models/Expense.php b/app/Models/Expense.php
index 658c4b3f7..a28940d29 100644
--- a/app/Models/Expense.php
+++ b/app/Models/Expense.php
@@ -12,376 +12,376 @@ use stdClass;
*/
class Expense extends Model
{
- protected $table = 'expenses';
- protected $primaryKey = 'expense_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'date',
- 'amount',
- 'payment_type',
- 'expense_category_id',
- 'description',
- 'employee_id',
- 'deleted',
- 'supplier_tax_code',
- 'tax_amount',
- 'supplier_id'
- ];
+ protected $table = 'expenses';
+ protected $primaryKey = 'expense_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'date',
+ 'amount',
+ 'payment_type',
+ 'expense_category_id',
+ 'description',
+ 'employee_id',
+ 'deleted',
+ 'supplier_tax_code',
+ 'tax_amount',
+ 'supplier_id'
+ ];
- /**
- * Determines if a given Expense_id is an Expense
- */
- public function exists(int $expense_id): bool
- {
- $builder = $this->db->table('expenses');
- $builder->where('expense_id', $expense_id);
+ /**
+ * Determines if a given Expense_id is an Expense
+ */
+ public function exists(int $expense_id): bool
+ {
+ $builder = $this->db->table('expenses');
+ $builder->where('expense_id', $expense_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets category info
- */
- public function get_expense_category(int $expense_id): object //TODO: This function is never called in the code
- {
- $builder = $this->db->table('expenses');
- $builder->where('expense_id', $expense_id);
+ /**
+ * Gets category info
+ */
+ public function get_expense_category(int $expense_id): object //TODO: This function is never called in the code
+ {
+ $builder = $this->db->table('expenses');
+ $builder->where('expense_id', $expense_id);
- $expense_category = model(Expense_category::class);
- return $expense_category->get_info($builder->get()->getRow()->expense_category_id); //TODO: refactor out the nested function call.
- }
+ $expense_category = model(Expense_category::class);
+ return $expense_category->get_info($builder->get()->getRow()->expense_category_id); //TODO: refactor out the nested function call.
+ }
- /**
- * Gets employee info
- */
- public function get_employee(int $expense_id): object //TODO: This function is never called in the code
- {
- $builder = $this->db->table('expenses');
- $builder->where('expense_id', $expense_id);
+ /**
+ * Gets employee info
+ */
+ public function get_employee(int $expense_id): object //TODO: This function is never called in the code
+ {
+ $builder = $this->db->table('expenses');
+ $builder->where('expense_id', $expense_id);
- $employee = model(Employee::class);
+ $employee = model(Employee::class);
- return $employee->get_info($builder->get()->getRow()->employee_id); //TODO: refactor out the nested function call.
- }
+ return $employee->get_info($builder->get()->getRow()->employee_id); //TODO: refactor out the nested function call.
+ }
- /**
- * @param array $expense_ids
- * @return ResultInterface
- */
- public function get_multiple_info(array $expense_ids): ResultInterface
- {
- $builder = $this->db->table('expenses');
- $builder->whereIn('expenses.expense_id', $expense_ids);
- $builder->orderBy('expense_id', 'asc');
+ /**
+ * @param array $expense_ids
+ * @return ResultInterface
+ */
+ public function get_multiple_info(array $expense_ids): ResultInterface
+ {
+ $builder = $this->db->table('expenses');
+ $builder->whereIn('expenses.expense_id', $expense_ids);
+ $builder->orderBy('expense_id', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search, array $filters): int
- {
- return $this->search($search, $filters, 0, 0, 'expense_id', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search, array $filters): int
+ {
+ return $this->search($search, $filters, 0, 0, 'expense_id', 'asc', true);
+ }
- /**
- * Searches expenses
- *
- * @param string $search
- * @param array $filters
- * @param int|null $rows
- * @param int|null $limit_from
- * @param string|null $sort
- * @param string|null $order
- * @param bool|null $count_only
- * @return ResultInterface|false|string
- */
- public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'expense_id', ?string $order = 'asc', ?bool $count_only = false): false|string|ResultInterface
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'expense_id';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Searches expenses
+ *
+ * @param string $search
+ * @param array $filters
+ * @param int|null $rows
+ * @param int|null $limit_from
+ * @param string|null $sort
+ * @param string|null $order
+ * @param bool|null $count_only
+ * @return ResultInterface|false|string
+ */
+ public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'expense_id', ?string $order = 'asc', ?bool $count_only = false): false|string|ResultInterface
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'expense_id';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('expenses AS expenses');
+ $config = config(OSPOS::class)->settings;
+ $builder = $this->db->table('expenses AS expenses');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(DISTINCT expenses.expense_id) as count');
- }
- else
- {
- $builder->select('
- expenses.expense_id,
- MAX(expenses.date) AS date,
- MAX(suppliers.company_name) AS supplier_name,
- MAX(expenses.supplier_tax_code) AS supplier_tax_code,
- MAX(expenses.amount) AS amount,
- MAX(expenses.tax_amount) AS tax_amount,
- MAX(expenses.payment_type) AS payment_type,
- MAX(expenses.description) AS description,
- MAX(employees.first_name) AS first_name,
- MAX(employees.last_name) AS last_name,
- MAX(expense_categories.category_name) AS category_name
- ');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(DISTINCT expenses.expense_id) as count');
+ }
+ else
+ {
+ $builder->select('
+ expenses.expense_id,
+ MAX(expenses.date) AS date,
+ MAX(suppliers.company_name) AS supplier_name,
+ MAX(expenses.supplier_tax_code) AS supplier_tax_code,
+ MAX(expenses.amount) AS amount,
+ MAX(expenses.tax_amount) AS tax_amount,
+ MAX(expenses.payment_type) AS payment_type,
+ MAX(expenses.description) AS description,
+ MAX(employees.first_name) AS first_name,
+ MAX(employees.last_name) AS last_name,
+ MAX(expense_categories.category_name) AS category_name
+ ');
+ }
- $builder->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT');
- $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
- $builder->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT');
+ $builder->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT');
+ $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
+ $builder->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT');
- $builder->groupStart();
- $builder->like('employees.first_name', $search);
- $builder->orLike('expenses.date', $search);
- $builder->orLike('employees.last_name', $search);
- $builder->orLike('expenses.payment_type', $search);
- $builder->orLike('expenses.amount', $search);
- $builder->orLike('expense_categories.category_name', $search);
- $builder->orLike('CONCAT(employees.first_name, " ", employees.last_name)', $search);
- $builder->groupEnd();
+ $builder->groupStart();
+ $builder->like('employees.first_name', $search);
+ $builder->orLike('expenses.date', $search);
+ $builder->orLike('employees.last_name', $search);
+ $builder->orLike('expenses.payment_type', $search);
+ $builder->orLike('expenses.amount', $search);
+ $builder->orLike('expense_categories.category_name', $search);
+ $builder->orLike('CONCAT(employees.first_name, " ", employees.last_name)', $search);
+ $builder->groupEnd();
- $builder->where('expenses.deleted', $filters['is_deleted']);
+ $builder->where('expenses.deleted', $filters['is_deleted']);
- if(empty($config['date_or_time_format']))
- {
- $builder->where('DATE_FORMAT(expenses.date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
- }
- else
- {
- $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
- }
+ if(empty($config['date_or_time_format']))
+ {
+ $builder->where('DATE_FORMAT(expenses.date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
+ }
+ else
+ {
+ $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
+ }
- if($filters['only_debit'])
- {
- $builder->like('expenses.payment_type', lang('Expenses.debit'));
- }
+ if($filters['only_debit'])
+ {
+ $builder->like('expenses.payment_type', lang('Expenses.debit'));
+ }
- if($filters['only_credit'])
- {
- $builder->like('expenses.payment_type', lang('Expenses.credit'));
- }
+ if($filters['only_credit'])
+ {
+ $builder->like('expenses.payment_type', lang('Expenses.credit'));
+ }
- if($filters['only_cash'])
- {
- $builder->groupStart();
- $builder->like('expenses.payment_type', lang('Expenses.cash'));
- $builder->orWhere('expenses.payment_type IS NULL');
- $builder->groupEnd();
- }
+ if($filters['only_cash'])
+ {
+ $builder->groupStart();
+ $builder->like('expenses.payment_type', lang('Expenses.cash'));
+ $builder->orWhere('expenses.payment_type IS NULL');
+ $builder->groupEnd();
+ }
- if($filters['only_due'])
- {
- $builder->like('expenses.payment_type', lang('Expenses.due'));
- }
+ if($filters['only_due'])
+ {
+ $builder->like('expenses.payment_type', lang('Expenses.due'));
+ }
- if($filters['only_check'])
- {
- $builder->like('expenses.payment_type', lang('Expenses.check'));
- }
+ if($filters['only_check'])
+ {
+ $builder->like('expenses.payment_type', lang('Expenses.check'));
+ }
- if($count_only) //TODO: replace this with `if($count_only)`
- {
- return $builder->get()->getRow()->count;
- }
+ if($count_only) //TODO: replace this with `if($count_only)`
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->groupBy('expense_id');
+ $builder->groupBy('expense_id');
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets information about a particular expense
- */
- public function get_info(int $expense_id): object
- {
- $builder = $this->db->table('expenses AS expenses');
- $builder->select('
- expenses.expense_id AS expense_id,
- expenses.date AS date,
- suppliers.company_name AS supplier_name,
- expenses.supplier_id AS supplier_id,
- expenses.supplier_tax_code AS supplier_tax_code,
- expenses.amount AS amount,
- expenses.tax_amount AS tax_amount,
- expenses.payment_type AS payment_type,
- expenses.description AS description,
- expenses.employee_id AS employee_id,
- expenses.deleted AS deleted,
- employees.first_name AS first_name,
- employees.last_name AS last_name,
- expense_categories.expense_category_id AS expense_category_id,
- expense_categories.category_name AS category_name
- ');
+ /**
+ * Gets information about a particular expense
+ */
+ public function get_info(int $expense_id): object
+ {
+ $builder = $this->db->table('expenses AS expenses');
+ $builder->select('
+ expenses.expense_id AS expense_id,
+ expenses.date AS date,
+ suppliers.company_name AS supplier_name,
+ expenses.supplier_id AS supplier_id,
+ expenses.supplier_tax_code AS supplier_tax_code,
+ expenses.amount AS amount,
+ expenses.tax_amount AS tax_amount,
+ expenses.payment_type AS payment_type,
+ expenses.description AS description,
+ expenses.employee_id AS employee_id,
+ expenses.deleted AS deleted,
+ employees.first_name AS first_name,
+ employees.last_name AS last_name,
+ expense_categories.expense_category_id AS expense_category_id,
+ expense_categories.category_name AS category_name
+ ');
- $builder->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT');
- $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
- $builder->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT');
- $builder->where('expense_id', $expense_id);
+ $builder->join('people AS employees', 'employees.person_id = expenses.employee_id', 'LEFT');
+ $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
+ $builder->join('suppliers AS suppliers', 'suppliers.person_id = expenses.supplier_id', 'LEFT');
+ $builder->where('expense_id', $expense_id);
- $query = $builder->get();
+ $query = $builder->get();
- if ($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
+ if ($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
- $empty_obj = $this->getEmptyObject('expenses');
- $empty_obj->supplier_name = null;
- $empty_obj->first_name = null;
- $empty_obj->last_name = null;
+ $empty_obj = $this->getEmptyObject('expenses');
+ $empty_obj->supplier_name = null;
+ $empty_obj->first_name = null;
+ $empty_obj->last_name = null;
- return $empty_obj;
- }
+ return $empty_obj;
+ }
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
- return $empty_obj;
- }
+ return $empty_obj;
+ }
- /**
- * Inserts or updates an expense
- */
- public function save_value(array &$expense_data, int $expense_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('expenses');
+ /**
+ * Inserts or updates an expense
+ */
+ public function save_value(array &$expense_data, int $expense_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('expenses');
- if($expense_id == NEW_ENTRY || !$this->exists($expense_id))
- {
- if($builder->insert($expense_data))
- {
- $expense_data['expense_id'] = $this->db->insertID();
+ if($expense_id == NEW_ENTRY || !$this->exists($expense_id))
+ {
+ if($builder->insert($expense_data))
+ {
+ $expense_data['expense_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('expense_id', $expense_id);
+ $builder->where('expense_id', $expense_id);
- return $builder->update($expense_data);
- }
+ return $builder->update($expense_data);
+ }
- /**
- * Deletes a list of expense_category
- */
- public function delete_list(array $expense_ids): bool
- {
- $builder = $this->db->table('expenses');
+ /**
+ * Deletes a list of expense_category
+ */
+ public function delete_list(array $expense_ids): bool
+ {
+ $builder = $this->db->table('expenses');
- $this->db->transStart();
- $builder->whereIn('expense_id', $expense_ids);
- $success = $builder->update(['deleted' => 1]);
- $this->db->transComplete();
+ $this->db->transStart();
+ $builder->whereIn('expense_id', $expense_ids);
+ $success = $builder->update(['deleted' => 1]);
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Gets the payment summary for the expenses (expenses/manage) view
- */
- public function get_payments_summary(string $search, array $filters): array //TODO: $search is passed but never used in the function
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * Gets the payment summary for the expenses (expenses/manage) view
+ */
+ public function get_payments_summary(string $search, array $filters): array //TODO: $search is passed but never used in the function
+ {
+ $config = config(OSPOS::class)->settings;
- // get payment summary
- $builder = $this->db->table('expenses');
- $builder->select('payment_type, COUNT(amount) AS count, SUM(amount) AS amount');
- $builder->where('deleted', $filters['is_deleted']);
+ // get payment summary
+ $builder = $this->db->table('expenses');
+ $builder->select('payment_type, COUNT(amount) AS count, SUM(amount) AS amount');
+ $builder->where('deleted', $filters['is_deleted']);
- if(empty($config['date_or_time_format']))
- {
- $builder->where('DATE_FORMAT(date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
- }
- else
- {
- $builder->where('date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
- }
+ if(empty($config['date_or_time_format']))
+ {
+ $builder->where('DATE_FORMAT(date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
+ }
+ else
+ {
+ $builder->where('date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
+ }
- if($filters['only_cash'])
- {
- $builder->like('payment_type', lang('Expenses.cash'));
- }
+ if($filters['only_cash'])
+ {
+ $builder->like('payment_type', lang('Expenses.cash'));
+ }
- if($filters['only_due'])
- {
- $builder->like('payment_type', lang('Expenses.due'));
- }
+ if($filters['only_due'])
+ {
+ $builder->like('payment_type', lang('Expenses.due'));
+ }
- if($filters['only_check'])
- {
- $builder->like('payment_type', lang('Expenses.check'));
- }
+ if($filters['only_check'])
+ {
+ $builder->like('payment_type', lang('Expenses.check'));
+ }
- if($filters['only_credit'])
- {
- $builder->like('payment_type', lang('Expenses.credit'));
- }
+ if($filters['only_credit'])
+ {
+ $builder->like('payment_type', lang('Expenses.credit'));
+ }
- if($filters['only_debit'])
- {
- $builder->like('payment_type', lang('Expenses.debit'));
- }
+ if($filters['only_debit'])
+ {
+ $builder->like('payment_type', lang('Expenses.debit'));
+ }
- $builder->groupBy('payment_type');
+ $builder->groupBy('payment_type');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
- /**
- * Gets the payment options to show in the expense forms
- */
- public function get_payment_options(): array
- {
- return get_payment_options();
- }
+ /**
+ * Gets the payment options to show in the expense forms
+ */
+ public function get_payment_options(): array
+ {
+ return get_payment_options();
+ }
- /**
- * Gets the expense payment
- */
- public function get_expense_payment(int $expense_id): ResultInterface
- {
- $builder = $this->db->table('expenses');
- $builder->where('expense_id', $expense_id);
+ /**
+ * Gets the expense payment
+ */
+ public function get_expense_payment(int $expense_id): ResultInterface
+ {
+ $builder = $this->db->table('expenses');
+ $builder->where('expense_id', $expense_id);
- return $builder->get();
- }
+ return $builder->get();
+ }
}
diff --git a/app/Models/Expense_category.php b/app/Models/Expense_category.php
index 43d486ef0..4249e5433 100644
--- a/app/Models/Expense_category.php
+++ b/app/Models/Expense_category.php
@@ -11,183 +11,183 @@ use stdClass;
*/
class Expense_category extends Model
{
- protected $table = 'expense_categories';
- protected $primaryKey = 'expense_category_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'category_name',
- 'category_description',
- 'deleted'
- ];
+ protected $table = 'expense_categories';
+ protected $primaryKey = 'expense_category_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'category_name',
+ 'category_description',
+ 'deleted'
+ ];
- /**
- * Determines if a given Expense_id is an Expense category
- */
- public function exists(int $expense_category_id): bool
- {
- $builder = $this->db->table('expense_categories');
- $builder->where('expense_category_id', $expense_category_id);
+ /**
+ * Determines if a given Expense_id is an Expense category
+ */
+ public function exists(int $expense_category_id): bool
+ {
+ $builder = $this->db->table('expense_categories');
+ $builder->where('expense_category_id', $expense_category_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('expense_categories');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('expense_categories');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about a particular category
- */
- public function get_info(int $expense_category_id): object
- {
- $builder = $this->db->table('expense_categories');
- $builder->where('expense_category_id', $expense_category_id);
- $builder->where('deleted', 0);
- $query = $builder->get();
+ /**
+ * Gets information about a particular category
+ */
+ public function get_info(int $expense_category_id): object
+ {
+ $builder = $this->db->table('expense_categories');
+ $builder->where('expense_category_id', $expense_category_id);
+ $builder->where('deleted', 0);
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object, as $item_kit_id is NOT an item kit
- $expense_obj = new stdClass();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object, as $item_kit_id is NOT an item kit
+ $expense_obj = new stdClass();
- //Get all the fields from items table
- foreach($this->db->getFieldNames('expense_categories') as $field)
- {
- $expense_obj->$field = '';
- }
+ //Get all the fields from items table
+ foreach($this->db->getFieldNames('expense_categories') as $field)
+ {
+ $expense_obj->$field = '';
+ }
- return $expense_obj;
- }
- }
+ return $expense_obj;
+ }
+ }
- /**
- * Returns all the expense_categories
- */
- public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = false): ResultInterface
- {
- $builder = $this->db->table('expense_categories');
+ /**
+ * Returns all the expense_categories
+ */
+ public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = false): ResultInterface
+ {
+ $builder = $this->db->table('expense_categories');
- if($no_deleted)
- {
- $builder->where('deleted', 0);
- }
+ if($no_deleted)
+ {
+ $builder->where('deleted', 0);
+ }
- $builder->orderBy('category_name', 'asc');
+ $builder->orderBy('category_name', 'asc');
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets information about multiple expense_category_id
- */
- public function get_multiple_info(array $expense_category_ids): ResultInterface
- {
- $builder = $this->db->table('expense_categories');
- $builder->whereIn('expense_category_id', $expense_category_ids);
- $builder->orderBy('category_name', 'asc');
+ /**
+ * Gets information about multiple expense_category_id
+ */
+ public function get_multiple_info(array $expense_category_ids): ResultInterface
+ {
+ $builder = $this->db->table('expense_categories');
+ $builder->whereIn('expense_category_id', $expense_category_ids);
+ $builder->orderBy('category_name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates an expense_category
- */
- public function save_value(array &$expense_category_data, int $expense_category_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('expense_categories');
+ /**
+ * Inserts or updates an expense_category
+ */
+ public function save_value(array &$expense_category_data, int $expense_category_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('expense_categories');
- if($expense_category_id == NEW_ENTRY || !$this->exists($expense_category_id))
- {
- if($builder->insert($expense_category_data))
- {
- $expense_category_data['expense_category_id'] = $this->db->insertID();
+ if($expense_category_id == NEW_ENTRY || !$this->exists($expense_category_id))
+ {
+ if($builder->insert($expense_category_data))
+ {
+ $expense_category_data['expense_category_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('expense_category_id', $expense_category_id);
+ $builder->where('expense_category_id', $expense_category_id);
- return $builder->update($expense_category_data);
- }
+ return $builder->update($expense_category_data);
+ }
- /**
- * Deletes a list of expense_category
- */
- public function delete_list(array $expense_category_ids): bool
- {
- $builder = $this->db->table('expense_categories');
- $builder->whereIn('expense_category_id', $expense_category_ids);
+ /**
+ * Deletes a list of expense_category
+ */
+ public function delete_list(array $expense_category_ids): bool
+ {
+ $builder = $this->db->table('expense_categories');
+ $builder->whereIn('expense_category_id', $expense_category_ids);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'category_name', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'category_name', 'asc', true);
+ }
- /**
- * Perform a search on expense_category
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'category_name', ?string $order='asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'category_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Perform a search on expense_category
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'category_name', ?string $order='asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'category_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('expense_categories AS expense_categories');
+ $builder = $this->db->table('expense_categories AS expense_categories');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(expense_categories.expense_category_id) as count');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(expense_categories.expense_category_id) as count');
+ }
- $builder->groupStart();
- $builder->like('category_name', $search);
- $builder->orLike('category_description', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
+ $builder->groupStart();
+ $builder->like('category_name', $search);
+ $builder->orLike('category_description', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
}
diff --git a/app/Models/Giftcard.php b/app/Models/Giftcard.php
index cbdaa9f24..1e97c2de0 100644
--- a/app/Models/Giftcard.php
+++ b/app/Models/Giftcard.php
@@ -11,370 +11,370 @@ use stdClass;
*/
class Giftcard extends Model
{
- protected $table = 'giftcards';
- protected $primaryKey = 'giftcard_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'giftcard_number',
- 'value',
- 'deleted',
- 'person_id',
- 'record_time'
- ];
+ protected $table = 'giftcards';
+ protected $primaryKey = 'giftcard_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'giftcard_number',
+ 'value',
+ 'deleted',
+ 'person_id',
+ 'record_time'
+ ];
- /**
- * Determines if a given giftcard_id is a giftcard
- */
- public function exists(int $giftcard_id): bool
- {
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_id', $giftcard_id);
- $builder->where('deleted', 0);
+ /**
+ * Determines if a given giftcard_id is a giftcard
+ */
+ public function exists(int $giftcard_id): bool
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_id', $giftcard_id);
+ $builder->where('deleted', 0);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets max gift card number //TODO: This isn't entirely accurate. It returns the object and the results then pulls the giftcard_number
- */
- public function get_max_number(): ?object
- {
- $builder = $this->db->table('giftcards');
- $builder->select('CAST(giftcard_number AS UNSIGNED) AS giftcard_number');
- $builder->where('giftcard_number REGEXP \'^[0-9]+$\'');
- $builder->orderBy("giftcard_number","desc");
- $builder->limit(1);
+ /**
+ * Gets max gift card number //TODO: This isn't entirely accurate. It returns the object and the results then pulls the giftcard_number
+ */
+ public function get_max_number(): ?object
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->select('CAST(giftcard_number AS UNSIGNED) AS giftcard_number');
+ $builder->where('giftcard_number REGEXP \'^[0-9]+$\'');
+ $builder->orderBy("giftcard_number","desc");
+ $builder->limit(1);
- return $builder->get()->getRow();
- }
+ return $builder->get()->getRow();
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('giftcards');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about a particular giftcard
- */
- public function get_info(int $giftcard_id): object
- {
- $builder = $this->db->table('giftcards');
- $builder->join('people', 'people.person_id = giftcards.person_id', 'left');
- $builder->where('giftcard_id', $giftcard_id);
- $builder->where('deleted', 0);
+ /**
+ * Gets information about a particular giftcard
+ */
+ public function get_info(int $giftcard_id): object
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->join('people', 'people.person_id = giftcards.person_id', 'left');
+ $builder->where('giftcard_id', $giftcard_id);
+ $builder->where('deleted', 0);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
- {
- return $this->getEmptyObject('giftcards');
- }
- }
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else //TODO: No need for this else statement. Just put it's contents outside of the else since the if has a return in it.
+ {
+ return $this->getEmptyObject('giftcards');
+ }
+ }
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
- return $empty_obj;
- }
+ return $empty_obj;
+ }
- /**
- * Gets a giftcard id given a giftcard number
- */
- public function get_giftcard_id(string $giftcard_number): bool
- {
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcard_number);
- $builder->where('deleted', 0);
+ /**
+ * Gets a giftcard id given a giftcard number
+ */
+ public function get_giftcard_id(string $giftcard_number): bool
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcard_number);
+ $builder->where('deleted', 0);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow()->giftcard_id;
- }
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow()->giftcard_id;
+ }
- return false;
- }
+ return false;
+ }
- /**
- * Gets information about multiple giftcards
- */
- public function get_multiple_info(array $giftcard_ids): ResultInterface
- {
- $builder = $this->db->table('giftcards');
- $builder->whereIn('giftcard_id', $giftcard_ids);
- $builder->where('deleted', 0);
- $builder->orderBy('giftcard_number', 'asc');
+ /**
+ * Gets information about multiple giftcards
+ */
+ public function get_multiple_info(array $giftcard_ids): ResultInterface
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->whereIn('giftcard_id', $giftcard_ids);
+ $builder->where('deleted', 0);
+ $builder->orderBy('giftcard_number', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a giftcard
- */
- public function save_value(array &$giftcard_data, int $giftcard_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('giftcards');
+ /**
+ * Inserts or updates a giftcard
+ */
+ public function save_value(array &$giftcard_data, int $giftcard_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('giftcards');
- if($giftcard_id == NEW_ENTRY || !$this->exists($giftcard_id))
- {
- if($builder->insert($giftcard_data))
- {
- $giftcard_data['giftcard_number'] = $this->db->insertID();
- $giftcard_data['giftcard_id'] = $this->db->insertID();
+ if($giftcard_id == NEW_ENTRY || !$this->exists($giftcard_id))
+ {
+ if($builder->insert($giftcard_data))
+ {
+ $giftcard_data['giftcard_number'] = $this->db->insertID();
+ $giftcard_data['giftcard_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('giftcard_id', $giftcard_id);
+ $builder->where('giftcard_id', $giftcard_id);
- return $builder->update($giftcard_data);
- }
+ return $builder->update($giftcard_data);
+ }
- /**
- * Updates multiple giftcards at once
- */
- public function update_multiple(array $giftcard_data, array $giftcard_ids): bool //TODO: This function appears to never be used in the code.
- {
- $builder = $this->db->table('giftcards');
- $builder->whereIn('giftcard_id', $giftcard_ids);
+ /**
+ * Updates multiple giftcards at once
+ */
+ public function update_multiple(array $giftcard_data, array $giftcard_ids): bool //TODO: This function appears to never be used in the code.
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->whereIn('giftcard_id', $giftcard_ids);
- return $builder->update($giftcard_data);
- }
+ return $builder->update($giftcard_data);
+ }
- /**
- * Deletes one giftcard
- */
- public function delete($giftcard_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_id', $giftcard_id);
+ /**
+ * Deletes one giftcard
+ */
+ public function delete($giftcard_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_id', $giftcard_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Deletes a list of giftcards
- */
- public function delete_list(array $giftcard_ids): bool
- {
- $builder = $this->db->table('giftcards');
- $builder->whereIn('giftcard_id', $giftcard_ids);
+ /**
+ * Deletes a list of giftcards
+ */
+ public function delete_list(array $giftcard_ids): bool
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->whereIn('giftcard_id', $giftcard_ids);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Get search suggestions to find giftcards
- */
- public function get_search_suggestions(string $search, int $limit = 25): array
- {
- $suggestions = [];
+ /**
+ * Get search suggestions to find giftcards
+ */
+ public function get_search_suggestions(string $search, int $limit = 25): array
+ {
+ $suggestions = [];
- $builder = $this->db->table('giftcards');
- $builder->like('giftcard_number', $search);
- $builder->where('deleted', 0);
- $builder->orderBy('giftcard_number', 'asc');
+ $builder = $this->db->table('giftcards');
+ $builder->like('giftcard_number', $search);
+ $builder->where('deleted', 0);
+ $builder->orderBy('giftcard_number', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[]= ['label' => $row->giftcard_number];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[]= ['label' => $row->giftcard_number];
+ }
- $builder = $this->db->table('customers');
- $builder->join('people', 'customers.person_id = people.person_id', 'left');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
- $builder->orderBy('last_name', 'asc');
+ $builder = $this->db->table('customers');
+ $builder->join('people', 'customers.person_id = people.person_id', 'left');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
+ $builder->orderBy('last_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->first_name.' '.$row->last_name];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->first_name.' '.$row->last_name];
+ }
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * Gets gift cards
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'giftcard_number', 'asc', true);
- }
+ /**
+ * Gets gift cards
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'giftcard_number', 'asc', true);
+ }
- /**
- * Performs a search on giftcards
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'giftcard_number', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'giftcard_number';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Performs a search on giftcards
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'giftcard_number', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'giftcard_number';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'giftcard_number';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'giftcard_number';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('giftcards');
+ $builder = $this->db->table('giftcards');
- // get_found_rows case
- if($count_only) //TODO: replace this with `if($count_only)`
- {
- $builder->select('COUNT(giftcard_id) as count');
- }
+ // get_found_rows case
+ if($count_only) //TODO: replace this with `if($count_only)`
+ {
+ $builder->select('COUNT(giftcard_id) as count');
+ }
- $builder->join('people AS person', 'giftcards.person_id = person.person_id', 'left');
- $builder->groupStart();
- $builder->like('person.first_name', $search);
- $builder->orLike('person.last_name', $search);
- $builder->orLike('CONCAT(person.first_name, " ", person.last_name)', $search);
- $builder->orLike('giftcards.giftcard_number', $search);
- $builder->orLike('giftcards.person_id', $search);
- $builder->groupEnd();
- $builder->where('giftcards.deleted', 0);
+ $builder->join('people AS person', 'giftcards.person_id = person.person_id', 'left');
+ $builder->groupStart();
+ $builder->like('person.first_name', $search);
+ $builder->orLike('person.last_name', $search);
+ $builder->orLike('CONCAT(person.first_name, " ", person.last_name)', $search);
+ $builder->orLike('giftcards.giftcard_number', $search);
+ $builder->orLike('giftcards.person_id', $search);
+ $builder->groupEnd();
+ $builder->where('giftcards.deleted', 0);
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets gift card value
- */
- public function get_giftcard_value(string $giftcard_number): float //TODO: we may need to do a search for all float values and for currencies cast them to strings at the point where we get them from the database.
- {
- if(!$this->exists($this->get_giftcard_id($giftcard_number)))
- {
- return 0;
- }
+ /**
+ * Gets gift card value
+ */
+ public function get_giftcard_value(string $giftcard_number): float //TODO: we may need to do a search for all float values and for currencies cast them to strings at the point where we get them from the database.
+ {
+ if(!$this->exists($this->get_giftcard_id($giftcard_number)))
+ {
+ return 0;
+ }
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcard_number);
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcard_number);
- return $builder->get()->getRow()->value;
- }
+ return $builder->get()->getRow()->value;
+ }
- /**
- * Updates gift card value
- */
- public function update_giftcard_value(string $giftcard_number, float $value): void //TODO: Should we return the value of update like other similar functions do?
- {
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcard_number);
- $builder->update(['value' => $value]);
- }
+ /**
+ * Updates gift card value
+ */
+ public function update_giftcard_value(string $giftcard_number, float $value): void //TODO: Should we return the value of update like other similar functions do?
+ {
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcard_number);
+ $builder->update(['value' => $value]);
+ }
- /**
- * Determines if a given giftcard_name exists
- */
- public function exists_giftcard_name($giftcard_name): bool
- {
- $giftcard_name = strtoupper($giftcard_name);
+ /**
+ * Determines if a given giftcard_name exists
+ */
+ public function exists_giftcard_name($giftcard_name): bool
+ {
+ $giftcard_name = strtoupper($giftcard_name);
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcard_name);
- $builder->where('deleted', 0);
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcard_name);
+ $builder->where('deleted', 0);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Generate unique gift card name/number
- */
- public function generate_unique_giftcard_name(string $value): string
- {
- $value = str_replace('.', 'DE', $value);
- $random = bin2hex(openssl_random_pseudo_bytes(3));
- $giftcard_name = "$random-$value";
+ /**
+ * Generate unique gift card name/number
+ */
+ public function generate_unique_giftcard_name(string $value): string
+ {
+ $value = str_replace('.', 'DE', $value);
+ $random = bin2hex(openssl_random_pseudo_bytes(3));
+ $giftcard_name = "$random-$value";
- if($this->exists_giftcard_name($giftcard_name))
- {
- $this->generate_unique_giftcard_name($value);
- }
+ if($this->exists_giftcard_name($giftcard_name))
+ {
+ $this->generate_unique_giftcard_name($value);
+ }
- return strtoupper($giftcard_name);
- }
+ return strtoupper($giftcard_name);
+ }
- /**
- * Gets gift card customer_id by gift card number
- *
- * @param string $giftcard_number Gift card number
- * @return int The customer_id of the gift card if it exists, 0 otherwise.
- */
- public function get_giftcard_customer(string $giftcard_number): int
- {
- if(!$this->exists($this->get_giftcard_id($giftcard_number)))
- {
- return 0;
- }
+ /**
+ * Gets gift card customer_id by gift card number
+ *
+ * @param string $giftcard_number Gift card number
+ * @return int The customer_id of the gift card if it exists, 0 otherwise.
+ */
+ public function get_giftcard_customer(string $giftcard_number): int
+ {
+ if(!$this->exists($this->get_giftcard_id($giftcard_number)))
+ {
+ return 0;
+ }
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcard_number);
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcard_number);
- return $builder->get()->getRow()->person_id;
- }
+ return $builder->get()->getRow()->person_id;
+ }
}
diff --git a/app/Models/Inventory.php b/app/Models/Inventory.php
index 33f228f68..56127e804 100644
--- a/app/Models/Inventory.php
+++ b/app/Models/Inventory.php
@@ -13,91 +13,91 @@ use CodeIgniter\Model;
*/
class Inventory extends Model
{
- protected $table = 'inventory';
- protected $primaryKey = 'trans_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'trans_items',
- 'trans_user',
- 'trans_date',
- 'trans_comment',
- 'trans_inventory',
- 'trans_location'
- ];
+ protected $table = 'inventory';
+ protected $primaryKey = 'trans_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'trans_items',
+ 'trans_user',
+ 'trans_date',
+ 'trans_comment',
+ 'trans_inventory',
+ 'trans_location'
+ ];
- /**
- * @param $comment
- * @param $inventory_data
- * @return bool
- */
- public function update($comment = null, $inventory_data = null): bool
- {
- $builder = $this->db->table('inventory');
- $builder->where('trans_comment', $comment);
+ /**
+ * @param $comment
+ * @param $inventory_data
+ * @return bool
+ */
+ public function update($comment = null, $inventory_data = null): bool
+ {
+ $builder = $this->db->table('inventory');
+ $builder->where('trans_comment', $comment);
- return $builder->update($inventory_data);
- }
+ return $builder->update($inventory_data);
+ }
- /**
- * Retrieves inventory data given an item_id.
- *
- * @param int $item_id
- * @param bool $location_id
- * @return ResultInterface
- */
- public function get_inventory_data_for_item(int $item_id, bool $location_id = false): ResultInterface
- {
- $builder = $this->db->table('inventory');
- $builder->where('trans_items', $item_id);
+ /**
+ * Retrieves inventory data given an item_id.
+ *
+ * @param int $item_id
+ * @param bool $location_id
+ * @return ResultInterface
+ */
+ public function get_inventory_data_for_item(int $item_id, bool $location_id = false): ResultInterface
+ {
+ $builder = $this->db->table('inventory');
+ $builder->where('trans_items', $item_id);
- if($location_id)
+ if($location_id)
{
$builder->where('trans_location', $location_id);
}
- $builder->orderBy('trans_date', 'desc');
+ $builder->orderBy('trans_date', 'desc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param int $item_id ID number for the item to have quantity reset.
- * @return bool|int|string The row id of the inventory table on insert or false on failure
- */
- public function reset_quantity(int $item_id): bool|int|string
- {
- $inventory_sums = $this->get_inventory_sum($item_id);
- foreach($inventory_sums as $inventory_sum)
- {
- if($inventory_sum['sum'] > 0)
- {
- $employee = model(Employee::class);
+ /**
+ * @param int $item_id ID number for the item to have quantity reset.
+ * @return bool|int|string The row id of the inventory table on insert or false on failure
+ */
+ public function reset_quantity(int $item_id): bool|int|string
+ {
+ $inventory_sums = $this->get_inventory_sum($item_id);
+ foreach($inventory_sums as $inventory_sum)
+ {
+ if($inventory_sum['sum'] > 0)
+ {
+ $employee = model(Employee::class);
- return $this->insert([
- 'trans_inventory' => -1 * $inventory_sum['sum'],
- 'trans_items' => $item_id,
- 'trans_location' => $inventory_sum['location_id'],
- 'trans_comment' => lang('Items.is_deleted'),
- 'trans_user' => $employee->get_logged_in_employee_info()->person_id
- ]);
- }
- }
+ return $this->insert([
+ 'trans_inventory' => -1 * $inventory_sum['sum'],
+ 'trans_items' => $item_id,
+ 'trans_location' => $inventory_sum['location_id'],
+ 'trans_comment' => lang('Items.is_deleted'),
+ 'trans_user' => $employee->get_logged_in_employee_info()->person_id
+ ]);
+ }
+ }
- return true;
- }
+ return true;
+ }
- /**
- * @param int $item_id
- * @return array
- */
- public function get_inventory_sum(int $item_id): array
- {
- $builder = $this->db->table('inventory');
- $builder->select('SUM(trans_inventory) AS sum, MAX(trans_location) AS location_id');
- $builder->where('trans_items', $item_id);
- $builder->groupBy('trans_location');
+ /**
+ * @param int $item_id
+ * @return array
+ */
+ public function get_inventory_sum(int $item_id): array
+ {
+ $builder = $this->db->table('inventory');
+ $builder->select('SUM(trans_inventory) AS sum, MAX(trans_location) AS location_id');
+ $builder->where('trans_items', $item_id);
+ $builder->groupBy('trans_location');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
}
diff --git a/app/Models/Item.php b/app/Models/Item.php
index 9f88b5185..1701e0143 100644
--- a/app/Models/Item.php
+++ b/app/Models/Item.php
@@ -16,1200 +16,1200 @@ use stdClass;
*/
class Item extends Model
{
- protected $table = 'items';
- protected $primaryKey = 'item_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'name',
- 'category',
- 'supplier_id',
- 'item_number',
- 'description',
- 'cost_price',
- 'unit_price',
- 'reorder_level',
- 'allow_alt_description',
- 'is_serialized',
- 'deleted',
- 'stock_type',
- 'item_type',
- 'tax_category_id',
- 'receiving_quantity',
- 'pic_filename',
- 'qty_per_pack',
- 'pack_name',
- 'low_sell_item_id',
- 'hsn_code'
- ];
-
-
- /**
- * Determines if a given item_id is an item
- */
- public function exists(int $item_id, bool $ignore_deleted = false, bool $deleted = false): bool
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
-
- if(!$ignore_deleted)
- {
- $builder->where('deleted', $deleted);
- }
-
- return ($builder->get()->getNumRows() === 1);
- }
-
- /**
- * Determines if a given item_number exists
- */
- public function item_number_exists(string $item_number, string $item_id = ''): bool
- {
- $config = config(OSPOS::class)->settings;
-
- if($config['allow_duplicate_barcodes'])
- {
- return false;
- }
-
- $builder = $this->db->table('items');
- $builder->where('item_number', $item_number);
- $builder->where('deleted !=', 1);
- $builder->where('item_id !=', intval($item_id));
-
-// // check if $item_id is a number and not a string starting with 0
-// // because cases like 00012345 will be seen as a number where it is a barcode
- if(ctype_digit($item_id) && !str_starts_with($item_id, '0'))
- {
- $builder->where('item_id !=', intval($item_id));
- }
- return ($builder->get()->getNumRows()) >= 1;
- }
-
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('items');
- $builder->where('deleted', 0);
-
- return $builder->countAllResults();
- }
-
- /**
- * @param int $tax_category_id
- * @return int
- */
- public function get_tax_category_usage(int $tax_category_id): int //TODO: This function is never called in the code.
- {
- $builder = $this->db->table('items');
- $builder->where('tax_category_id', $tax_category_id);
-
- return $builder->countAllResults();
- }
-
- /**
- * Get number of rows
- */
- public function get_found_rows(string $search, array $filters): int
- {
- return $this->search($search, $filters, 0, 0, 'items.name', 'asc', true);
- }
-
- /**
- * Perform a search on items
- */
- public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'items.name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null)
- {
- $rows = 0;
- }
- if($limit_from == null)
- {
- $limit_from = 0;
- }
- if($sort == null)
- {
- $sort = 'items.name';
- }
- if($order == null)
- {
- $order = 'asc';
- }
- if($count_only == null)
- {
- $count_only = false;
- }
-
- $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('items AS items'); //TODO: I'm not sure if it's needed to write items AS items... I think you can just get away with items
-
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(DISTINCT items.item_id) AS count');
- }
- else
- {
- $builder->select('MAX(items.item_id) AS item_id');
- $builder->select('MAX(items.name) AS name');
- $builder->select('MAX(items.category) AS category');
- $builder->select('MAX(items.supplier_id) AS supplier_id');
- $builder->select('MAX(items.item_number) AS item_number');
- $builder->select('MAX(items.description) AS description');
- $builder->select('MAX(items.cost_price) AS cost_price');
- $builder->select('MAX(items.unit_price) AS unit_price');
- $builder->select('MAX(items.reorder_level) AS reorder_level');
- $builder->select('MAX(items.receiving_quantity) AS receiving_quantity');
- $builder->select('MAX(items.pic_filename) AS pic_filename');
- $builder->select('MAX(items.allow_alt_description) AS allow_alt_description');
- $builder->select('MAX(items.is_serialized) AS is_serialized');
- $builder->select('MAX(items.pack_name) AS pack_name');
- $builder->select('MAX(items.tax_category_id) AS tax_category_id');
- $builder->select('MAX(items.deleted) AS deleted');
-
- $builder->select('MAX(suppliers.person_id) AS person_id');
- $builder->select('MAX(suppliers.company_name) AS company_name');
- $builder->select('MAX(suppliers.agency_name) AS agency_name');
- $builder->select('MAX(suppliers.account_number) AS account_number');
- $builder->select('MAX(suppliers.deleted) AS deleted');
-
- $builder->select('MAX(inventory.trans_id) AS trans_id');
- $builder->select('MAX(inventory.trans_items) AS trans_items');
- $builder->select('MAX(inventory.trans_user) AS trans_user');
- $builder->select('MAX(inventory.trans_date) AS trans_date');
- $builder->select('MAX(inventory.trans_comment) AS trans_comment');
- $builder->select('MAX(inventory.trans_location) AS trans_location');
- $builder->select('MAX(inventory.trans_inventory) AS trans_inventory');
-
- if($filters['stock_location_id'] > -1)
- {
- $builder->select('MAX(item_quantities.item_id) AS qty_item_id');
- $builder->select('MAX(item_quantities.location_id) AS location_id');
- $builder->select('MAX(item_quantities.quantity) AS quantity');
- }
- }
-
- $builder->join('suppliers AS suppliers', 'suppliers.person_id = items.supplier_id', 'left');
- $builder->join('inventory AS inventory', 'inventory.trans_items = items.item_id');
-
- if($filters['stock_location_id'] > -1)
- {
- $builder->join('item_quantities AS item_quantities', 'item_quantities.item_id = items.item_id');
- $builder->where('location_id', $filters['stock_location_id']);
- }
-
- $where = empty($config['date_or_time_format'])
- ? 'DATE_FORMAT(trans_date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date'])
- : 'trans_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']));
- $builder->where($where);
-
- $attributes_enabled = count($filters['definition_ids']) > 0;
-
- if(!empty($search))
- {
- if($attributes_enabled && $filters['search_custom'])
- {
- $builder->having("attribute_values LIKE '%$search%'");
- $builder->orHaving("attribute_dtvalues LIKE '%$search%'");
- $builder->orHaving("attribute_dvalues LIKE '%$search%'");
- }
- else
- {
- $builder->groupStart();
- $builder->like('name', $search);
- $builder->orLike('item_number', $search);
- $builder->orLike('items.item_id', $search);
- $builder->orLike('company_name', $search);
- $builder->orLike('items.category', $search);
- $builder->groupEnd();
- }
- }
-
- if($attributes_enabled)
- {
- $format = $this->db->escape(dateformat_mysql());
- $this->db->simpleQuery('SET SESSION group_concat_max_len=49152');
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
- $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
- $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id IS NULL AND attribute_links.sale_id IS NULL AND definition_id IN (' . implode(',', $filters['definition_ids']) . ')', 'left');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
- }
-
- $builder->where('items.deleted', $filters['is_deleted']);
-
- if($filters['empty_upc'])
- {
- $builder->where('item_number', null);
- }
- if($filters['low_inventory'])
- {
- $builder->where('quantity <=', 'reorder_level');
- }
- if($filters['is_serialized'])
- {
- $builder->where('is_serialized', 1);
- }
- if($filters['no_description'])
- {
- $builder->where('items.description', '');
- }
- if($filters['temporary'])
- {
- $builder->where('items.item_type', ITEM_TEMP);
- }
- else
- {
- $non_temp = [ITEM, ITEM_KIT, ITEM_AMOUNT_ENTRY];
- $builder->whereIn('items.item_type', $non_temp);
- }
-
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
-
- // avoid duplicated entries with same name because of inventory reporting multiple changes on the same item in the same date range
- $builder->groupBy('items.item_id');
-
- // order by name of item by default
- $builder->orderBy($sort, $order);
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
-
- /**
- * Returns all the items
- */
- public function get_all(int $stock_location_id = NEW_ENTRY, int $rows = 0, int $limit_from = 0): ResultInterface
- {
- $builder = $this->db->table('items');
-
- if($stock_location_id > -1)
- {
- $builder->join('item_quantities', 'item_quantities.item_id = items.item_id');
- $builder->where('location_id', $stock_location_id);
- }
-
- $builder->where('items.deleted', 0);
-
- // order by name of item
- $builder->orderBy('items.name', 'asc');
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
-
- /**
- * Gets information about a particular item
- */
- public function get_info(int $item_id): object
- {
- $builder = $this->db->table('items');
- $builder->select('items.*');
- $builder->select('GROUP_CONCAT(attribute_value SEPARATOR \'|\') AS attribute_values');
- $builder->select('GROUP_CONCAT(attribute_decimal SEPARATOR \'|\') AS attribute_dvalues');
- $builder->select('GROUP_CONCAT(attribute_date SEPARATOR \'|\') AS attribute_dtvalues');
- $builder->join('attribute_links', 'attribute_links.item_id = items.item_id', 'left');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left');
- $builder->where('items.item_id', $item_id);
- $builder->groupBy('items.item_id');
-
- $query = $builder->get();
-
- if($query->getNumRows() == 1)
- {
- return $query->getRow();
- }
-
- return $this->getEmptyObject('items');
- }
-
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
-
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
-
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
-
- return $empty_obj;
- }
-
- /**
- * Gets information about a particular item by item id or number
- */
- public function get_info_by_id_or_number(int $item_id, bool $include_deleted = true)
- {
- $builder = $this->db->table('items');
- $builder->groupStart();
- $builder->where('items.item_number', $item_id);
-
- // check if $item_id is a number and not a string starting with 0
- // because cases like 00012345 will be seen as a number where it is a barcode
- if(ctype_digit(strval($item_id)) && !str_starts_with($item_id, '0'))
- {
- $builder->orWhere('items.item_id', $item_id);
- }
-
- $builder->groupEnd();
-
- if(!$include_deleted)
- {
- $builder->where('items.deleted', 0);
- }
-
- // limit to only 1 so there is a result in case two are returned
- // due to barcode and item_id clash
- $builder->limit(1);
-
- $query = $builder->get();
-
- if($query->getNumRows() == 1)
- {
- return $query->getRow();
- }
-
- return '';
- }
-
- /**
- * Get an item id given an item number
- */
- public function get_item_id(string $item_number, bool $ignore_deleted = false, bool $deleted = false): bool
- {
- $builder = $this->db->table('items');
- $builder->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
- $builder->where('item_number', $item_number);
-
- if(!$ignore_deleted)
- {
- $builder->where('items.deleted', $deleted);
- }
-
- $query = $builder->get();
-
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow()->item_id;
- }
-
- return false;
- }
-
- /**
- * Gets information about multiple items
- */
- public function get_multiple_info(array $item_ids, int $location_id): ResultInterface
- {
- $format = $this->db->escape(dateformat_mysql());
-
- $builder = $this->db->table('items');
- $builder->select('items.*');
- $builder->select('MAX(company_name) AS company_name');
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
- $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) ORDER BY definition_id SEPARATOR '|') AS attribute_dtvalues");
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) ORDER BY definition_id SEPARATOR \'|\') AS attribute_dvalues');
- $builder->select('MAX(quantity) as quantity');
-
- $builder->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
- $builder->join('item_quantities', 'item_quantities.item_id = items.item_id', 'left');
- $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND sale_id IS NULL AND receiving_id IS NULL', 'left');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left');
-
- $builder->where('location_id', $location_id);
- $builder->whereIn('items.item_id', $item_ids);
-
- $builder->groupBy('items.item_id');
-
- return $builder->get();
- }
-
- /**
- * Inserts or updates an item
- */
- public function save_value(array &$item_data, int $item_id = NEW_ENTRY): bool //TODO: need to bring this in line with parent or change the name
- {
- $builder = $this->db->table('items');
-
- if($item_id < 1 || !$this->exists($item_id, true))
- {
- if($builder->insert($item_data))
- {
- $item_data['item_id'] = (int)$this->db->insertID();
- if($item_id < 1)
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_data['item_id']);
- $builder->update(['low_sell_item_id' => $item_data['item_id']]);
- }
-
- return true;
- }
-
- return false;
- }
- else
- {
- $item_data['item_id'] = $item_id;
- }
-
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
-
- return $builder->update($item_data);
- }
-
- /**
- * Updates multiple items at once
- */
- public function update_multiple(array $item_data, string $item_ids): bool
- {
- $builder = $this->db->table('items');
- $builder->whereIn('item_id', explode(':', $item_ids));
-
- return $builder->update($item_data);
- }
-
- /**
- * Deletes one item
- */
- public function delete($item_id = null, bool $purge = false): bool|int|string
- {
- $this->db->transStart();
-
- // set to 0 quantities
- $item_quantity = model(Item_quantity::class);
- $item_quantity->reset_quantity($item_id);
-
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
- $success = $builder->update(['deleted' => 1]);
-
- $inventory = model(Inventory::class);
- $success &= $inventory->reset_quantity($item_id);
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * Undeletes one item
- */
- public function undelete(int $item_id): bool
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
-
- return $builder->update(['deleted' => 0]);
- }
-
- /**
- * Deletes a list of items
- */
- public function delete_list(array $item_ids): bool
- {
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- // set to 0 quantities
- $item_quantity = model(Item_quantity::class);
- $item_quantity->reset_quantity_list($item_ids);
-
- $builder = $this->db->table('items');
- $builder->whereIn('item_id', $item_ids);
- $success = $builder->update(['deleted' => 1]);
-
- $inventory = model(Inventory::class);
-
- foreach($item_ids as $item_id)
- {
- $success &= $inventory->reset_quantity($item_id);
- }
-
- $this->db->transComplete();
-
- $success &= $this->db->transStatus();
-
- return $success;
- }
-
- /**
- * @param string|null $seed
- * @return string
- */
- public function get_search_suggestion_format(string $seed = null): string
- {
- $config = config(OSPOS::class)->settings;
- $seed .= ',' . $config['suggestions_first_column'];
-
- if($config['suggestions_second_column'] !== '')
- {
- $seed .= ',' . $config['suggestions_second_column'];
- }
-
- if($config['suggestions_third_column'] !== '')
- {
- $seed .= ',' . $config['suggestions_third_column'];
- }
-
- return $seed;
- }
-
- /**
- * @param object $result_row
- * @return string
- */
- public function get_search_suggestion_label(object $result_row): string
- {
- $config = config(OSPOS::class)->settings;
-
- $label = '';
- $label1 = $config['suggestions_first_column'];
- $label2 = $config['suggestions_second_column'];
- $label3 = $config['suggestions_third_column'];
-
- $this->format_result_numbers($result_row);
-
- // If multi_pack enabled then if "name" is part of the search suggestions then append pack
- if($config['multi_pack_enabled'])
- {
- $this->append_label($label, $label1, $result_row);
- $this->append_label($label, $label2, $result_row);
- $this->append_label($label, $label3, $result_row);
- }
- else
- {
- $label = $result_row->$label1;
-
- if($label2 !== '')
- {
- $label .= NAME_SEPARATOR . $result_row->$label2;
- }
-
- if($label3 !== '')
- {
- $label .= NAME_SEPARATOR . $result_row->$label3;
- }
- }
-
- return $label;
- }
-
- /**
- * Converts decimal money values to their correct locale format.
- *
- * @param object $result_row
- * @return void
- */
- private function format_result_numbers(object &$result_row): void
- {
- if(isset($result_row->cost_price))
- {
- $result_row->cost_price = to_currency_no_money($result_row->cost_price);
- }
- if(isset($result_row->unit_price))
- {
- $result_row->unit_price = to_currency_no_money($result_row->unit_price);
- }
- }
-
- /**
- * @param string $label
- * @param string $item_field_name
- * @param object $item_info
- * @return void
- */
- private function append_label(string &$label, string $item_field_name, object $item_info): void
- {
- if($item_field_name !== '')
- {
- if($label == '')
- {
- if($item_field_name == 'name') //TODO: This needs to be replaced with Ternary notation if possible
- {
- $label .= implode(NAME_SEPARATOR, [$item_info->name, $item_info->pack_name]); //TODO: no need for .= operator. If it gets here then that means label is an empty string.
- }
- else
- {
- $label .= $item_info->$item_field_name;
- }
- }
- else
- {
- if($item_field_name == 'name')
- {
- $label .= implode(NAME_SEPARATOR, ['', $item_info->name, $item_info->pack_name]);
- }
- else
- {
- $label .= NAME_SEPARATOR . $item_info->$item_field_name;
- }
- }
- }
- }
-
- /**
- * @param string $search
- * @param array $filters
- * @param bool $unique
- * @param int $limit
- * @return array
- */
- public function get_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
- {
- $suggestions = [];
- $non_kit = [ITEM, ITEM_AMOUNT_ENTRY];
-
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, name, pack_name'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->like('name', $search);//TODO: this and the next 11 lines are duplicated directly below. We should extract a method here.
- $builder->orderBy('name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
-
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->like('item_number', $search);
- $builder->orderBy('item_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
-
- if(!$unique)
- {
- //Search by category
- $builder = $this->db->table('items');
- $builder->select('category');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->distinct(); //TODO: duplicate code. Refactor method.
- $builder->like('category', $search);
- $builder->orderBy('category', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->category];
- }
-
- $builder = $this->db->table('suppliers');
-
- //Search by supplier
- $builder->select('company_name');
- $builder->like('company_name', $search);
-
- // restrict to non deleted companies only if is_deleted is false
- $builder->where('deleted', $filters['is_deleted']);
- $builder->distinct();
- $builder->orderBy('company_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->company_name];
- }
-
- //Search by description
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->like('description', $search); //TODO: duplicate code, refactor method.
- $builder->orderBy('description', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $entry = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
-
- if(!array_walk($suggestions, function ($value, $label) use ($entry)
- {
- return $entry['label'] != $label;
- }))
- {
- $suggestions[] = $entry;
- }
- }
-
- //Search in attributes
- if($filters['search_custom'] !== false)
- {
- $builder = $this->db->table('attribute_links');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
- $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
- $builder->like('attribute_value', $search);
- $builder->where('definition_type', TEXT);
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
- }
- }
-
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
-
- return array_unique($suggestions, SORT_REGULAR);
- }
-
-
- /**
- * @param string $search
- * @param array $filters
- * @param bool $unique
- * @param int $limit
- * @return array
- */
- public function get_stock_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
- {
- $suggestions = [];
- $non_kit = [ITEM, ITEM_AMOUNT_ENTRY];
-
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, name, pack_name'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->where('stock_type', '0'); // stocked items only
- $builder->like('name', $search);
- $builder->orderBy('name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
-
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->where('stock_type', '0'); // stocked items only
- $builder->like('item_number', $search);
- $builder->orderBy('item_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
-
- if(!$unique)
- {
- //Search by category
- $builder = $this->db->table('items');
- $builder->select('category');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->where('stock_type', '0'); // stocked items only
- $builder->distinct();
- $builder->like('category', $search);
- $builder->orderBy('category', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->category];
- }
-
- //Search by supplier
- $builder = $this->db->table('suppliers');
- $builder->select('company_name');
- $builder->like('company_name', $search);
-
- // restrict to non deleted companies only if is_deleted is false
- $builder->where('deleted', $filters['is_deleted']);
- $builder->distinct();
- $builder->orderBy('company_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->company_name];
- }
-
- //Search by description
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
- $builder->where('deleted', $filters['is_deleted']);
- $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
- $builder->where('stock_type', '0'); // stocked items only
- $builder->like('description', $search); //TODO: duplicated code, refactor method.
- $builder->orderBy('description', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $entry = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- if(!array_walk($suggestions, function ($value, $label) use ($entry)
- {
- return $entry['label'] != $label;
- }))
- {
- $suggestions[] = $entry;
- }
- }
-
- //Search by custom fields
- if($filters['search_custom'] !== false) //TODO: duplicated code. We should refactor out a method... this can be replaced with `if($filters['search_custom']`... no need for the double negative
- {
- $builder = $this->db->table('attribute_links');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
- $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
- $builder->like('attribute_value', $search);
- $builder->where('definition_type', TEXT);
- $builder->where('stock_type', '0'); // stocked items only
- $builder->where('deleted', $filters['is_deleted']);
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
- }
- }
-
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
-
- return array_unique($suggestions, SORT_REGULAR);
- }
-
- /**
- * @param string $search
- * @param array $filters
- * @param bool $unique
- * @param int $limit
- * @return array
- */
- public function get_kit_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
- {
- $suggestions = [];
- $non_kit = [ITEM, ITEM_AMOUNT_ENTRY]; //TODO: This variable is never used.
-
- $builder = $this->db->table('items');
- $builder->select('item_id, name');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->where('item_type', ITEM_KIT);
- $builder->like('name', $search);
- $builder->orderBy('name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $row->name];
- }
-
- $builder = $this->db->table('items');
- $builder->select('item_id, item_number');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->like('item_number', $search);
- $builder->where('item_type', ITEM_KIT);
- $builder->orderBy('item_number', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $row->item_number];
- }
-
- if(!$unique)
- {
- //Search by category
- $builder = $this->db->table('items');
- $builder->select('category');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->where('item_type', ITEM_KIT);
- $builder->distinct();//TODO: duplicated code, refactor method.
- $builder->like('category', $search);
- $builder->orderBy('category', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->category];
- }
-
- //Search by supplier
- $builder = $this->db->table('suppliers');
- $builder->select('company_name');
- $builder->like('company_name', $search);
-
- // restrict to non deleted companies only if is_deleted is false
- $builder->where('deleted', $filters['is_deleted']);
- $builder->distinct();
- $builder->orderBy('company_name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->company_name];
- }
-
- //Search by description
- $builder = $this->db->table('items');
- $builder->select('item_id, name, description');
- $builder->where('deleted', $filters['is_deleted']);
- $builder->where('item_type', ITEM_KIT);
- $builder->like('description', $search);
- $builder->orderBy('description', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $entry = ['value' => $row->item_id, 'label' => $row->name];
- if(!array_walk($suggestions, function ($value, $label) use ($entry)
- {
- return $entry['label'] != $label;
- }))
- {
- $suggestions[] = $entry;
- }
- }
-
- //Search in attributes
- if($filters['search_custom'] !== false) //TODO: Duplicate code... same as above... no double negatives
- {
- $builder = $this->db->table('attribute_links');
- $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
- $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
- $builder->like('attribute_value', $search);
- $builder->where('definition_type', TEXT);
- $builder->where('stock_type', '0'); // stocked items only
- $builder->where('deleted', $filters['is_deleted']);
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
- }
- }
-
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
-
- return array_unique($suggestions, SORT_REGULAR);
- }
-
- /**
- * @param string $search
- * @return array
- */
- public function get_low_sell_suggestions(string $search): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('items');
- $builder->select($this->get_search_suggestion_format('item_id, pack_name'));
- $builder->where('deleted', '0');
- $builder->where('stock_type', '0'); // stocked items only //TODO: '0' should be replaced with a constant.
- $builder->like('name', $search);
- $builder->orderBy('name', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
- }
-
- return $suggestions;
- }
-
- /**
- * @param string $search
- * @return array
- */
- public function get_category_suggestions(string $search): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('items');
- $builder->distinct();
- $builder->select('category');
- $builder->like('category', $search);
- $builder->where('deleted', 0);
- $builder->orderBy('category', 'asc');
-
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->category];
- }
-
- return $suggestions;
- }
-
- /**
- * @param string $search
- * @return array
- */
- public function get_location_suggestions(string $search): array
- {
- $suggestions = [];
-
- $builder = $this->db->table('items');
- $builder->distinct();
- $builder->select('location');
- $builder->like('location', $search);
- $builder->where('deleted', 0);
- $builder->orderBy('location', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->location];
- }
-
- return $suggestions;
- }
-
- /**
- * @return ResultInterface|false|string
- */
- public function get_categories(): ResultInterface|bool //TODO: This function is never called in the code.
- {
- $builder = $this->db->table('items');
- $builder->select('category');
- $builder->where('deleted', 0);
- $builder->distinct();
- $builder->orderBy('category', 'asc');
-
- return $builder->get();
- }
-
- /**
- * changes the cost price of a given item
- * calculates the average price between received items and items on stock
- * $item_id : the item which price should be changed
- * $items_received : the amount of new items received
- * $new_price : the cost-price for the newly received items
- * $old_price (optional) : the current-cost-price
- *
- * used in receiving-process to update cost-price if changed
- * caution: must be used before item_quantities gets updated, otherwise the average price is wrong!
- *
- */
- public function change_cost_price(int $item_id, float $items_received, float $new_price, float $old_price = null): bool
- {
- if($old_price === null)
- {
- $item_info = $this->get_info($item_id);
- $old_price = $item_info->cost_price;
- }
-
- $builder = $this->db->table('item_quantities');
- $builder->selectSum('quantity');
- $builder->where('item_id', $item_id);
- $builder->join('stock_locations', 'stock_locations.location_id=item_quantities.location_id');
- $builder->where('stock_locations.deleted', 0);
- $old_total_quantity = $builder->get()->getRow()->quantity;
-
- $total_quantity = $old_total_quantity + $items_received;
- $average_price = bcdiv(bcadd(bcmul((string)$items_received, (string)$new_price), bcmul((string)$old_total_quantity, (string)$old_price)), (string)$total_quantity);
-
- $data = ['cost_price' => $average_price];
-
- return $this->save_value($data, $item_id);
- }
-
- /**
- * @param int $item_id
- * @param string $item_number
- * @return void
- */
- public function update_item_number(int $item_id, string $item_number): void
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
- $builder->update(['item_number' => $item_number]); //TODO: this function should probably return the result of update() and add ": bool" to the function signature
- }
-
- /**
- * @param int $item_id
- * @param string $item_name
- * @return void
- */
- public function update_item_name(int $item_id, string $item_name): void //TODO: this function should probably return the result of update() and add ": bool" to the function signature
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
- $builder->update(['name' => $item_name]);
- }
-
- /**
- * @param int $item_id
- * @param string $item_description
- * @return void
- */
- public function update_item_description(int $item_id, string $item_description): void //TODO: this function should probably return the result of update() and add ": bool" to the function signature
- {
- $builder = $this->db->table('items');
- $builder->where('item_id', $item_id);
- $builder->update(['description' => $item_description]);
- }
-
- /**
- * Determine the item name to use taking into consideration that
- * for a multipack environment then the item name should have the
- * pack appended to it
- */
- public function get_item_name(string $as_name = null): string
- {
- $config = config(OSPOS::class)->settings;
-
- if($as_name == null) //TODO: Replace with ternary notation
- {
- $as_name = '';
- }
- else
- {
- $as_name = ' AS ' . $as_name;
- }
-
- if($config['multi_pack_enabled']) //TODO: Replace with ternary notation
- {
- $item_name = "concat(items.name,'" . NAME_SEPARATOR . '\', items.pack_name)' . $as_name;
- }
- else
- {
- $item_name = 'items.name' . $as_name;
- }
-
- return $item_name;
- }
+ protected $table = 'items';
+ protected $primaryKey = 'item_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'name',
+ 'category',
+ 'supplier_id',
+ 'item_number',
+ 'description',
+ 'cost_price',
+ 'unit_price',
+ 'reorder_level',
+ 'allow_alt_description',
+ 'is_serialized',
+ 'deleted',
+ 'stock_type',
+ 'item_type',
+ 'tax_category_id',
+ 'receiving_quantity',
+ 'pic_filename',
+ 'qty_per_pack',
+ 'pack_name',
+ 'low_sell_item_id',
+ 'hsn_code'
+ ];
+
+
+ /**
+ * Determines if a given item_id is an item
+ */
+ public function exists(int $item_id, bool $ignore_deleted = false, bool $deleted = false): bool
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+
+ if(!$ignore_deleted)
+ {
+ $builder->where('deleted', $deleted);
+ }
+
+ return ($builder->get()->getNumRows() === 1);
+ }
+
+ /**
+ * Determines if a given item_number exists
+ */
+ public function item_number_exists(string $item_number, string $item_id = ''): bool
+ {
+ $config = config(OSPOS::class)->settings;
+
+ if($config['allow_duplicate_barcodes'])
+ {
+ return false;
+ }
+
+ $builder = $this->db->table('items');
+ $builder->where('item_number', $item_number);
+ $builder->where('deleted !=', 1);
+ $builder->where('item_id !=', intval($item_id));
+
+// // check if $item_id is a number and not a string starting with 0
+// // because cases like 00012345 will be seen as a number where it is a barcode
+ if(ctype_digit($item_id) && !str_starts_with($item_id, '0'))
+ {
+ $builder->where('item_id !=', intval($item_id));
+ }
+ return ($builder->get()->getNumRows()) >= 1;
+ }
+
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('items');
+ $builder->where('deleted', 0);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * @param int $tax_category_id
+ * @return int
+ */
+ public function get_tax_category_usage(int $tax_category_id): int //TODO: This function is never called in the code.
+ {
+ $builder = $this->db->table('items');
+ $builder->where('tax_category_id', $tax_category_id);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Get number of rows
+ */
+ public function get_found_rows(string $search, array $filters): int
+ {
+ return $this->search($search, $filters, 0, 0, 'items.name', 'asc', true);
+ }
+
+ /**
+ * Perform a search on items
+ */
+ public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'items.name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null)
+ {
+ $rows = 0;
+ }
+ if($limit_from == null)
+ {
+ $limit_from = 0;
+ }
+ if($sort == null)
+ {
+ $sort = 'items.name';
+ }
+ if($order == null)
+ {
+ $order = 'asc';
+ }
+ if($count_only == null)
+ {
+ $count_only = false;
+ }
+
+ $config = config(OSPOS::class)->settings;
+ $builder = $this->db->table('items AS items'); //TODO: I'm not sure if it's needed to write items AS items... I think you can just get away with items
+
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(DISTINCT items.item_id) AS count');
+ }
+ else
+ {
+ $builder->select('MAX(items.item_id) AS item_id');
+ $builder->select('MAX(items.name) AS name');
+ $builder->select('MAX(items.category) AS category');
+ $builder->select('MAX(items.supplier_id) AS supplier_id');
+ $builder->select('MAX(items.item_number) AS item_number');
+ $builder->select('MAX(items.description) AS description');
+ $builder->select('MAX(items.cost_price) AS cost_price');
+ $builder->select('MAX(items.unit_price) AS unit_price');
+ $builder->select('MAX(items.reorder_level) AS reorder_level');
+ $builder->select('MAX(items.receiving_quantity) AS receiving_quantity');
+ $builder->select('MAX(items.pic_filename) AS pic_filename');
+ $builder->select('MAX(items.allow_alt_description) AS allow_alt_description');
+ $builder->select('MAX(items.is_serialized) AS is_serialized');
+ $builder->select('MAX(items.pack_name) AS pack_name');
+ $builder->select('MAX(items.tax_category_id) AS tax_category_id');
+ $builder->select('MAX(items.deleted) AS deleted');
+
+ $builder->select('MAX(suppliers.person_id) AS person_id');
+ $builder->select('MAX(suppliers.company_name) AS company_name');
+ $builder->select('MAX(suppliers.agency_name) AS agency_name');
+ $builder->select('MAX(suppliers.account_number) AS account_number');
+ $builder->select('MAX(suppliers.deleted) AS deleted');
+
+ $builder->select('MAX(inventory.trans_id) AS trans_id');
+ $builder->select('MAX(inventory.trans_items) AS trans_items');
+ $builder->select('MAX(inventory.trans_user) AS trans_user');
+ $builder->select('MAX(inventory.trans_date) AS trans_date');
+ $builder->select('MAX(inventory.trans_comment) AS trans_comment');
+ $builder->select('MAX(inventory.trans_location) AS trans_location');
+ $builder->select('MAX(inventory.trans_inventory) AS trans_inventory');
+
+ if($filters['stock_location_id'] > -1)
+ {
+ $builder->select('MAX(item_quantities.item_id) AS qty_item_id');
+ $builder->select('MAX(item_quantities.location_id) AS location_id');
+ $builder->select('MAX(item_quantities.quantity) AS quantity');
+ }
+ }
+
+ $builder->join('suppliers AS suppliers', 'suppliers.person_id = items.supplier_id', 'left');
+ $builder->join('inventory AS inventory', 'inventory.trans_items = items.item_id');
+
+ if($filters['stock_location_id'] > -1)
+ {
+ $builder->join('item_quantities AS item_quantities', 'item_quantities.item_id = items.item_id');
+ $builder->where('location_id', $filters['stock_location_id']);
+ }
+
+ $where = empty($config['date_or_time_format'])
+ ? 'DATE_FORMAT(trans_date, "%Y-%m-%d") BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date'])
+ : 'trans_date BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']));
+ $builder->where($where);
+
+ $attributes_enabled = count($filters['definition_ids']) > 0;
+
+ if(!empty($search))
+ {
+ if($attributes_enabled && $filters['search_custom'])
+ {
+ $builder->having("attribute_values LIKE '%$search%'");
+ $builder->orHaving("attribute_dtvalues LIKE '%$search%'");
+ $builder->orHaving("attribute_dvalues LIKE '%$search%'");
+ }
+ else
+ {
+ $builder->groupStart();
+ $builder->like('name', $search);
+ $builder->orLike('item_number', $search);
+ $builder->orLike('items.item_id', $search);
+ $builder->orLike('company_name', $search);
+ $builder->orLike('items.category', $search);
+ $builder->groupEnd();
+ }
+ }
+
+ if($attributes_enabled)
+ {
+ $format = $this->db->escape(dateformat_mysql());
+ $this->db->simpleQuery('SET SESSION group_concat_max_len=49152');
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
+ $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
+ $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id IS NULL AND attribute_links.sale_id IS NULL AND definition_id IN (' . implode(',', $filters['definition_ids']) . ')', 'left');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
+ }
+
+ $builder->where('items.deleted', $filters['is_deleted']);
+
+ if($filters['empty_upc'])
+ {
+ $builder->where('item_number', null);
+ }
+ if($filters['low_inventory'])
+ {
+ $builder->where('quantity <=', 'reorder_level');
+ }
+ if($filters['is_serialized'])
+ {
+ $builder->where('is_serialized', 1);
+ }
+ if($filters['no_description'])
+ {
+ $builder->where('items.description', '');
+ }
+ if($filters['temporary'])
+ {
+ $builder->where('items.item_type', ITEM_TEMP);
+ }
+ else
+ {
+ $non_temp = [ITEM, ITEM_KIT, ITEM_AMOUNT_ENTRY];
+ $builder->whereIn('items.item_type', $non_temp);
+ }
+
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
+
+ // avoid duplicated entries with same name because of inventory reporting multiple changes on the same item in the same date range
+ $builder->groupBy('items.item_id');
+
+ // order by name of item by default
+ $builder->orderBy($sort, $order);
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Returns all the items
+ */
+ public function get_all(int $stock_location_id = NEW_ENTRY, int $rows = 0, int $limit_from = 0): ResultInterface
+ {
+ $builder = $this->db->table('items');
+
+ if($stock_location_id > -1)
+ {
+ $builder->join('item_quantities', 'item_quantities.item_id = items.item_id');
+ $builder->where('location_id', $stock_location_id);
+ }
+
+ $builder->where('items.deleted', 0);
+
+ // order by name of item
+ $builder->orderBy('items.name', 'asc');
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets information about a particular item
+ */
+ public function get_info(int $item_id): object
+ {
+ $builder = $this->db->table('items');
+ $builder->select('items.*');
+ $builder->select('GROUP_CONCAT(attribute_value SEPARATOR \'|\') AS attribute_values');
+ $builder->select('GROUP_CONCAT(attribute_decimal SEPARATOR \'|\') AS attribute_dvalues');
+ $builder->select('GROUP_CONCAT(attribute_date SEPARATOR \'|\') AS attribute_dtvalues');
+ $builder->join('attribute_links', 'attribute_links.item_id = items.item_id', 'left');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left');
+ $builder->where('items.item_id', $item_id);
+ $builder->groupBy('items.item_id');
+
+ $query = $builder->get();
+
+ if($query->getNumRows() == 1)
+ {
+ return $query->getRow();
+ }
+
+ return $this->getEmptyObject('items');
+ }
+
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
+
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
+
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
+
+ return $empty_obj;
+ }
+
+ /**
+ * Gets information about a particular item by item id or number
+ */
+ public function get_info_by_id_or_number(int $item_id, bool $include_deleted = true)
+ {
+ $builder = $this->db->table('items');
+ $builder->groupStart();
+ $builder->where('items.item_number', $item_id);
+
+ // check if $item_id is a number and not a string starting with 0
+ // because cases like 00012345 will be seen as a number where it is a barcode
+ if(ctype_digit(strval($item_id)) && !str_starts_with($item_id, '0'))
+ {
+ $builder->orWhere('items.item_id', $item_id);
+ }
+
+ $builder->groupEnd();
+
+ if(!$include_deleted)
+ {
+ $builder->where('items.deleted', 0);
+ }
+
+ // limit to only 1 so there is a result in case two are returned
+ // due to barcode and item_id clash
+ $builder->limit(1);
+
+ $query = $builder->get();
+
+ if($query->getNumRows() == 1)
+ {
+ return $query->getRow();
+ }
+
+ return '';
+ }
+
+ /**
+ * Get an item id given an item number
+ */
+ public function get_item_id(string $item_number, bool $ignore_deleted = false, bool $deleted = false): bool
+ {
+ $builder = $this->db->table('items');
+ $builder->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
+ $builder->where('item_number', $item_number);
+
+ if(!$ignore_deleted)
+ {
+ $builder->where('items.deleted', $deleted);
+ }
+
+ $query = $builder->get();
+
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow()->item_id;
+ }
+
+ return false;
+ }
+
+ /**
+ * Gets information about multiple items
+ */
+ public function get_multiple_info(array $item_ids, int $location_id): ResultInterface
+ {
+ $format = $this->db->escape(dateformat_mysql());
+
+ $builder = $this->db->table('items');
+ $builder->select('items.*');
+ $builder->select('MAX(company_name) AS company_name');
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
+ $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) ORDER BY definition_id SEPARATOR '|') AS attribute_dtvalues");
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) ORDER BY definition_id SEPARATOR \'|\') AS attribute_dvalues');
+ $builder->select('MAX(quantity) as quantity');
+
+ $builder->join('suppliers', 'suppliers.person_id = items.supplier_id', 'left');
+ $builder->join('item_quantities', 'item_quantities.item_id = items.item_id', 'left');
+ $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND sale_id IS NULL AND receiving_id IS NULL', 'left');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id', 'left');
+
+ $builder->where('location_id', $location_id);
+ $builder->whereIn('items.item_id', $item_ids);
+
+ $builder->groupBy('items.item_id');
+
+ return $builder->get();
+ }
+
+ /**
+ * Inserts or updates an item
+ */
+ public function save_value(array &$item_data, int $item_id = NEW_ENTRY): bool //TODO: need to bring this in line with parent or change the name
+ {
+ $builder = $this->db->table('items');
+
+ if($item_id < 1 || !$this->exists($item_id, true))
+ {
+ if($builder->insert($item_data))
+ {
+ $item_data['item_id'] = (int)$this->db->insertID();
+ if($item_id < 1)
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_data['item_id']);
+ $builder->update(['low_sell_item_id' => $item_data['item_id']]);
+ }
+
+ return true;
+ }
+
+ return false;
+ }
+ else
+ {
+ $item_data['item_id'] = $item_id;
+ }
+
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+
+ return $builder->update($item_data);
+ }
+
+ /**
+ * Updates multiple items at once
+ */
+ public function update_multiple(array $item_data, string $item_ids): bool
+ {
+ $builder = $this->db->table('items');
+ $builder->whereIn('item_id', explode(':', $item_ids));
+
+ return $builder->update($item_data);
+ }
+
+ /**
+ * Deletes one item
+ */
+ public function delete($item_id = null, bool $purge = false): bool|int|string
+ {
+ $this->db->transStart();
+
+ // set to 0 quantities
+ $item_quantity = model(Item_quantity::class);
+ $item_quantity->reset_quantity($item_id);
+
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+ $success = $builder->update(['deleted' => 1]);
+
+ $inventory = model(Inventory::class);
+ $success &= $inventory->reset_quantity($item_id);
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * Undeletes one item
+ */
+ public function undelete(int $item_id): bool
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+
+ return $builder->update(['deleted' => 0]);
+ }
+
+ /**
+ * Deletes a list of items
+ */
+ public function delete_list(array $item_ids): bool
+ {
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ // set to 0 quantities
+ $item_quantity = model(Item_quantity::class);
+ $item_quantity->reset_quantity_list($item_ids);
+
+ $builder = $this->db->table('items');
+ $builder->whereIn('item_id', $item_ids);
+ $success = $builder->update(['deleted' => 1]);
+
+ $inventory = model(Inventory::class);
+
+ foreach($item_ids as $item_id)
+ {
+ $success &= $inventory->reset_quantity($item_id);
+ }
+
+ $this->db->transComplete();
+
+ $success &= $this->db->transStatus();
+
+ return $success;
+ }
+
+ /**
+ * @param string|null $seed
+ * @return string
+ */
+ public function get_search_suggestion_format(string $seed = null): string
+ {
+ $config = config(OSPOS::class)->settings;
+ $seed .= ',' . $config['suggestions_first_column'];
+
+ if($config['suggestions_second_column'] !== '')
+ {
+ $seed .= ',' . $config['suggestions_second_column'];
+ }
+
+ if($config['suggestions_third_column'] !== '')
+ {
+ $seed .= ',' . $config['suggestions_third_column'];
+ }
+
+ return $seed;
+ }
+
+ /**
+ * @param object $result_row
+ * @return string
+ */
+ public function get_search_suggestion_label(object $result_row): string
+ {
+ $config = config(OSPOS::class)->settings;
+
+ $label = '';
+ $label1 = $config['suggestions_first_column'];
+ $label2 = $config['suggestions_second_column'];
+ $label3 = $config['suggestions_third_column'];
+
+ $this->format_result_numbers($result_row);
+
+ // If multi_pack enabled then if "name" is part of the search suggestions then append pack
+ if($config['multi_pack_enabled'])
+ {
+ $this->append_label($label, $label1, $result_row);
+ $this->append_label($label, $label2, $result_row);
+ $this->append_label($label, $label3, $result_row);
+ }
+ else
+ {
+ $label = $result_row->$label1;
+
+ if($label2 !== '')
+ {
+ $label .= NAME_SEPARATOR . $result_row->$label2;
+ }
+
+ if($label3 !== '')
+ {
+ $label .= NAME_SEPARATOR . $result_row->$label3;
+ }
+ }
+
+ return $label;
+ }
+
+ /**
+ * Converts decimal money values to their correct locale format.
+ *
+ * @param object $result_row
+ * @return void
+ */
+ private function format_result_numbers(object &$result_row): void
+ {
+ if(isset($result_row->cost_price))
+ {
+ $result_row->cost_price = to_currency_no_money($result_row->cost_price);
+ }
+ if(isset($result_row->unit_price))
+ {
+ $result_row->unit_price = to_currency_no_money($result_row->unit_price);
+ }
+ }
+
+ /**
+ * @param string $label
+ * @param string $item_field_name
+ * @param object $item_info
+ * @return void
+ */
+ private function append_label(string &$label, string $item_field_name, object $item_info): void
+ {
+ if($item_field_name !== '')
+ {
+ if($label == '')
+ {
+ if($item_field_name == 'name') //TODO: This needs to be replaced with Ternary notation if possible
+ {
+ $label .= implode(NAME_SEPARATOR, [$item_info->name, $item_info->pack_name]); //TODO: no need for .= operator. If it gets here then that means label is an empty string.
+ }
+ else
+ {
+ $label .= $item_info->$item_field_name;
+ }
+ }
+ else
+ {
+ if($item_field_name == 'name')
+ {
+ $label .= implode(NAME_SEPARATOR, ['', $item_info->name, $item_info->pack_name]);
+ }
+ else
+ {
+ $label .= NAME_SEPARATOR . $item_info->$item_field_name;
+ }
+ }
+ }
+ }
+
+ /**
+ * @param string $search
+ * @param array $filters
+ * @param bool $unique
+ * @param int $limit
+ * @return array
+ */
+ public function get_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
+ {
+ $suggestions = [];
+ $non_kit = [ITEM, ITEM_AMOUNT_ENTRY];
+
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, name, pack_name'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->like('name', $search);//TODO: this and the next 11 lines are duplicated directly below. We should extract a method here.
+ $builder->orderBy('name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->like('item_number', $search);
+ $builder->orderBy('item_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+
+ if(!$unique)
+ {
+ //Search by category
+ $builder = $this->db->table('items');
+ $builder->select('category');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->distinct(); //TODO: duplicate code. Refactor method.
+ $builder->like('category', $search);
+ $builder->orderBy('category', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->category];
+ }
+
+ $builder = $this->db->table('suppliers');
+
+ //Search by supplier
+ $builder->select('company_name');
+ $builder->like('company_name', $search);
+
+ // restrict to non deleted companies only if is_deleted is false
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->distinct();
+ $builder->orderBy('company_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->company_name];
+ }
+
+ //Search by description
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->like('description', $search); //TODO: duplicate code, refactor method.
+ $builder->orderBy('description', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $entry = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+
+ if(!array_walk($suggestions, function ($value, $label) use ($entry)
+ {
+ return $entry['label'] != $label;
+ }))
+ {
+ $suggestions[] = $entry;
+ }
+ }
+
+ //Search in attributes
+ if($filters['search_custom'] !== false)
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
+ $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
+ $builder->like('attribute_value', $search);
+ $builder->where('definition_type', TEXT);
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+ }
+ }
+
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
+
+ return array_unique($suggestions, SORT_REGULAR);
+ }
+
+
+ /**
+ * @param string $search
+ * @param array $filters
+ * @param bool $unique
+ * @param int $limit
+ * @return array
+ */
+ public function get_stock_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
+ {
+ $suggestions = [];
+ $non_kit = [ITEM, ITEM_AMOUNT_ENTRY];
+
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, name, pack_name'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->like('name', $search);
+ $builder->orderBy('name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, item_number, pack_name'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->like('item_number', $search);
+ $builder->orderBy('item_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+
+ if(!$unique)
+ {
+ //Search by category
+ $builder = $this->db->table('items');
+ $builder->select('category');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->distinct();
+ $builder->like('category', $search);
+ $builder->orderBy('category', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->category];
+ }
+
+ //Search by supplier
+ $builder = $this->db->table('suppliers');
+ $builder->select('company_name');
+ $builder->like('company_name', $search);
+
+ // restrict to non deleted companies only if is_deleted is false
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->distinct();
+ $builder->orderBy('company_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->company_name];
+ }
+
+ //Search by description
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, name, pack_name, description'));
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->whereIn('item_type', $non_kit); // standard, exclude kit items since kits will be picked up later
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->like('description', $search); //TODO: duplicated code, refactor method.
+ $builder->orderBy('description', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $entry = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ if(!array_walk($suggestions, function ($value, $label) use ($entry)
+ {
+ return $entry['label'] != $label;
+ }))
+ {
+ $suggestions[] = $entry;
+ }
+ }
+
+ //Search by custom fields
+ if($filters['search_custom'] !== false) //TODO: duplicated code. We should refactor out a method... this can be replaced with `if($filters['search_custom']`... no need for the double negative
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
+ $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
+ $builder->like('attribute_value', $search);
+ $builder->where('definition_type', TEXT);
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->where('deleted', $filters['is_deleted']);
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+ }
+ }
+
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
+
+ return array_unique($suggestions, SORT_REGULAR);
+ }
+
+ /**
+ * @param string $search
+ * @param array $filters
+ * @param bool $unique
+ * @param int $limit
+ * @return array
+ */
+ public function get_kit_search_suggestions(string $search, array $filters = ['is_deleted' => false, 'search_custom' => false], bool $unique = false, int $limit = 25): array
+ {
+ $suggestions = [];
+ $non_kit = [ITEM, ITEM_AMOUNT_ENTRY]; //TODO: This variable is never used.
+
+ $builder = $this->db->table('items');
+ $builder->select('item_id, name');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->where('item_type', ITEM_KIT);
+ $builder->like('name', $search);
+ $builder->orderBy('name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $row->name];
+ }
+
+ $builder = $this->db->table('items');
+ $builder->select('item_id, item_number');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->like('item_number', $search);
+ $builder->where('item_type', ITEM_KIT);
+ $builder->orderBy('item_number', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $row->item_number];
+ }
+
+ if(!$unique)
+ {
+ //Search by category
+ $builder = $this->db->table('items');
+ $builder->select('category');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->where('item_type', ITEM_KIT);
+ $builder->distinct();//TODO: duplicated code, refactor method.
+ $builder->like('category', $search);
+ $builder->orderBy('category', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->category];
+ }
+
+ //Search by supplier
+ $builder = $this->db->table('suppliers');
+ $builder->select('company_name');
+ $builder->like('company_name', $search);
+
+ // restrict to non deleted companies only if is_deleted is false
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->distinct();
+ $builder->orderBy('company_name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->company_name];
+ }
+
+ //Search by description
+ $builder = $this->db->table('items');
+ $builder->select('item_id, name, description');
+ $builder->where('deleted', $filters['is_deleted']);
+ $builder->where('item_type', ITEM_KIT);
+ $builder->like('description', $search);
+ $builder->orderBy('description', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $entry = ['value' => $row->item_id, 'label' => $row->name];
+ if(!array_walk($suggestions, function ($value, $label) use ($entry)
+ {
+ return $entry['label'] != $label;
+ }))
+ {
+ $suggestions[] = $entry;
+ }
+ }
+
+ //Search in attributes
+ if($filters['search_custom'] !== false) //TODO: Duplicate code... same as above... no double negatives
+ {
+ $builder = $this->db->table('attribute_links');
+ $builder->join('attribute_values', 'attribute_links.attribute_id = attribute_values.attribute_id');
+ $builder->join('attribute_definitions', 'attribute_definitions.definition_id = attribute_links.definition_id');
+ $builder->like('attribute_value', $search);
+ $builder->where('definition_type', TEXT);
+ $builder->where('stock_type', '0'); // stocked items only
+ $builder->where('deleted', $filters['is_deleted']);
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+ }
+ }
+
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
+
+ return array_unique($suggestions, SORT_REGULAR);
+ }
+
+ /**
+ * @param string $search
+ * @return array
+ */
+ public function get_low_sell_suggestions(string $search): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('items');
+ $builder->select($this->get_search_suggestion_format('item_id, pack_name'));
+ $builder->where('deleted', '0');
+ $builder->where('stock_type', '0'); // stocked items only //TODO: '0' should be replaced with a constant.
+ $builder->like('name', $search);
+ $builder->orderBy('name', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->item_id, 'label' => $this->get_search_suggestion_label($row)];
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * @param string $search
+ * @return array
+ */
+ public function get_category_suggestions(string $search): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('items');
+ $builder->distinct();
+ $builder->select('category');
+ $builder->like('category', $search);
+ $builder->where('deleted', 0);
+ $builder->orderBy('category', 'asc');
+
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->category];
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * @param string $search
+ * @return array
+ */
+ public function get_location_suggestions(string $search): array
+ {
+ $suggestions = [];
+
+ $builder = $this->db->table('items');
+ $builder->distinct();
+ $builder->select('location');
+ $builder->like('location', $search);
+ $builder->where('deleted', 0);
+ $builder->orderBy('location', 'asc');
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->location];
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * @return ResultInterface|false|string
+ */
+ public function get_categories(): ResultInterface|bool //TODO: This function is never called in the code.
+ {
+ $builder = $this->db->table('items');
+ $builder->select('category');
+ $builder->where('deleted', 0);
+ $builder->distinct();
+ $builder->orderBy('category', 'asc');
+
+ return $builder->get();
+ }
+
+ /**
+ * changes the cost price of a given item
+ * calculates the average price between received items and items on stock
+ * $item_id : the item which price should be changed
+ * $items_received : the amount of new items received
+ * $new_price : the cost-price for the newly received items
+ * $old_price (optional) : the current-cost-price
+ *
+ * used in receiving-process to update cost-price if changed
+ * caution: must be used before item_quantities gets updated, otherwise the average price is wrong!
+ *
+ */
+ public function change_cost_price(int $item_id, float $items_received, float $new_price, float $old_price = null): bool
+ {
+ if($old_price === null)
+ {
+ $item_info = $this->get_info($item_id);
+ $old_price = $item_info->cost_price;
+ }
+
+ $builder = $this->db->table('item_quantities');
+ $builder->selectSum('quantity');
+ $builder->where('item_id', $item_id);
+ $builder->join('stock_locations', 'stock_locations.location_id=item_quantities.location_id');
+ $builder->where('stock_locations.deleted', 0);
+ $old_total_quantity = $builder->get()->getRow()->quantity;
+
+ $total_quantity = $old_total_quantity + $items_received;
+ $average_price = bcdiv(bcadd(bcmul((string)$items_received, (string)$new_price), bcmul((string)$old_total_quantity, (string)$old_price)), (string)$total_quantity);
+
+ $data = ['cost_price' => $average_price];
+
+ return $this->save_value($data, $item_id);
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $item_number
+ * @return void
+ */
+ public function update_item_number(int $item_id, string $item_number): void
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+ $builder->update(['item_number' => $item_number]); //TODO: this function should probably return the result of update() and add ": bool" to the function signature
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $item_name
+ * @return void
+ */
+ public function update_item_name(int $item_id, string $item_name): void //TODO: this function should probably return the result of update() and add ": bool" to the function signature
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+ $builder->update(['name' => $item_name]);
+ }
+
+ /**
+ * @param int $item_id
+ * @param string $item_description
+ * @return void
+ */
+ public function update_item_description(int $item_id, string $item_description): void //TODO: this function should probably return the result of update() and add ": bool" to the function signature
+ {
+ $builder = $this->db->table('items');
+ $builder->where('item_id', $item_id);
+ $builder->update(['description' => $item_description]);
+ }
+
+ /**
+ * Determine the item name to use taking into consideration that
+ * for a multipack environment then the item name should have the
+ * pack appended to it
+ */
+ public function get_item_name(string $as_name = null): string
+ {
+ $config = config(OSPOS::class)->settings;
+
+ if($as_name == null) //TODO: Replace with ternary notation
+ {
+ $as_name = '';
+ }
+ else
+ {
+ $as_name = ' AS ' . $as_name;
+ }
+
+ if($config['multi_pack_enabled']) //TODO: Replace with ternary notation
+ {
+ $item_name = "concat(items.name,'" . NAME_SEPARATOR . '\', items.pack_name)' . $as_name;
+ }
+ else
+ {
+ $item_name = 'items.name' . $as_name;
+ }
+
+ return $item_name;
+ }
}
diff --git a/app/Models/Item_kit.php b/app/Models/Item_kit.php
index f33f0d7f3..d35716f55 100644
--- a/app/Models/Item_kit.php
+++ b/app/Models/Item_kit.php
@@ -12,297 +12,297 @@ use stdClass;
*/
class Item_kit extends Model
{
- protected $table = 'item_kits';
- protected $primaryKey = 'item_kit_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'item_kit_number',
- 'name',
- 'description',
- 'item_id',
- 'kit_discount',
- 'kit_discount_type',
- 'price_option'
- ];
+ protected $table = 'item_kits';
+ protected $primaryKey = 'item_kit_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'item_kit_number',
+ 'name',
+ 'description',
+ 'item_id',
+ 'kit_discount',
+ 'kit_discount_type',
+ 'price_option'
+ ];
- /**
- * Determines if a given item_id is an item kit
- */
- public function exists(int $item_kit_id): bool
- {
- $builder = $this->db->table('item_kits');
- $builder->where('item_kit_id', $item_kit_id);
+ /**
+ * Determines if a given item_id is an item kit
+ */
+ public function exists(int $item_kit_id): bool
+ {
+ $builder = $this->db->table('item_kits');
+ $builder->where('item_kit_id', $item_kit_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Check if a given item_id is an item kit
- */
- public function is_valid_item_kit(string $item_kit_id): bool
- {
- if(!empty($item_kit_id))
- {
- //KIT #
- $pieces = explode(' ', $item_kit_id);
+ /**
+ * Check if a given item_id is an item kit
+ */
+ public function is_valid_item_kit(string $item_kit_id): bool
+ {
+ if(!empty($item_kit_id))
+ {
+ //KIT #
+ $pieces = explode(' ', $item_kit_id);
- if((count($pieces) == 2) && preg_match('/(KIT)/i', $pieces[0])) //TODO: === ... perhaps think about converting this to ternary notation
- {
- return $this->exists($pieces[1]);
- }
- else
- {
- return $this->item_number_exists($item_kit_id);
- }
- }
+ if((count($pieces) == 2) && preg_match('/(KIT)/i', $pieces[0])) //TODO: === ... perhaps think about converting this to ternary notation
+ {
+ return $this->exists($pieces[1]);
+ }
+ else
+ {
+ return $this->item_number_exists($item_kit_id);
+ }
+ }
- return false;
- }
+ return false;
+ }
- /**
- * Determines if a given item_number exists
- */
- public function item_number_exists(string $item_kit_number, string $item_kit_id = ''): bool
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * Determines if a given item_number exists
+ */
+ public function item_number_exists(string $item_kit_number, string $item_kit_id = ''): bool
+ {
+ $config = config(OSPOS::class)->settings;
- if($config['allow_duplicate_barcodes'])
- {
- return false;
- }
+ if($config['allow_duplicate_barcodes'])
+ {
+ return false;
+ }
- $builder = $this->db->table('item_kits');
- $builder->where('item_kit_number', $item_kit_number);
+ $builder = $this->db->table('item_kits');
+ $builder->where('item_kit_number', $item_kit_number);
- // check if $item_id is a number and not a string starting with 0
- // because cases like 00012345 will be seen as a number where it is a barcode
- if(ctype_digit($item_kit_id) && !str_starts_with($item_kit_id, '0'))
- {
- $builder->where('item_kit_id !=', (int) $item_kit_id);
- }
+ // check if $item_id is a number and not a string starting with 0
+ // because cases like 00012345 will be seen as a number where it is a barcode
+ if(ctype_digit($item_kit_id) && !str_starts_with($item_kit_id, '0'))
+ {
+ $builder->where('item_kit_id !=', (int) $item_kit_id);
+ }
- return ($builder->get()->getNumRows() >= 1);
- }
+ return ($builder->get()->getNumRows() >= 1);
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('item_kits');
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('item_kits');
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about a particular item kit
- */
- public function get_info(string $item_kit_id): object
- {
- $builder = $this->db->table('item_kits');
- $builder->select('
- item_kit_id,
- item_kits.name as name,
- item_kit_number,
- items.name as item_name,
- item_kits.description,
- items.description as item_description,
- item_kits.item_id as kit_item_id,
- kit_discount,
- kit_discount_type,
- price_option,
- print_option,
- category,
- supplier_id,
- item_number,
- cost_price,
- unit_price,
- reorder_level,
- receiving_quantity,
- pic_filename,
- allow_alt_description,
- is_serialized,
- items.deleted,
- item_type,
- stock_type
- ');
+ /**
+ * Gets information about a particular item kit
+ */
+ public function get_info(string $item_kit_id): object
+ {
+ $builder = $this->db->table('item_kits');
+ $builder->select('
+ item_kit_id,
+ item_kits.name as name,
+ item_kit_number,
+ items.name as item_name,
+ item_kits.description,
+ items.description as item_description,
+ item_kits.item_id as kit_item_id,
+ kit_discount,
+ kit_discount_type,
+ price_option,
+ print_option,
+ category,
+ supplier_id,
+ item_number,
+ cost_price,
+ unit_price,
+ reorder_level,
+ receiving_quantity,
+ pic_filename,
+ allow_alt_description,
+ is_serialized,
+ items.deleted,
+ item_type,
+ stock_type
+ ');
- $builder->join('items', 'item_kits.item_id = items.item_id', 'left');
- $builder->where('item_kit_id', $item_kit_id);
- $builder->orWhere('item_kit_number', $item_kit_id);
+ $builder->join('items', 'item_kits.item_id = items.item_id', 'left');
+ $builder->where('item_kit_id', $item_kit_id);
+ $builder->orWhere('item_kit_number', $item_kit_id);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object, as $item_kit_id is NOT an item kit
- $item_obj = new stdClass();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object, as $item_kit_id is NOT an item kit
+ $item_obj = new stdClass();
- //Get all the fields from items table
- foreach($this->db->getFieldNames('item_kits') as $field)
- {
- $item_obj->$field = '';
- }
+ //Get all the fields from items table
+ foreach($this->db->getFieldNames('item_kits') as $field)
+ {
+ $item_obj->$field = '';
+ }
- return $item_obj;
- }
- }
+ return $item_obj;
+ }
+ }
- /**
- * Gets information about multiple item kits
- */
- public function get_multiple_info(array $item_kit_ids): ResultInterface
- {
- $builder = $this->db->table('item_kits');
- $builder->whereIn('item_kit_id', $item_kit_ids);
- $builder->orderBy('name', 'asc');
+ /**
+ * Gets information about multiple item kits
+ */
+ public function get_multiple_info(array $item_kit_ids): ResultInterface
+ {
+ $builder = $this->db->table('item_kits');
+ $builder->whereIn('item_kit_id', $item_kit_ids);
+ $builder->orderBy('name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates an item kit
- */
- public function save_value(array &$item_kit_data, int $item_kit_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('item_kits');
- if($item_kit_id == NEW_ENTRY || !$this->exists($item_kit_id))
- {
- if($builder->insert($item_kit_data))
- {
- $item_kit_data['item_kit_id'] = $this->db->insertID();
+ /**
+ * Inserts or updates an item kit
+ */
+ public function save_value(array &$item_kit_data, int $item_kit_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('item_kits');
+ if($item_kit_id == NEW_ENTRY || !$this->exists($item_kit_id))
+ {
+ if($builder->insert($item_kit_data))
+ {
+ $item_kit_data['item_kit_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('item_kit_id', $item_kit_id);
+ $builder->where('item_kit_id', $item_kit_id);
- return $builder->update($item_kit_data);
- }
+ return $builder->update($item_kit_data);
+ }
- /**
- * Deletes one item kit
- */
- public function delete($item_kit_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('item_kits');
+ /**
+ * Deletes one item kit
+ */
+ public function delete($item_kit_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('item_kits');
- return $builder->delete(['item_kit_id' => $item_kit_id]);
- }
+ return $builder->delete(['item_kit_id' => $item_kit_id]);
+ }
- /**
- * Deletes a list of item kits
- */
- public function delete_list(array $item_kit_ids): bool
- {
- $builder = $this->db->table('item_kits');
- $builder->whereIn('item_kit_id', $item_kit_ids);
+ /**
+ * Deletes a list of item kits
+ */
+ public function delete_list(array $item_kit_ids): bool
+ {
+ $builder = $this->db->table('item_kits');
+ $builder->whereIn('item_kit_id', $item_kit_ids);
- return $builder->delete();
- }
+ return $builder->delete();
+ }
- /**
- * @param string $search
- * @param int $limit
- * @return array
- */
- public function get_search_suggestions(string $search, int $limit = 25): array
- {
- $suggestions = [];
+ /**
+ * @param string $search
+ * @param int $limit
+ * @return array
+ */
+ public function get_search_suggestions(string $search, int $limit = 25): array
+ {
+ $suggestions = [];
- $builder = $this->db->table('item_kits');
+ $builder = $this->db->table('item_kits');
- //KIT #
- if(stripos($search, 'KIT ') !== false)
- {
- $builder->like('item_kit_id', str_ireplace('KIT ', '', $search));
- $builder->orderBy('item_kit_id', 'asc');
+ //KIT #
+ if(stripos($search, 'KIT ') !== false)
+ {
+ $builder->like('item_kit_id', str_ireplace('KIT ', '', $search));
+ $builder->orderBy('item_kit_id', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => 'KIT '. $row->item_kit_id, 'label' => 'KIT ' . $row->item_kit_id];
- }
- }
- else
- {
- $builder->like('name', $search);
- $builder->orLike('item_kit_number', $search);
- $builder->orderBy('name', 'asc');
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => 'KIT '. $row->item_kit_id, 'label' => 'KIT ' . $row->item_kit_id];
+ }
+ }
+ else
+ {
+ $builder->like('name', $search);
+ $builder->orLike('item_kit_number', $search);
+ $builder->orderBy('name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => 'KIT ' . $row->item_kit_id, 'label' => $row->name];
- }
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => 'KIT ' . $row->item_kit_id, 'label' => $row->name];
+ }
+ }
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'name', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'name', 'asc', true);
+ }
- /**
- * Perform a search on items
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Perform a search on items
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('item_kits');
+ $builder = $this->db->table('item_kits');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(item_kit_id) as count');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(item_kit_id) as count');
+ }
- $builder->like('name', $search);
- $builder->orLike('description', $search);
- $builder->orLike('item_kit_number', $search);
+ $builder->like('name', $search);
+ $builder->orLike('description', $search);
+ $builder->orLike('item_kit_number', $search);
- //KIT #
- if(stripos($search, 'KIT ') !== false)
- {
- $builder->orLike('item_kit_id', str_ireplace('KIT ', '', $search));
- }
+ //KIT #
+ if(stripos($search, 'KIT ') !== false)
+ {
+ $builder->orLike('item_kit_id', str_ireplace('KIT ', '', $search));
+ }
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
}
diff --git a/app/Models/Item_kit_items.php b/app/Models/Item_kit_items.php
index b7aeba5c1..97363b360 100644
--- a/app/Models/Item_kit_items.php
+++ b/app/Models/Item_kit_items.php
@@ -9,81 +9,81 @@ use CodeIgniter\Model;
*/
class Item_kit_items extends Model
{
- protected $table = 'item_kit_items';
- protected $primaryKey = 'item_kit_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'kit_sequence'
- ];
+ protected $table = 'item_kit_items';
+ protected $primaryKey = 'item_kit_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'kit_sequence'
+ ];
- /**
- * Gets item kit items for a particular item kit
- */
- public function get_info(int $item_kit_id): array
- {
- $builder = $this->db->table('item_kit_items as item_kit_items');
- $builder->select('item_kits.item_kit_id, item_kit_items.item_id, quantity, kit_sequence, unit_price, item_type, stock_type');
- $builder->join('items as items', 'item_kit_items.item_id = items.item_id');
- $builder->join('item_kits as item_kits', 'item_kits.item_kit_id = item_kit_items.item_kit_id');
- $builder->where('item_kits.item_kit_id', $item_kit_id);
- $builder->orWhere('item_kit_number', $item_kit_id);
- $builder->orderBy('kit_sequence', 'asc');
+ /**
+ * Gets item kit items for a particular item kit
+ */
+ public function get_info(int $item_kit_id): array
+ {
+ $builder = $this->db->table('item_kit_items as item_kit_items');
+ $builder->select('item_kits.item_kit_id, item_kit_items.item_id, quantity, kit_sequence, unit_price, item_type, stock_type');
+ $builder->join('items as items', 'item_kit_items.item_id = items.item_id');
+ $builder->join('item_kits as item_kits', 'item_kits.item_kit_id = item_kit_items.item_kit_id');
+ $builder->where('item_kits.item_kit_id', $item_kit_id);
+ $builder->orWhere('item_kit_number', $item_kit_id);
+ $builder->orderBy('kit_sequence', 'asc');
- //return an array of item kit items for an item
- return $builder->get()->getResultArray();
- }
+ //return an array of item kit items for an item
+ return $builder->get()->getResultArray();
+ }
- /**
- * Gets item kit items for a particular item kit
- */
- public function get_info_for_sale(int $item_kit_id): array //TODO: This function does not seem to be called anywhere in the code
- {
- $builder = $this->db->table('item_kit_items');
- $builder->where('item_kit_id', $item_kit_id);
+ /**
+ * Gets item kit items for a particular item kit
+ */
+ public function get_info_for_sale(int $item_kit_id): array //TODO: This function does not seem to be called anywhere in the code
+ {
+ $builder = $this->db->table('item_kit_items');
+ $builder->where('item_kit_id', $item_kit_id);
- $builder->orderBy('kit_sequence', 'desc');
+ $builder->orderBy('kit_sequence', 'desc');
- //return an array of item kit items for an item
- return $builder->get()->getResultArray();
- }
+ //return an array of item kit items for an item
+ return $builder->get()->getResultArray();
+ }
- /**
- * Inserts or updates an item kit's items
- */
- public function save_value(array &$item_kit_items_data, int $item_kit_id): bool
- {
- $success = true;
+ /**
+ * Inserts or updates an item kit's items
+ */
+ public function save_value(array &$item_kit_items_data, int $item_kit_id): bool
+ {
+ $success = true;
- $this->db->transStart();
+ $this->db->transStart();
- $this->delete($item_kit_id);
+ $this->delete($item_kit_id);
- if($item_kit_items_data != null)
- {
- $builder = $this->db->table('item_kit_items');
+ if($item_kit_items_data != null)
+ {
+ $builder = $this->db->table('item_kit_items');
- foreach($item_kit_items_data as $row)
- {
- $row['item_kit_id'] = $item_kit_id;
- $success &= $builder->insert($row);
- }
- }
+ foreach($item_kit_items_data as $row)
+ {
+ $row['item_kit_id'] = $item_kit_id;
+ $success &= $builder->insert($row);
+ }
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Deletes item kit items given an item kit
- */
- public function delete($item_kit_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('item_kit_items');
+ /**
+ * Deletes item kit items given an item kit
+ */
+ public function delete($item_kit_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('item_kit_items');
- return $builder->delete(['item_kit_id' => $item_kit_id]);
- }
+ return $builder->delete(['item_kit_id' => $item_kit_id]);
+ }
}
diff --git a/app/Models/Item_quantity.php b/app/Models/Item_quantity.php
index 3fabbb25e..d2f49f3f5 100644
--- a/app/Models/Item_quantity.php
+++ b/app/Models/Item_quantity.php
@@ -10,60 +10,60 @@ use stdClass;
*/
class Item_quantity extends Model
{
- protected $table = 'item_quantities';
- protected $primaryKey = 'item_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'quantity'
- ];
+ protected $table = 'item_quantities';
+ protected $primaryKey = 'item_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'quantity'
+ ];
- protected $item_id;
- protected $location_id;
- protected $quantity;
+ protected $item_id;
+ protected $location_id;
+ protected $quantity;
- /**
- * @param int $item_id
- * @param int $location_id
- * @return bool
- */
- public function exists(int $item_id, int $location_id): bool
+ /**
+ * @param int $item_id
+ * @param int $location_id
+ * @return bool
+ */
+ public function exists(int $item_id, int $location_id): bool
{
$builder = $this->db->table('item_quantities');
$builder->where('item_id', $item_id);
$builder->where('location_id', $location_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
}
- /**
- * @param array $location_detail
- * @param int $item_id
- * @param int $location_id
- * @return bool
- */
- public function save_value(array $location_detail, int $item_id, int $location_id): bool
+ /**
+ * @param array $location_detail
+ * @param int $item_id
+ * @param int $location_id
+ * @return bool
+ */
+ public function save_value(array $location_detail, int $item_id, int $location_id): bool
{
if(!$this->exists($item_id, $location_id))
{
- $builder = $this->db->table('item_quantities');
- return $builder->insert($location_detail);
+ $builder = $this->db->table('item_quantities');
+ return $builder->insert($location_detail);
}
- $builder = $this->db->table('item_quantities');
+ $builder = $this->db->table('item_quantities');
$builder->where('item_id', $item_id);
$builder->where('location_id', $location_id);
return $builder->update($location_detail);
}
- /**
- * @param int $item_id
- * @param int $location_id
- * @return array|Item_quantity|stdClass|null
- */
- public function get_item_quantity(int $item_id, int $location_id): array|Item_quantity|StdClass|null
- {
+ /**
+ * @param int $item_id
+ * @param int $location_id
+ * @return array|Item_quantity|stdClass|null
+ */
+ public function get_item_quantity(int $item_id, int $location_id): array|Item_quantity|StdClass|null
+ {
$builder = $this->db->table('item_quantities');
$builder->where('item_id', $item_id);
$builder->where('location_id', $location_id);
@@ -86,39 +86,39 @@ class Item_quantity extends Model
return $result;
}
- /**
- * changes to quantity of an item according to the given amount.
- * if $quantity_change is negative, it will be subtracted,
- * if it is positive, it will be added to the current quantity
- */
- public function change_quantity(int $item_id, int $location_id, int $quantity_change): bool
- {
- $quantity_old = $this->get_item_quantity($item_id, $location_id);
- $quantity_new = $quantity_old->quantity + $quantity_change;
- $location_detail = ['item_id' => $item_id, 'location_id' => $location_id, 'quantity' => $quantity_new];
+ /**
+ * changes to quantity of an item according to the given amount.
+ * if $quantity_change is negative, it will be subtracted,
+ * if it is positive, it will be added to the current quantity
+ */
+ public function change_quantity(int $item_id, int $location_id, int $quantity_change): bool
+ {
+ $quantity_old = $this->get_item_quantity($item_id, $location_id);
+ $quantity_new = $quantity_old->quantity + $quantity_change;
+ $location_detail = ['item_id' => $item_id, 'location_id' => $location_id, 'quantity' => $quantity_new];
- return $this->save_value($location_detail, $item_id, $location_id);
- }
+ return $this->save_value($location_detail, $item_id, $location_id);
+ }
- /**
- * Set to 0 all quantity in the given item
- */
- public function reset_quantity(int $item_id): bool
- {
- $builder = $this->db->table('item_quantities');
- $builder->where('item_id', $item_id);
+ /**
+ * Set to 0 all quantity in the given item
+ */
+ public function reset_quantity(int $item_id): bool
+ {
+ $builder = $this->db->table('item_quantities');
+ $builder->where('item_id', $item_id);
return $builder->update(['quantity' => 0]);
- }
+ }
- /**
- * Set to 0 all quantity in the given list of items
- */
- public function reset_quantity_list(array $item_ids): bool
- {
- $builder = $this->db->table('item_quantities');
- $builder->whereIn('item_id', $item_ids);
+ /**
+ * Set to 0 all quantity in the given list of items
+ */
+ public function reset_quantity_list(array $item_ids): bool
+ {
+ $builder = $this->db->table('item_quantities');
+ $builder->whereIn('item_id', $item_ids);
return $builder->update(['quantity' => 0]);
- }
+ }
}
diff --git a/app/Models/Item_taxes.php b/app/Models/Item_taxes.php
index 3692b942a..b43126443 100644
--- a/app/Models/Item_taxes.php
+++ b/app/Models/Item_taxes.php
@@ -9,91 +9,91 @@ use CodeIgniter\Model;
*/
class Item_taxes extends Model
{
- protected $table = 'item_taxes';
- protected $primaryKey = 'item_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'name',
- 'percent'
- ];
+ protected $table = 'item_taxes';
+ protected $primaryKey = 'item_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'name',
+ 'percent'
+ ];
- /**
- * Gets tax info for a particular item
- */
- public function get_info(int $item_id): array
- {
- $builder = $this->db->table('items_taxes');
- $builder->where('item_id', $item_id);
+ /**
+ * Gets tax info for a particular item
+ */
+ public function get_info(int $item_id): array
+ {
+ $builder = $this->db->table('items_taxes');
+ $builder->where('item_id', $item_id);
- //return an array of taxes for an item
- return $builder->get()->getResultArray();
- }
+ //return an array of taxes for an item
+ return $builder->get()->getResultArray();
+ }
- /**
- * Inserts or updates an item's taxes
- */
- public function save_value(array &$items_taxes_data, int $item_id): bool
- {
- $success = true;
+ /**
+ * Inserts or updates an item's taxes
+ */
+ public function save_value(array &$items_taxes_data, int $item_id): bool
+ {
+ $success = true;
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
- $this->delete($item_id);
+ $this->delete($item_id);
- $builder = $this->db->table('items_taxes');
+ $builder = $this->db->table('items_taxes');
- foreach($items_taxes_data as $row)
- {
- $row['item_id'] = $item_id;
- $success &= $builder->insert($row);
- }
+ foreach($items_taxes_data as $row)
+ {
+ $row['item_id'] = $item_id;
+ $success &= $builder->insert($row);
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Saves taxes for multiple items
- */
- public function save_multiple(array &$items_taxes_data, string $item_ids): bool //TODO: investigate why this is sent as a : delimited string rather than an array.
- {
- $success = true;
+ /**
+ * Saves taxes for multiple items
+ */
+ public function save_multiple(array &$items_taxes_data, string $item_ids): bool //TODO: investigate why this is sent as a : delimited string rather than an array.
+ {
+ $success = true;
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
- foreach(explode(':', $item_ids) as $item_id)
- {
- $this->delete($item_id);
+ foreach(explode(':', $item_ids) as $item_id)
+ {
+ $this->delete($item_id);
- $builder = $this->db->table('items_taxes');
+ $builder = $this->db->table('items_taxes');
- foreach($items_taxes_data as $row)
- {
- $row['item_id'] = $item_id;
- $success &= $builder->insert($row);
- }
- }
+ foreach($items_taxes_data as $row)
+ {
+ $row['item_id'] = $item_id;
+ $success &= $builder->insert($row);
+ }
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Deletes taxes given an item
- */
- public function delete($item_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('items_taxes');
+ /**
+ * Deletes taxes given an item
+ */
+ public function delete($item_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('items_taxes');
- return $builder->delete(['item_id' => $item_id]);
- }
+ return $builder->delete(['item_id' => $item_id]);
+ }
}
diff --git a/app/Models/Module.php b/app/Models/Module.php
index 73767b5a7..98630a5b9 100644
--- a/app/Models/Module.php
+++ b/app/Models/Module.php
@@ -10,157 +10,157 @@ use CodeIgniter\Model;
*/
class Module extends Model
{
- protected $table = 'modules';
- protected $primaryKey = 'module_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'name_lang_key',
- 'desc_lang_key',
- 'sort'
- ];
+ protected $table = 'modules';
+ protected $primaryKey = 'module_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'name_lang_key',
+ 'desc_lang_key',
+ 'sort'
+ ];
- /**
- * @param string $module_id
- * @return string
- */
- public function get_module_name(string $module_id): string
- {
- $builder = $this->db->table('modules');
- $query = $builder->getWhere(['module_id' => $module_id], 1);
+ /**
+ * @param string $module_id
+ * @return string
+ */
+ public function get_module_name(string $module_id): string
+ {
+ $builder = $this->db->table('modules');
+ $query = $builder->getWhere(['module_id' => $module_id], 1);
- if($query->getNumRows() == 1) //TODO: ===
- {
- $row = $query->getRow();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ $row = $query->getRow();
- return lang($row->name_lang_key);
- }
+ return lang($row->name_lang_key);
+ }
- return lang('Errors.unknown');
- }
+ return lang('Errors.unknown');
+ }
- /**
- * @param string $module_id
- * @return string
- */
- public function get_module_desc(string $module_id): string //TODO: This method doesn't seem to be called in the code. Is it needed? Also, probably should change the name to get_module_description()
- {
- $builder = $this->db->table('modules');
- $query = $builder->getWhere(['module_id' => $module_id], 1);
+ /**
+ * @param string $module_id
+ * @return string
+ */
+ public function get_module_desc(string $module_id): string //TODO: This method doesn't seem to be called in the code. Is it needed? Also, probably should change the name to get_module_description()
+ {
+ $builder = $this->db->table('modules');
+ $query = $builder->getWhere(['module_id' => $module_id], 1);
- if($query->getNumRows() == 1) //TODO: ===
- {
- $row = $query->getRow();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ $row = $query->getRow();
- return lang($row->desc_lang_key);
- }
+ return lang($row->desc_lang_key);
+ }
- return lang('Errors.unknown');
- }
+ return lang('Errors.unknown');
+ }
- /**
- * @return ResultInterface
- */
- public function get_all_permissions(): ResultInterface
- {
- $builder = $this->db->table('permissions');
+ /**
+ * @return ResultInterface
+ */
+ public function get_all_permissions(): ResultInterface
+ {
+ $builder = $this->db->table('permissions');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @return ResultInterface
- */
- public function get_all_subpermissions(): ResultInterface
- {
- $builder = $this->db->table('permissions');
- $builder->join('modules AS modules', 'modules.module_id = permissions.module_id'); //TODO: can the table parameter just be modules instead of modules AS modules?
+ /**
+ * @return ResultInterface
+ */
+ public function get_all_subpermissions(): ResultInterface
+ {
+ $builder = $this->db->table('permissions');
+ $builder->join('modules AS modules', 'modules.module_id = permissions.module_id'); //TODO: can the table parameter just be modules instead of modules AS modules?
- // can't quote the parameters correctly when using different operators..
- $builder->where('modules.module_id != ', 'permission_id', false);
+ // can't quote the parameters correctly when using different operators..
+ $builder->where('modules.module_id != ', 'permission_id', false);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @return ResultInterface
- */
- public function get_all_modules(): ResultInterface
- {
- $builder = $this->db->table('modules');
- $builder->orderBy('sort', 'asc');
+ /**
+ * @return ResultInterface
+ */
+ public function get_all_modules(): ResultInterface
+ {
+ $builder = $this->db->table('modules');
+ $builder->orderBy('sort', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param int $person_id
- * @return ResultInterface
- */
- public function get_allowed_home_modules(int $person_id): ResultInterface
- {
- $menus = ['home', 'both'];
- $builder = $this->db->table('modules'); //TODO: this is duplicated with the code below... probably refactor a method and just pass through whether home/office modules are needed.
- $builder->join('permissions', 'permissions.permission_id = modules.module_id');
- $builder->join('grants', 'permissions.permission_id = grants.permission_id');
- $builder->where('person_id', $person_id);
- $builder->whereIn('menu_group', $menus);
- $builder->where('sort !=', 0);
- $builder->orderBy('sort', 'asc');
+ /**
+ * @param int $person_id
+ * @return ResultInterface
+ */
+ public function get_allowed_home_modules(int $person_id): ResultInterface
+ {
+ $menus = ['home', 'both'];
+ $builder = $this->db->table('modules'); //TODO: this is duplicated with the code below... probably refactor a method and just pass through whether home/office modules are needed.
+ $builder->join('permissions', 'permissions.permission_id = modules.module_id');
+ $builder->join('grants', 'permissions.permission_id = grants.permission_id');
+ $builder->where('person_id', $person_id);
+ $builder->whereIn('menu_group', $menus);
+ $builder->where('sort !=', 0);
+ $builder->orderBy('sort', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param int $person_id
- * @return ResultInterface
- */
- public function get_allowed_office_modules(int $person_id): ResultInterface
- {
- $menus = ['office', 'both'];
- $builder = $this->db->table('modules'); //TODO: Duplicated code
- $builder->join('permissions', 'permissions.permission_id = modules.module_id');
- $builder->join('grants', 'permissions.permission_id = grants.permission_id');
- $builder->where('person_id', $person_id);
- $builder->whereIn('menu_group', $menus);
- $builder->where('sort !=', 0);
- $builder->orderBy('sort', 'asc');
+ /**
+ * @param int $person_id
+ * @return ResultInterface
+ */
+ public function get_allowed_office_modules(int $person_id): ResultInterface
+ {
+ $menus = ['office', 'both'];
+ $builder = $this->db->table('modules'); //TODO: Duplicated code
+ $builder->join('permissions', 'permissions.permission_id = modules.module_id');
+ $builder->join('grants', 'permissions.permission_id = grants.permission_id');
+ $builder->where('person_id', $person_id);
+ $builder->whereIn('menu_group', $menus);
+ $builder->where('sort !=', 0);
+ $builder->orderBy('sort', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * This method is used to set the show the office navigation icon on the home page
- * which happens when the sort value is greater than zero
- */
- public function set_show_office_group(bool $show_office_group): void //TODO: Should we return the value of update() as a bool for consistency?
- {
- if($show_office_group) //TODO: This should be replaced with ternary notation
- {
- $sort = 999;
- }
- else
- {
- $sort = 0;
- }
+ /**
+ * This method is used to set the show the office navigation icon on the home page
+ * which happens when the sort value is greater than zero
+ */
+ public function set_show_office_group(bool $show_office_group): void //TODO: Should we return the value of update() as a bool for consistency?
+ {
+ if($show_office_group) //TODO: This should be replaced with ternary notation
+ {
+ $sort = 999;
+ }
+ else
+ {
+ $sort = 0;
+ }
- $modules_data = ['sort' => $sort];
+ $modules_data = ['sort' => $sort];
- $builder = $this->db->table('modules');
- $builder->where('module_id', 'office');
- $builder->update($modules_data);
- }
+ $builder = $this->db->table('modules');
+ $builder->where('module_id', 'office');
+ $builder->update($modules_data);
+ }
- /**
- * This method is used to show the office navigation icon on the home page
- * which happens when the sort value is greater than zero
- */
- public function get_show_office_group(): int
- {
- $builder = $this->db->table('modules');
- $builder->select('sort');
- $builder->where('module_id', 'office');
+ /**
+ * This method is used to show the office navigation icon on the home page
+ * which happens when the sort value is greater than zero
+ */
+ public function get_show_office_group(): int
+ {
+ $builder = $this->db->table('modules');
+ $builder->select('sort');
+ $builder->where('module_id', 'office');
- return $builder->get()->getRow()->sort;
- }
+ return $builder->get()->getRow()->sort;
+ }
}
diff --git a/app/Models/Person.php b/app/Models/Person.php
index dcac3a0a0..00043086b 100644
--- a/app/Models/Person.php
+++ b/app/Models/Person.php
@@ -11,222 +11,222 @@ use stdClass;
*/
class Person extends Model
{
- protected $table = 'people';
- protected $primaryKey = 'person_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'first_name',
- 'last_name',
- 'phone_number',
- 'email',
- 'address_1',
- 'address_2',
- 'city',
- 'state',
- 'zip',
- 'country',
- 'comments',
- 'gender'
- ];
+ protected $table = 'people';
+ protected $primaryKey = 'person_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'first_name',
+ 'last_name',
+ 'phone_number',
+ 'email',
+ 'address_1',
+ 'address_2',
+ 'city',
+ 'state',
+ 'zip',
+ 'country',
+ 'comments',
+ 'gender'
+ ];
- /**
- * Determines whether the given person exists in the people database table
- *
- * @param integer $person_id identifier of the person to verify the existence
- *
- * @return boolean true if the person exists, false if not
- */
- public function exists(int $person_id): bool
- {
- $builder = $this->db->table('people');
- $builder->where('people.person_id', $person_id);
+ /**
+ * Determines whether the given person exists in the people database table
+ *
+ * @param integer $person_id identifier of the person to verify the existence
+ *
+ * @return boolean true if the person exists, false if not
+ */
+ public function exists(int $person_id): bool
+ {
+ $builder = $this->db->table('people');
+ $builder->where('people.person_id', $person_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets all people from the database table
- *
- * @param integer $limit limits the query return rows
- * @param integer $offset offset the query
- */
- public function get_all(int $limit = 10000, int $offset = 0): ResultInterface
- {
- $builder = $this->db->table('people');
- $builder->orderBy('last_name', 'asc');
- $builder->limit($limit);
- $builder->offset($offset);
+ /**
+ * Gets all people from the database table
+ *
+ * @param integer $limit limits the query return rows
+ * @param integer $offset offset the query
+ */
+ public function get_all(int $limit = 10000, int $offset = 0): ResultInterface
+ {
+ $builder = $this->db->table('people');
+ $builder->orderBy('last_name', 'asc');
+ $builder->limit($limit);
+ $builder->offset($offset);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets total of rows of people database table
- *
- * @return integer row counter
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('people');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows of people database table
+ *
+ * @return integer row counter
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('people');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about a person as an array
- *
- * @param integer $person_id identifier of the person
- *
- * @return object containing all the fields of the table row
- */
- public function get_info(int $person_id): object
- {
- $builder = $this->db->table('people');
- $query = $builder->getWhere(['person_id' => $person_id], 1);
+ /**
+ * Gets information about a person as an array
+ *
+ * @param integer $person_id identifier of the person
+ *
+ * @return object containing all the fields of the table row
+ */
+ public function get_info(int $person_id): object
+ {
+ $builder = $this->db->table('people');
+ $query = $builder->getWhere(['person_id' => $person_id], 1);
- if($query->getNumRows() == 1)
- {
- return $query->getRow();
- }
- else
- {
- return $this->getEmptyObject('people');
- }
- }
+ if($query->getNumRows() == 1)
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ return $this->getEmptyObject('people');
+ }
+ }
- /**
- * Initializes an empty object based on database definitions
- * @param string $table_name
- * @return object
- */
- private function getEmptyObject(string $table_name): object
- {
- // Return an empty base parent object, as $item_id is NOT an item
- $empty_obj = new stdClass();
+ /**
+ * Initializes an empty object based on database definitions
+ * @param string $table_name
+ * @return object
+ */
+ private function getEmptyObject(string $table_name): object
+ {
+ // Return an empty base parent object, as $item_id is NOT an item
+ $empty_obj = new stdClass();
- // Iterate through field definitions to determine how the fields should be initialized
- foreach($this->db->getFieldData($table_name) as $field)
- {
- $field_name = $field->name;
+ // Iterate through field definitions to determine how the fields should be initialized
+ foreach($this->db->getFieldData($table_name) as $field)
+ {
+ $field_name = $field->name;
- if(in_array($field->type, ['int', 'tinyint', 'decimal']))
- {
- $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
- }
- else
- {
- $empty_obj->$field_name = null;
- }
- }
+ if(in_array($field->type, ['int', 'tinyint', 'decimal']))
+ {
+ $empty_obj->$field_name = ($field->primary_key == 1) ? NEW_ENTRY : 0;
+ }
+ else
+ {
+ $empty_obj->$field_name = null;
+ }
+ }
- return $empty_obj;
- }
+ return $empty_obj;
+ }
- /**
- * Gets information about people as an array of rows
- *
- * @param array $person_ids array of people identifiers
- *
- */
- public function get_multiple_info(array $person_ids): ResultInterface
- {
- $builder = $this->db->table('people');
- $builder->whereIn('person_id', $person_ids);
- $builder->orderBy('last_name', 'asc');
+ /**
+ * Gets information about people as an array of rows
+ *
+ * @param array $person_ids array of people identifiers
+ *
+ */
+ public function get_multiple_info(array $person_ids): ResultInterface
+ {
+ $builder = $this->db->table('people');
+ $builder->whereIn('person_id', $person_ids);
+ $builder->orderBy('last_name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a person
- *
- * @param array $person_data array containing person information
- * @param int $person_id identifier of the person to update the information
- * @return boolean true if the save was successful, false if not
- */
- public function save_value(array &$person_data, int $person_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('people');
+ /**
+ * Inserts or updates a person
+ *
+ * @param array $person_data array containing person information
+ * @param int $person_id identifier of the person to update the information
+ * @return boolean true if the save was successful, false if not
+ */
+ public function save_value(array &$person_data, int $person_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('people');
- if($person_id == NEW_ENTRY || !$this->exists($person_id))
- {
- if($builder->insert($person_data))
- {
- $person_data['person_id'] = $this->db->insertID();
+ if($person_id == NEW_ENTRY || !$this->exists($person_id))
+ {
+ if($builder->insert($person_data))
+ {
+ $person_data['person_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('person_id', $person_id);
+ $builder->where('person_id', $person_id);
- return $builder->update($person_data);
- }
+ return $builder->update($person_data);
+ }
- /**
- * Get search suggestions to find person
- *
- * @param string $search string containing the term to search in the people table
- * @param int $limit limit the search
- * @return array array with the suggestion strings
- */
- public function get_search_suggestions(string $search, int $limit = 25): array
- {
- $suggestions = [];
+ /**
+ * Get search suggestions to find person
+ *
+ * @param string $search string containing the term to search in the people table
+ * @param int $limit limit the search
+ * @return array array with the suggestion strings
+ */
+ public function get_search_suggestions(string $search, int $limit = 25): array
+ {
+ $suggestions = [];
- $builder = $this->db->table('people');
+ $builder = $this->db->table('people');
//TODO: If this won't be added back into the code later, we should delete this commented section of code
-// $builder->select('person_id');
-// $builder->where('deleted', 0);
-// $builder->where('person_id', $search);
-// $builder->groupStart();
-// $builder->like('first_name', $search);
-// $builder->orLike('last_name', $search);
-// $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
-// $builder->orLike('email', $search);
-// $builder->orLike('phone_number', $search);
-// $builder->groupEnd();
-// $builder->orderBy('last_name', 'asc');
+// $builder->select('person_id');
+// $builder->where('deleted', 0);
+// $builder->where('person_id', $search);
+// $builder->groupStart();
+// $builder->like('first_name', $search);
+// $builder->orLike('last_name', $search);
+// $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+// $builder->orLike('email', $search);
+// $builder->orLike('phone_number', $search);
+// $builder->groupEnd();
+// $builder->orderBy('last_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['label' => $row->person_id];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['label' => $row->person_id];
+ }
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * Deletes one Person (dummy base function)
- *
- * @param integer $person_id person identifier
- * @return boolean always true
- */
- public function delete($person_id = null, bool $purge = false): bool
- {
- return true;
- }
+ /**
+ * Deletes one Person (dummy base function)
+ *
+ * @param integer $person_id person identifier
+ * @return boolean always true
+ */
+ public function delete($person_id = null, bool $purge = false): bool
+ {
+ return true;
+ }
- /**
- * Deletes a list of people (dummy base function)
- *
- * @param array $person_ids list of person identifiers
- * @return boolean always true
- */
- public function delete_list(array $person_ids): bool
- {
- return true;
- }
+ /**
+ * Deletes a list of people (dummy base function)
+ *
+ * @param array $person_ids list of person identifiers
+ * @return boolean always true
+ */
+ public function delete_list(array $person_ids): bool
+ {
+ return true;
+ }
}
diff --git a/app/Models/Receiving.php b/app/Models/Receiving.php
index 1e3a97a26..c0a756fb6 100644
--- a/app/Models/Receiving.php
+++ b/app/Models/Receiving.php
@@ -12,355 +12,355 @@ use ReflectionException;
*/
class Receiving extends Model
{
- protected $table = 'receivings';
- protected $primaryKey = 'receiving_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'receiving_time',
- 'supplier_id',
- 'employee_id',
- 'comment',
- 'receiving_id',
- 'payment_type',
- 'reference'
- ];
+ protected $table = 'receivings';
+ protected $primaryKey = 'receiving_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'receiving_time',
+ 'supplier_id',
+ 'employee_id',
+ 'comment',
+ 'receiving_id',
+ 'payment_type',
+ 'reference'
+ ];
- /**
- * @param int $receiving_id
- * @return ResultInterface
- */
- public function get_info(int $receiving_id): ResultInterface
- {
- $builder = $this->db->table('receivings');
- $builder->join('people', 'people.person_id = receivings.supplier_id', 'LEFT');
- $builder->join('suppliers', 'suppliers.person_id = receivings.supplier_id', 'LEFT');
- $builder->where('receiving_id', $receiving_id);
+ /**
+ * @param int $receiving_id
+ * @return ResultInterface
+ */
+ public function get_info(int $receiving_id): ResultInterface
+ {
+ $builder = $this->db->table('receivings');
+ $builder->join('people', 'people.person_id = receivings.supplier_id', 'LEFT');
+ $builder->join('suppliers', 'suppliers.person_id = receivings.supplier_id', 'LEFT');
+ $builder->where('receiving_id', $receiving_id);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $reference
- * @return ResultInterface
- */
- public function get_receiving_by_reference(string $reference): ResultInterface
- {
- $builder = $this->db->table('receivings');
- $builder->where('reference', $reference);
+ /**
+ * @param string $reference
+ * @return ResultInterface
+ */
+ public function get_receiving_by_reference(string $reference): ResultInterface
+ {
+ $builder = $this->db->table('receivings');
+ $builder->where('reference', $reference);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $receipt_receiving_id
- * @return bool
- */
- public function is_valid_receipt(string $receipt_receiving_id): bool //TODO: maybe receipt_receiving_id should be an array rather than a space delimited string
- {
- if(!empty($receipt_receiving_id))
- {
- //RECV #
- $pieces = explode(' ', $receipt_receiving_id);
+ /**
+ * @param string $receipt_receiving_id
+ * @return bool
+ */
+ public function is_valid_receipt(string $receipt_receiving_id): bool //TODO: maybe receipt_receiving_id should be an array rather than a space delimited string
+ {
+ if(!empty($receipt_receiving_id))
+ {
+ //RECV #
+ $pieces = explode(' ', $receipt_receiving_id);
- if(count($pieces) == 2 && preg_match('/(RECV|KIT)/', $pieces[0]))
- {
- return $this->exists($pieces[1]);
- }
- else
- {
- return $this->get_receiving_by_reference($receipt_receiving_id)->getNumRows() > 0;
- }
- }
+ if(count($pieces) == 2 && preg_match('/(RECV|KIT)/', $pieces[0]))
+ {
+ return $this->exists($pieces[1]);
+ }
+ else
+ {
+ return $this->get_receiving_by_reference($receipt_receiving_id)->getNumRows() > 0;
+ }
+ }
- return false;
- }
+ return false;
+ }
- /**
- * @param int $receiving_id
- * @return bool
- */
- public function exists(int $receiving_id): bool
- {
- $builder = $this->db->table('receivings');
- $builder->where('receiving_id', $receiving_id);
+ /**
+ * @param int $receiving_id
+ * @return bool
+ */
+ public function exists(int $receiving_id): bool
+ {
+ $builder = $this->db->table('receivings');
+ $builder->where('receiving_id', $receiving_id);
- return ($builder->get()->getNumRows() == 1);
- }
+ return ($builder->get()->getNumRows() == 1);
+ }
- /**
- * @param $receiving_id
- * @param $receiving_data
- * @return bool
- */
- public function update($receiving_id = null, $receiving_data = null): bool
- {
- $builder = $this->db->table('receivings');
- $builder->where('receiving_id', $receiving_id);
+ /**
+ * @param $receiving_id
+ * @param $receiving_data
+ * @return bool
+ */
+ public function update($receiving_id = null, $receiving_data = null): bool
+ {
+ $builder = $this->db->table('receivings');
+ $builder->where('receiving_id', $receiving_id);
- return $builder->update($receiving_data);
- }
+ return $builder->update($receiving_data);
+ }
- /**
- * @throws ReflectionException
- */
- public function save_value(array $items, int $supplier_id, int $employee_id, string $comment, string $reference, ?string $payment_type, int $receiving_id = NEW_ENTRY): int //TODO: $receiving_id gets overwritten before it's evaluated. It doesn't make sense to pass this here.
- {
- $attribute = model(Attribute::class);
- $inventory = model('Inventory');
- $item = model(Item::class);
- $item_quantity = model(Item_quantity::class);
- $supplier = model(Supplier::class);
+ /**
+ * @throws ReflectionException
+ */
+ public function save_value(array $items, int $supplier_id, int $employee_id, string $comment, string $reference, ?string $payment_type, int $receiving_id = NEW_ENTRY): int //TODO: $receiving_id gets overwritten before it's evaluated. It doesn't make sense to pass this here.
+ {
+ $attribute = model(Attribute::class);
+ $inventory = model('Inventory');
+ $item = model(Item::class);
+ $item_quantity = model(Item_quantity::class);
+ $supplier = model(Supplier::class);
- if(count($items) == 0)
- {
- return -1; //TODO: Replace -1 with a constant
- }
+ if(count($items) == 0)
+ {
+ return -1; //TODO: Replace -1 with a constant
+ }
- $receivings_data = [
- 'receiving_time' => date('Y-m-d H:i:s'),
- 'supplier_id' => $supplier->exists($supplier_id) ? $supplier_id : null,
- 'employee_id' => $employee_id,
- 'payment_type' => $payment_type,
- 'comment' => $comment,
- 'reference' => $reference
- ];
+ $receivings_data = [
+ 'receiving_time' => date('Y-m-d H:i:s'),
+ 'supplier_id' => $supplier->exists($supplier_id) ? $supplier_id : null,
+ 'employee_id' => $employee_id,
+ 'payment_type' => $payment_type,
+ 'comment' => $comment,
+ 'reference' => $reference
+ ];
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
- $builder = $this->db->table('receivings');
- $builder->insert($receivings_data);
- $receiving_id = $this->db->insertID();
+ $builder = $this->db->table('receivings');
+ $builder->insert($receivings_data);
+ $receiving_id = $this->db->insertID();
- $builder = $this->db->table('receivings_items');
+ $builder = $this->db->table('receivings_items');
- foreach($items as $line => $item_data)
- {
- $config = config(OSPOS::class)->settings;
- $cur_item_info = $item->get_info($item_data['item_id']);
+ foreach($items as $line => $item_data)
+ {
+ $config = config(OSPOS::class)->settings;
+ $cur_item_info = $item->get_info($item_data['item_id']);
- $receivings_items_data = [
- 'receiving_id' => $receiving_id,
- 'item_id' => $item_data['item_id'],
- 'line' => $item_data['line'],
- 'description' => $item_data['description'],
- 'serialnumber' => $item_data['serialnumber'],
- 'quantity_purchased' => $item_data['quantity'],
- 'receiving_quantity' => $item_data['receiving_quantity'],
- 'discount' => $item_data['discount'],
- 'discount_type' => $item_data['discount_type'],
- 'item_cost_price' => $cur_item_info->cost_price,
- 'item_unit_price' => $item_data['price'],
- 'item_location' => $item_data['item_location']
- ];
+ $receivings_items_data = [
+ 'receiving_id' => $receiving_id,
+ 'item_id' => $item_data['item_id'],
+ 'line' => $item_data['line'],
+ 'description' => $item_data['description'],
+ 'serialnumber' => $item_data['serialnumber'],
+ 'quantity_purchased' => $item_data['quantity'],
+ 'receiving_quantity' => $item_data['receiving_quantity'],
+ 'discount' => $item_data['discount'],
+ 'discount_type' => $item_data['discount_type'],
+ 'item_cost_price' => $cur_item_info->cost_price,
+ 'item_unit_price' => $item_data['price'],
+ 'item_location' => $item_data['item_location']
+ ];
- $builder->insert($receivings_items_data);
+ $builder->insert($receivings_items_data);
- $items_received = $item_data['receiving_quantity'] != 0 ? $item_data['quantity'] * $item_data['receiving_quantity'] : $item_data['quantity'];
+ $items_received = $item_data['receiving_quantity'] != 0 ? $item_data['quantity'] * $item_data['receiving_quantity'] : $item_data['quantity'];
- // update cost price, if changed AND is set in config as wanted
- if($cur_item_info->cost_price != $item_data['price'] && $config['receiving_calculate_average_price'])
- {
- $item->change_cost_price($item_data['item_id'], $items_received, $item_data['price'], $cur_item_info->cost_price);
- }
+ // update cost price, if changed AND is set in config as wanted
+ if($cur_item_info->cost_price != $item_data['price'] && $config['receiving_calculate_average_price'])
+ {
+ $item->change_cost_price($item_data['item_id'], $items_received, $item_data['price'], $cur_item_info->cost_price);
+ }
- //Update stock quantity
- $item_quantity_value = $item_quantity->get_item_quantity($item_data['item_id'], $item_data['item_location']);
- $item_quantity->save_value([
- 'quantity' => $item_quantity_value->quantity + $items_received,
- 'item_id' => $item_data['item_id'],
- 'location_id' => $item_data['item_location']],
- $item_data['item_id'],
- $item_data['item_location']
- );
+ //Update stock quantity
+ $item_quantity_value = $item_quantity->get_item_quantity($item_data['item_id'], $item_data['item_location']);
+ $item_quantity->save_value([
+ 'quantity' => $item_quantity_value->quantity + $items_received,
+ 'item_id' => $item_data['item_id'],
+ 'location_id' => $item_data['item_location']],
+ $item_data['item_id'],
+ $item_data['item_location']
+ );
- $recv_remarks = 'RECV ' . $receiving_id;
- $inv_data = [
- 'trans_date' => date('Y-m-d H:i:s'),
- 'trans_items' => $item_data['item_id'],
- 'trans_user' => $employee_id,
- 'trans_location' => $item_data['item_location'],
- 'trans_comment' => $recv_remarks,
- 'trans_inventory' => $items_received
- ];
+ $recv_remarks = 'RECV ' . $receiving_id;
+ $inv_data = [
+ 'trans_date' => date('Y-m-d H:i:s'),
+ 'trans_items' => $item_data['item_id'],
+ 'trans_user' => $employee_id,
+ 'trans_location' => $item_data['item_location'],
+ 'trans_comment' => $recv_remarks,
+ 'trans_inventory' => $items_received
+ ];
- $inventory->insert($inv_data, false);
- $attribute->copy_attribute_links($item_data['item_id'], 'receiving_id', $receiving_id);
- }
+ $inventory->insert($inv_data, false);
+ $attribute->copy_attribute_links($item_data['item_id'], 'receiving_id', $receiving_id);
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- return $this->db->transStatus() ? $receiving_id : -1;
- }
+ return $this->db->transStatus() ? $receiving_id : -1;
+ }
- /**
- * @throws ReflectionException
- */
- public function delete_list(array $receiving_ids, int $employee_id, bool $update_inventory = true): bool
- {
- $success = true;
+ /**
+ * @throws ReflectionException
+ */
+ public function delete_list(array $receiving_ids, int $employee_id, bool $update_inventory = true): bool
+ {
+ $success = true;
- // start a transaction to assure data integrity
- $this->db->transStart();
+ // start a transaction to assure data integrity
+ $this->db->transStart();
- foreach($receiving_ids as $receiving_id)
- {
- $success &= $this->delete_value($receiving_id, $employee_id, $update_inventory);
- }
+ foreach($receiving_ids as $receiving_id)
+ {
+ $success &= $this->delete_value($receiving_id, $employee_id, $update_inventory);
+ }
- // execute transaction
- $this->db->transComplete();
+ // execute transaction
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * @throws ReflectionException
- */
- public function delete_value(int $receiving_id, int $employee_id, bool $update_inventory = true): bool
- {
- // start a transaction to assure data integrity
- $this->db->transStart();
+ /**
+ * @throws ReflectionException
+ */
+ public function delete_value(int $receiving_id, int $employee_id, bool $update_inventory = true): bool
+ {
+ // start a transaction to assure data integrity
+ $this->db->transStart();
- if($update_inventory)
- {
- //TODO: defect, not all item deletions will be undone? get array with all the items involved in the sale to update the inventory tracking
- $items = $this->get_receiving_items($receiving_id)->getResultArray();
+ if($update_inventory)
+ {
+ //TODO: defect, not all item deletions will be undone? get array with all the items involved in the sale to update the inventory tracking
+ $items = $this->get_receiving_items($receiving_id)->getResultArray();
- $inventory = model('Inventory');
- $item_quantity = model(Item_quantity::class);
+ $inventory = model('Inventory');
+ $item_quantity = model(Item_quantity::class);
- foreach($items as $item)
- {
- // create query to update inventory tracking
- $inv_data = [
- 'trans_date' => date('Y-m-d H:i:s'),
- 'trans_items' => $item['item_id'],
- 'trans_user' => $employee_id,
- 'trans_comment' => 'Deleting receiving ' . $receiving_id,
- 'trans_location' => $item['item_location'],
- 'trans_inventory' => $item['quantity_purchased'] * (-$item['receiving_quantity'])
- ];
- // update inventory
- $inventory->insert($inv_data, false);
+ foreach($items as $item)
+ {
+ // create query to update inventory tracking
+ $inv_data = [
+ 'trans_date' => date('Y-m-d H:i:s'),
+ 'trans_items' => $item['item_id'],
+ 'trans_user' => $employee_id,
+ 'trans_comment' => 'Deleting receiving ' . $receiving_id,
+ 'trans_location' => $item['item_location'],
+ 'trans_inventory' => $item['quantity_purchased'] * (-$item['receiving_quantity'])
+ ];
+ // update inventory
+ $inventory->insert($inv_data, false);
- // update quantities
- $item_quantity->change_quantity($item['item_id'], $item['item_location'], $item['quantity_purchased'] * (-$item['receiving_quantity']));
- }
- }
+ // update quantities
+ $item_quantity->change_quantity($item['item_id'], $item['item_location'], $item['quantity_purchased'] * (-$item['receiving_quantity']));
+ }
+ }
- //delete all items
- $builder = $this->db->table('receivings_items');
- $builder->delete(['receiving_id' => $receiving_id]);
+ //delete all items
+ $builder = $this->db->table('receivings_items');
+ $builder->delete(['receiving_id' => $receiving_id]);
- //delete sale itself
- $builder = $this->db->table('receivings');
- $builder->delete(['receiving_id' => $receiving_id]);
+ //delete sale itself
+ $builder = $this->db->table('receivings');
+ $builder->delete(['receiving_id' => $receiving_id]);
- // execute transaction
- $this->db->transComplete();
+ // execute transaction
+ $this->db->transComplete();
- return $this->db->transStatus();
- }
+ return $this->db->transStatus();
+ }
- /**
- * @param int $receiving_id
- * @return ResultInterface
- */
- public function get_receiving_items(int $receiving_id): ResultInterface
- {
- $builder = $this->db->table('receivings_items');
- $builder->where('receiving_id', $receiving_id);
+ /**
+ * @param int $receiving_id
+ * @return ResultInterface
+ */
+ public function get_receiving_items(int $receiving_id): ResultInterface
+ {
+ $builder = $this->db->table('receivings_items');
+ $builder->where('receiving_id', $receiving_id);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param int $receiving_id
- * @return object
- */
- public function get_supplier(int $receiving_id): object
- {
- $builder = $this->db->table('receivings');
- $builder->where('receiving_id', $receiving_id);
+ /**
+ * @param int $receiving_id
+ * @return object
+ */
+ public function get_supplier(int $receiving_id): object
+ {
+ $builder = $this->db->table('receivings');
+ $builder->where('receiving_id', $receiving_id);
- $supplier = model(Supplier::class);
- return $supplier->get_info($builder->get()->getRow()->supplier_id);
- }
+ $supplier = model(Supplier::class);
+ return $supplier->get_info($builder->get()->getRow()->supplier_id);
+ }
- /**
- * @return array
- */
- public function get_payment_options(): array
- {
- return [
- lang('Sales.cash') => lang('Sales.cash'),
- lang('Sales.check') => lang('Sales.check'),
- lang('Sales.debit') => lang('Sales.debit'),
- lang('Sales.credit') => lang('Sales.credit'),
- lang('Sales.due') => lang('Sales.due')
- ];
- }
+ /**
+ * @return array
+ */
+ public function get_payment_options(): array
+ {
+ return [
+ lang('Sales.cash') => lang('Sales.cash'),
+ lang('Sales.check') => lang('Sales.check'),
+ lang('Sales.debit') => lang('Sales.debit'),
+ lang('Sales.credit') => lang('Sales.credit'),
+ lang('Sales.due') => lang('Sales.due')
+ ];
+ }
- /**
- * Create a temp table that allows us to do easy report/receiving queries
- */
- public function create_temp_table(array $inputs): void
- {
- $config = config(OSPOS::class)->settings;
- $db_prefix = $this->db->getPrefix();
+ /**
+ * Create a temp table that allows us to do easy report/receiving queries
+ */
+ public function create_temp_table(array $inputs): void
+ {
+ $config = config(OSPOS::class)->settings;
+ $db_prefix = $this->db->getPrefix();
- if(empty($inputs['receiving_id']))
- {
- $where = empty($config['date_or_time_format'])
- ? 'DATE(`receiving_time`) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date'])
- : 'receiving_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
- }
- else
- {
- $where = 'receivings_items.receiving_id = ' . $this->db->escape($inputs['receiving_id']);
- }
+ if(empty($inputs['receiving_id']))
+ {
+ $where = empty($config['date_or_time_format'])
+ ? 'DATE(`receiving_time`) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date'])
+ : 'receiving_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
+ }
+ else
+ {
+ $where = 'receivings_items.receiving_id = ' . $this->db->escape($inputs['receiving_id']);
+ }
- $builder = $this->db->table('receivings_items');
- $builder->select([
- 'MAX(DATE(`receiving_time`)) AS receiving_date',
- 'MAX(`receiving_time`) AS receiving_time',
- 'receivings_items.receiving_id AS receiving_id',
- 'MAX(`comment`) AS comment',
- 'MAX(`item_location`) AS item_location',
- 'MAX(`reference`) AS reference',
- 'MAX(`payment_type`) AS payment_type',
- 'MAX(`employee_id`) AS employee_id',
- 'items.item_id AS item_id',
- 'MAX(`'. $db_prefix .'receivings`.`supplier_id`) AS supplier_id',
- 'MAX(`quantity_purchased`) AS quantity_purchased',
- 'MAX(`'. $db_prefix .'receivings_items`.`receiving_quantity`) AS item_receiving_quantity',
- 'MAX(`item_cost_price`) AS item_cost_price',
- 'MAX(`item_unit_price`) AS item_unit_price',
- 'MAX(`discount`) AS discount',
- 'MAX(`discount_type`) AS discount_type',
- 'receivings_items.line AS line',
- 'MAX(`serialnumber`) AS serialnumber',
- 'MAX(`'. $db_prefix .'receivings_items`.`description`) AS description',
- 'MAX(CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `discount` END) AS subtotal',
- 'MAX(CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `discount` END) AS total',
- 'MAX((CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - discount END) - (`item_cost_price` * `quantity_purchased`)) AS profit',
- 'MAX(`item_cost_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` ) AS cost'
- ]);
- $builder->join('receivings', 'receivings_items.receiving_id = receivings.receiving_id', 'inner');
- $builder->join('items', 'receivings_items.item_id = items.item_id', 'inner');
- $builder->where($where);
- $builder->groupBy(['receivings_items.receiving_id', 'items.item_id', 'receivings_items.line']);
- $selectQuery = $builder->getCompiledSelect();
+ $builder = $this->db->table('receivings_items');
+ $builder->select([
+ 'MAX(DATE(`receiving_time`)) AS receiving_date',
+ 'MAX(`receiving_time`) AS receiving_time',
+ 'receivings_items.receiving_id AS receiving_id',
+ 'MAX(`comment`) AS comment',
+ 'MAX(`item_location`) AS item_location',
+ 'MAX(`reference`) AS reference',
+ 'MAX(`payment_type`) AS payment_type',
+ 'MAX(`employee_id`) AS employee_id',
+ 'items.item_id AS item_id',
+ 'MAX(`'. $db_prefix .'receivings`.`supplier_id`) AS supplier_id',
+ 'MAX(`quantity_purchased`) AS quantity_purchased',
+ 'MAX(`'. $db_prefix .'receivings_items`.`receiving_quantity`) AS item_receiving_quantity',
+ 'MAX(`item_cost_price`) AS item_cost_price',
+ 'MAX(`item_unit_price`) AS item_unit_price',
+ 'MAX(`discount`) AS discount',
+ 'MAX(`discount_type`) AS discount_type',
+ 'receivings_items.line AS line',
+ 'MAX(`serialnumber`) AS serialnumber',
+ 'MAX(`'. $db_prefix .'receivings_items`.`description`) AS description',
+ 'MAX(CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `discount` END) AS subtotal',
+ 'MAX(CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `discount` END) AS total',
+ 'MAX((CASE WHEN `'. $db_prefix .'receivings_items`.`discount_type` = ' . PERCENT . ' THEN `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` * `discount` / 100 ELSE `item_unit_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` - discount END) - (`item_cost_price` * `quantity_purchased`)) AS profit',
+ 'MAX(`item_cost_price` * `quantity_purchased` * `'. $db_prefix .'receivings_items`.`receiving_quantity` ) AS cost'
+ ]);
+ $builder->join('receivings', 'receivings_items.receiving_id = receivings.receiving_id', 'inner');
+ $builder->join('items', 'receivings_items.item_id = items.item_id', 'inner');
+ $builder->where($where);
+ $builder->groupBy(['receivings_items.receiving_id', 'items.item_id', 'receivings_items.line']);
+ $selectQuery = $builder->getCompiledSelect();
- //QueryBuilder does not support creating temporary tables.
- $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('receivings_items_temp') .
- ' (INDEX(receiving_date), INDEX(receiving_time), INDEX(receiving_id)) AS (' . $selectQuery . ')';
+ //QueryBuilder does not support creating temporary tables.
+ $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('receivings_items_temp') .
+ ' (INDEX(receiving_date), INDEX(receiving_time), INDEX(receiving_id)) AS (' . $selectQuery . ')';
- $this->db->query($sql);
- }
+ $this->db->query($sql);
+ }
}
diff --git a/app/Models/Reports/Detailed_receivings.php b/app/Models/Reports/Detailed_receivings.php
index f65d6b859..3744a3328 100644
--- a/app/Models/Reports/Detailed_receivings.php
+++ b/app/Models/Reports/Detailed_receivings.php
@@ -12,180 +12,180 @@ use App\Models\Receiving;
*/
class Detailed_receivings extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $receiving = model(Receiving::class);
- $receiving->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $receiving = model(Receiving::class);
+ $receiving->create_temp_table($inputs);
+ }
- /**
- * @return array
- */
- public function getDataColumns(): array
- {
- return [
- 'summary' => [
- ['id' => lang('Reports.receiving_id')],
- ['receiving_time' => lang('Reports.date'), 'sortable' => false],
- ['quantity' => lang('Reports.quantity')],
- ['employee_name' => lang('Reports.received_by')],
- ['supplier_name' => lang('Reports.supplied_by')],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['payment_type' => lang('Reports.payment_type')],
- ['comment' => lang('Reports.comments')],
- ['reference' => lang('Receivings.reference')]
- ],
- 'details' => [
- lang('Reports.item_number'),
- lang('Reports.name'),
- lang('Reports.category'),
- lang('Reports.quantity'),
- lang('Reports.total'),
- lang('Reports.discount')
- ]
- ];
- }
+ /**
+ * @return array
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ 'summary' => [
+ ['id' => lang('Reports.receiving_id')],
+ ['receiving_time' => lang('Reports.date'), 'sortable' => false],
+ ['quantity' => lang('Reports.quantity')],
+ ['employee_name' => lang('Reports.received_by')],
+ ['supplier_name' => lang('Reports.supplied_by')],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['payment_type' => lang('Reports.payment_type')],
+ ['comment' => lang('Reports.comments')],
+ ['reference' => lang('Receivings.reference')]
+ ],
+ 'details' => [
+ lang('Reports.item_number'),
+ lang('Reports.name'),
+ lang('Reports.category'),
+ lang('Reports.quantity'),
+ lang('Reports.total'),
+ lang('Reports.discount')
+ ]
+ ];
+ }
- /**
- * @param string $receiving_id
- * @return array
- */
- public function getDataByReceivingId(string $receiving_id): array
- {
- $builder = $this->db->table('receivings_items_temp');
- $builder->select('receiving_id,
- MAX(receiving_time) as receiving_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
- MAX(supplier.company_name) AS supplier_name,
- SUM(subtotal) AS subtotal,
- SUM(total) AS total,
- SUM(profit) AS profit,
- MAX(payment_type) as payment_type,
- MAX(comment) as comment,
- MAX(reference) as reference');
- $builder->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id');
- $builder->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left');
- $builder->where('receiving_id', $receiving_id);
- $builder->groupBy('receiving_id');
+ /**
+ * @param string $receiving_id
+ * @return array
+ */
+ public function getDataByReceivingId(string $receiving_id): array
+ {
+ $builder = $this->db->table('receivings_items_temp');
+ $builder->select('receiving_id,
+ MAX(receiving_time) as receiving_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
+ MAX(supplier.company_name) AS supplier_name,
+ SUM(subtotal) AS subtotal,
+ SUM(total) AS total,
+ SUM(profit) AS profit,
+ MAX(payment_type) as payment_type,
+ MAX(comment) as comment,
+ MAX(reference) as reference');
+ $builder->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id');
+ $builder->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left');
+ $builder->where('receiving_id', $receiving_id);
+ $builder->groupBy('receiving_id');
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('receivings_items_temp AS receivings_items_temp');
- $builder->select('receiving_id,
- MAX(receiving_time) as receiving_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(CONCAT(employee.first_name," ",employee.last_name)) AS employee_name,
- MAX(supplier.company_name) AS supplier_name,
- SUM(total) AS total,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(comment) AS comment,
- MAX(reference) AS reference');
- $builder->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id');
- $builder->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('receivings_items_temp AS receivings_items_temp');
+ $builder->select('receiving_id,
+ MAX(receiving_time) as receiving_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(CONCAT(employee.first_name," ",employee.last_name)) AS employee_name,
+ MAX(supplier.company_name) AS supplier_name,
+ SUM(total) AS total,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(comment) AS comment,
+ MAX(reference) AS reference');
+ $builder->join('people AS employee', 'receivings_items_temp.employee_id = employee.person_id');
+ $builder->join('suppliers AS supplier', 'receivings_items_temp.supplier_id = supplier.person_id', 'left');
- if($inputs['location_id'] != 'all')
- {
- $builder->where('item_location', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all')
+ {
+ $builder->where('item_location', $inputs['location_id']);
+ }
- if($inputs['receiving_type'] == 'receiving') //TODO: These if statements should be replaced with a switch statement
- {
- $builder->where('quantity_purchased >', 0);
- }
- elseif($inputs['receiving_type'] == 'returns')
- {
- $builder->where('quantity_purchased <', 0);
- }
- elseif($inputs['receiving_type'] == 'requisitions')
- {
- $builder->having('items_purchased = 0');
- }
+ if($inputs['receiving_type'] == 'receiving') //TODO: These if statements should be replaced with a switch statement
+ {
+ $builder->where('quantity_purchased >', 0);
+ }
+ elseif($inputs['receiving_type'] == 'returns')
+ {
+ $builder->where('quantity_purchased <', 0);
+ }
+ elseif($inputs['receiving_type'] == 'requisitions')
+ {
+ $builder->having('items_purchased = 0');
+ }
- $builder->groupBy('receiving_id', 'receiving_time');
- $builder->orderBy('MAX(receiving_id)');
+ $builder->groupBy('receiving_id', 'receiving_time');
+ $builder->orderBy('MAX(receiving_id)');
- $data = [];
- $data['summary'] = $builder->get()->getResultArray();
- $data['details'] = [];
+ $data = [];
+ $data['summary'] = $builder->get()->getResultArray();
+ $data['details'] = [];
- $builder = $this->db->table('receivings_items_temp');
+ $builder = $this->db->table('receivings_items_temp');
- foreach($data['summary'] as $key => $value)
- {
- $builder->select('
- MAX(name) AS name,
- MAX(item_number) AS item_number,
- MAX(category) AS category,
- MAX(quantity_purchased) AS quantity_purchased,
- MAX(serialnumber) AS serialnumber,
- MAX(total) AS total,
- MAX(discount) AS discount,
- MAX(discount_type) AS discount_type,
- MAX(item_location) AS item_location,
- MAX(item_receiving_quantity) AS receiving_quantity');
- $builder->join('items', 'receivings_items_temp.item_id = items.item_id');
+ foreach($data['summary'] as $key => $value)
+ {
+ $builder->select('
+ MAX(name) AS name,
+ MAX(item_number) AS item_number,
+ MAX(category) AS category,
+ MAX(quantity_purchased) AS quantity_purchased,
+ MAX(serialnumber) AS serialnumber,
+ MAX(total) AS total,
+ MAX(discount) AS discount,
+ MAX(discount_type) AS discount_type,
+ MAX(item_location) AS item_location,
+ MAX(item_receiving_quantity) AS receiving_quantity');
+ $builder->join('items', 'receivings_items_temp.item_id = items.item_id');
- if(count($inputs['definition_ids']) > 0)
- {
- $format = $this->db->escape(dateformat_mysql());
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
- $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
- $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id = receivings_items_temp.receiving_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
- }
+ if(count($inputs['definition_ids']) > 0)
+ {
+ $format = $this->db->escape(dateformat_mysql());
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
+ $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
+ $builder->join('attribute_links', 'attribute_links.item_id = items.item_id AND attribute_links.receiving_id = receivings_items_temp.receiving_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
+ }
- $builder->where('receivings_items_temp.receiving_id', $value['receiving_id']);
- $builder->groupBy('receivings_items_temp.receiving_id, receivings_items_temp.item_id');
- $data['details'][$key] = $builder->get()->getResultArray();
- }
+ $builder->where('receivings_items_temp.receiving_id', $value['receiving_id']);
+ $builder->groupBy('receivings_items_temp.receiving_id, receivings_items_temp.item_id');
+ $data['details'][$key] = $builder->get()->getResultArray();
+ }
- return $data;
- }
+ return $data;
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('receivings_items_temp');
- $builder->select('SUM(total) AS total');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('receivings_items_temp');
+ $builder->select('SUM(total) AS total');
- if($inputs['location_id'] != 'all')
- {
- $builder->where('item_location', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all')
+ {
+ $builder->where('item_location', $inputs['location_id']);
+ }
- switch($inputs['receiving_type'])
- {
- case 'receiving':
- $builder->where('quantity_purchased >', 0);
- break;
+ switch($inputs['receiving_type'])
+ {
+ case 'receiving':
+ $builder->where('quantity_purchased >', 0);
+ break;
- case 'returns':
- $builder->where('quantity_purchased <', 0);
- break;
+ case 'returns':
+ $builder->where('quantity_purchased <', 0);
+ break;
- case 'requisitions':
- $builder->where('quantity_purchased', 0);
- break;
- }
+ case 'requisitions':
+ $builder->where('quantity_purchased', 0);
+ break;
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Detailed_sales.php b/app/Models/Reports/Detailed_sales.php
index e682e608f..2fcd88a6e 100644
--- a/app/Models/Reports/Detailed_sales.php
+++ b/app/Models/Reports/Detailed_sales.php
@@ -12,260 +12,260 @@ use App\Models\Sale;
*/
class Detailed_sales extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $sale = model(Sale::class);
- $sale->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $sale = model(Sale::class);
+ $sale->create_temp_table($inputs);
+ }
- /**
- * @return array
- */
- public function getDataColumns(): array
- {
- return [ //TODO: Duplicated code
- 'summary' => [
- ['id' => lang('Reports.sale_id')],
- ['type_code' => lang('Reports.code_type')],
- ['sale_time' => lang('Reports.date'), 'sortable' => false],
- ['quantity' => lang('Reports.quantity')],
- ['employee_name' => lang('Reports.sold_by')],
- ['customer_name' => lang('Reports.sold_to')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
- ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
- ['comment' => lang('Reports.comments')]
- ],
- 'details' => [
- lang('Reports.name'),
- lang('Reports.category'),
- lang('Reports.item_number'),
- lang('Reports.description'),
- lang('Reports.quantity'),
- lang('Reports.subtotal'),
- lang('Reports.tax'),
- lang('Reports.total'),
- lang('Reports.cost'),
- lang('Reports.profit'),
- lang('Reports.discount')
- ],
- 'details_rewards' => [
- lang('Reports.used'),
- lang('Reports.earned')
- ]
- ];
- }
+ /**
+ * @return array
+ */
+ public function getDataColumns(): array
+ {
+ return [ //TODO: Duplicated code
+ 'summary' => [
+ ['id' => lang('Reports.sale_id')],
+ ['type_code' => lang('Reports.code_type')],
+ ['sale_time' => lang('Reports.date'), 'sortable' => false],
+ ['quantity' => lang('Reports.quantity')],
+ ['employee_name' => lang('Reports.sold_by')],
+ ['customer_name' => lang('Reports.sold_to')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
+ ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
+ ['comment' => lang('Reports.comments')]
+ ],
+ 'details' => [
+ lang('Reports.name'),
+ lang('Reports.category'),
+ lang('Reports.item_number'),
+ lang('Reports.description'),
+ lang('Reports.quantity'),
+ lang('Reports.subtotal'),
+ lang('Reports.tax'),
+ lang('Reports.total'),
+ lang('Reports.cost'),
+ lang('Reports.profit'),
+ lang('Reports.discount')
+ ],
+ 'details_rewards' => [
+ lang('Reports.used'),
+ lang('Reports.earned')
+ ]
+ ];
+ }
- /**
- * @param int $sale_id
- * @return array
- */
- public function getDataBySaleId(int $sale_id): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('sale_id,
- MAX(sale_time) as sale_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(employee_name) AS employee_name,
- MAX(customer_name) AS customer_name,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(sale_status) AS sale_status,
- comment');
- $builder->where('sale_id', $sale_id);
+ /**
+ * @param int $sale_id
+ * @return array
+ */
+ public function getDataBySaleId(int $sale_id): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('sale_id,
+ MAX(sale_time) as sale_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(employee_name) AS employee_name,
+ MAX(customer_name) AS customer_name,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(sale_status) AS sale_status,
+ comment');
+ $builder->where('sale_id', $sale_id);
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('sale_id,
- MAX(CASE
- WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
- WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
- WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
- WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
- WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
- WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
- ELSE \'\'
- END) AS type_code,
- MAX(sale_status) as sale_status,
- MAX(sale_time) AS sale_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(employee_name) AS employee_name,
- MAX(customer_name) AS customer_name,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(comment) AS comment');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('sale_id,
+ MAX(CASE
+ WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
+ WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
+ WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
+ WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
+ WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
+ WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
+ ELSE \'\'
+ END) AS type_code,
+ MAX(sale_status) as sale_status,
+ MAX(sale_time) AS sale_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(employee_name) AS employee_name,
+ MAX(customer_name) AS customer_name,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(comment) AS comment');
- if($inputs['location_id'] != 'all') //TODO: Duplicated code
- {
- $builder->where('item_location', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all') //TODO: Duplicated code
+ {
+ $builder->where('item_location', $inputs['location_id']);
+ }
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- $builder->groupBy('sale_id');
- $builder->orderBy('MAX(sale_time)');
+ $builder->groupBy('sale_id');
+ $builder->orderBy('MAX(sale_time)');
- $data = [];
- $data['summary'] = $builder->get()->getResultArray();
- $data['details'] = [];
- $data['rewards'] = [];
+ $data = [];
+ $data['summary'] = $builder->get()->getResultArray();
+ $data['details'] = [];
+ $data['rewards'] = [];
- foreach($data['summary'] as $key => $value)
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('
- MAX(name) AS name,
- MAX(category) AS category,
- MAX(quantity_purchased) AS quantity_purchased,
- MAX(item_location) AS item_location,
- MAX(item_number) AS item_number,
- MAX(description) AS description,
- MAX(subtotal) AS subtotal,
- MAX(tax) AS tax,
- MAX(total) AS total,
- MAX(cost) AS cost,
- MAX(profit) AS profit,
- MAX(discount) AS discount,
- MAX(discount_type) AS discount_type,
- MAX(sale_status) AS sale_status');
+ foreach($data['summary'] as $key => $value)
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('
+ MAX(name) AS name,
+ MAX(category) AS category,
+ MAX(quantity_purchased) AS quantity_purchased,
+ MAX(item_location) AS item_location,
+ MAX(item_number) AS item_number,
+ MAX(description) AS description,
+ MAX(subtotal) AS subtotal,
+ MAX(tax) AS tax,
+ MAX(total) AS total,
+ MAX(cost) AS cost,
+ MAX(profit) AS profit,
+ MAX(discount) AS discount,
+ MAX(discount_type) AS discount_type,
+ MAX(sale_status) AS sale_status');
- if(count($inputs['definition_ids']) > 0)
- {
- $format = $this->db->escape(dateformat_mysql());
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
- $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
- $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
- $builder->join('attribute_links', 'attribute_links.item_id = sales_items_temp.item_id AND attribute_links.sale_id = sales_items_temp.sale_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left');
- $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
- }
+ if(count($inputs['definition_ids']) > 0)
+ {
+ $format = $this->db->escape(dateformat_mysql());
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_value) ORDER BY definition_id SEPARATOR \'|\') AS attribute_values');
+ $builder->select("GROUP_CONCAT(DISTINCT CONCAT_WS('_', definition_id, DATE_FORMAT(attribute_date, $format)) SEPARATOR '|') AS attribute_dtvalues");
+ $builder->select('GROUP_CONCAT(DISTINCT CONCAT_WS(\'_\', definition_id, attribute_decimal) SEPARATOR \'|\') AS attribute_dvalues');
+ $builder->join('attribute_links', 'attribute_links.item_id = sales_items_temp.item_id AND attribute_links.sale_id = sales_items_temp.sale_id AND definition_id IN (' . implode(',', $inputs['definition_ids']) . ')', 'left');
+ $builder->join('attribute_values', 'attribute_values.attribute_id = attribute_links.attribute_id', 'left');
+ }
- $builder->groupBy('sales_items_temp.sale_id, sales_items_temp.item_id, sales_items_temp.sale_id');
- $builder->where('sales_items_temp.sale_id', $value['sale_id']);
- $data['details'][$key] = $builder->get()->getResultArray();
+ $builder->groupBy('sales_items_temp.sale_id, sales_items_temp.item_id, sales_items_temp.sale_id');
+ $builder->where('sales_items_temp.sale_id', $value['sale_id']);
+ $data['details'][$key] = $builder->get()->getResultArray();
- $builder->select('used, earned');
- $builder = $this->db->table('sales_reward_points');
- $builder->where('sale_id', $value['sale_id']);
- $data['rewards'][$key] = $builder->get()->getResultArray();
- }
+ $builder->select('used, earned');
+ $builder = $this->db->table('sales_reward_points');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['rewards'][$key] = $builder->get()->getResultArray();
+ }
- return $data;
- }
+ return $data;
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
- if($inputs['location_id'] != 'all') //TODO: Duplicated code
- {
- $builder->where('item_location', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all') //TODO: Duplicated code
+ {
+ $builder->where('item_location', $inputs['location_id']);
+ }
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Inventory_low.php b/app/Models/Reports/Inventory_low.php
index a5e8e72eb..b204474e9 100644
--- a/app/Models/Reports/Inventory_low.php
+++ b/app/Models/Reports/Inventory_low.php
@@ -12,50 +12,50 @@ use App\Models\Item;
*/
class Inventory_low extends Report
{
- /**
- * @return array[]
- */
- public function getDataColumns(): array
- {
- return [
- ['item_name' => lang('Reports.item_name')],
- ['item_number' => lang('Reports.item_number')],
- ['quantity' => lang('Reports.quantity')],
- ['reorder_level' => lang('Reports.reorder_level')],
- ['location_name' => lang('Reports.stock_location')]
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ ['item_name' => lang('Reports.item_name')],
+ ['item_number' => lang('Reports.item_number')],
+ ['quantity' => lang('Reports.quantity')],
+ ['reorder_level' => lang('Reports.reorder_level')],
+ ['location_name' => lang('Reports.stock_location')]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {//TODO: convert to using QueryBuilder. Use App/Models/Reports/Summary_taxes.php getData() as a reference template
- $item = model(Item::class);
- $query = $this->db->query("SELECT " . $item->get_item_name('name') . ",
- items.item_number,
- item_quantities.quantity,
- items.reorder_level,
- stock_locations.location_name
- FROM " . $this->db->prefixTable('items') . " AS items
- JOIN " . $this->db->prefixTable('item_quantities') . " AS item_quantities ON items.item_id = item_quantities.item_id
- JOIN " . $this->db->prefixTable('stock_locations') . " AS stock_locations ON item_quantities.location_id = stock_locations.location_id
- WHERE items.deleted = 0
- AND items.stock_type = 0
- AND item_quantities.quantity <= items.reorder_level
- AND stock_locations.deleted = 0
- ORDER BY items.name");
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {//TODO: convert to using QueryBuilder. Use App/Models/Reports/Summary_taxes.php getData() as a reference template
+ $item = model(Item::class);
+ $query = $this->db->query("SELECT " . $item->get_item_name('name') . ",
+ items.item_number,
+ item_quantities.quantity,
+ items.reorder_level,
+ stock_locations.location_name
+ FROM " . $this->db->prefixTable('items') . " AS items
+ JOIN " . $this->db->prefixTable('item_quantities') . " AS item_quantities ON items.item_id = item_quantities.item_id
+ JOIN " . $this->db->prefixTable('stock_locations') . " AS stock_locations ON item_quantities.location_id = stock_locations.location_id
+ WHERE items.deleted = 0
+ AND items.stock_type = 0
+ AND item_quantities.quantity <= items.reorder_level
+ AND stock_locations.deleted = 0
+ ORDER BY items.name");
- return $query->getResultArray() ?: [];
- }
+ return $query->getResultArray() ?: [];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- return [];
- }
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ return [];
+ }
}
diff --git a/app/Models/Reports/Inventory_summary.php b/app/Models/Reports/Inventory_summary.php
index 8b1ec0829..76af90d14 100644
--- a/app/Models/Reports/Inventory_summary.php
+++ b/app/Models/Reports/Inventory_summary.php
@@ -12,110 +12,110 @@ use App\Models\Item;
*/
class Inventory_summary extends Report
{
- /**
- * @return array[]
- */
- public function getDataColumns(): array
- {
- return [
- ['item_name' => lang('Reports.item_name')],
- ['item_number' => lang('Reports.item_number')],
- ['category' => lang('Reports.category')],
- ['quantity' => lang('Reports.quantity')],
- ['low_sell_quantity' => lang('Reports.low_sell_quantity')],
- ['reorder_level' => lang('Reports.reorder_level')],
- ['location_name' => lang('Reports.stock_location')],
- ['cost_price' => lang('Reports.cost_price'), 'sorter' => 'number_sorter'],
- ['unit_price' => lang('Reports.unit_price'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.sub_total_value'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ ['item_name' => lang('Reports.item_name')],
+ ['item_number' => lang('Reports.item_number')],
+ ['category' => lang('Reports.category')],
+ ['quantity' => lang('Reports.quantity')],
+ ['low_sell_quantity' => lang('Reports.low_sell_quantity')],
+ ['reorder_level' => lang('Reports.reorder_level')],
+ ['location_name' => lang('Reports.stock_location')],
+ ['cost_price' => lang('Reports.cost_price'), 'sorter' => 'number_sorter'],
+ ['unit_price' => lang('Reports.unit_price'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.sub_total_value'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $item = model(Item::class);
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $item = model(Item::class);
- $builder = $this->db->table('items AS items');
- $builder->select($item->get_item_name('name') . ',
- items.item_number,
- items.category,
- item_quantities.quantity,
- (item_quantities.quantity * items.qty_per_pack) as low_sell_quantity,
- items.reorder_level,
- stock_locations.location_name,
- items.cost_price,
- items.unit_price,
- (items.cost_price * item_quantities.quantity) AS sub_total_value'
- );
- $builder->join('item_quantities AS item_quantities', 'items.item_id = item_quantities.item_id');
- $builder->join('stock_locations AS stock_locations', 'item_quantities.location_id = stock_locations.location_id');
- $builder->where('items.deleted', 0);
- $builder->where('items.stock_type', 0);
- $builder->where('stock_locations.deleted', 0);
+ $builder = $this->db->table('items AS items');
+ $builder->select($item->get_item_name('name') . ',
+ items.item_number,
+ items.category,
+ item_quantities.quantity,
+ (item_quantities.quantity * items.qty_per_pack) as low_sell_quantity,
+ items.reorder_level,
+ stock_locations.location_name,
+ items.cost_price,
+ items.unit_price,
+ (items.cost_price * item_quantities.quantity) AS sub_total_value'
+ );
+ $builder->join('item_quantities AS item_quantities', 'items.item_id = item_quantities.item_id');
+ $builder->join('stock_locations AS stock_locations', 'item_quantities.location_id = stock_locations.location_id');
+ $builder->where('items.deleted', 0);
+ $builder->where('items.stock_type', 0);
+ $builder->where('stock_locations.deleted', 0);
- // should be corresponding to the values Inventory_summary::getItemCountDropdownArray() returns...
- if($inputs['item_count'] == 'zero_and_less')
- {
- $builder->where('item_quantities.quantity <=', 0);
- }
- elseif($inputs['item_count'] == 'more_than_zero')
- {
- $builder->where('item_quantities.quantity >', 0);
- }
+ // should be corresponding to the values Inventory_summary::getItemCountDropdownArray() returns...
+ if($inputs['item_count'] == 'zero_and_less')
+ {
+ $builder->where('item_quantities.quantity <=', 0);
+ }
+ elseif($inputs['item_count'] == 'more_than_zero')
+ {
+ $builder->where('item_quantities.quantity >', 0);
+ }
- if($inputs['location_id'] != 'all')
- {
- $builder->where('stock_locations.location_id', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all')
+ {
+ $builder->where('stock_locations.location_id', $inputs['location_id']);
+ }
$builder->orderBy('items.name');
- $builder->orderBy('items.qty_per_pack');
+ $builder->orderBy('items.qty_per_pack');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
- /**
- * calculates the total value of the given inventory summary by summing all sub_total_values (see Inventory_summary::getData())
- *
- * @param array $inputs expects the reports-data-array which Inventory_summary::getData() returns
- *
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $return = [ //TODO: This variable name should be refactored to reflect what it is... perhaps summary_data
- 'total_inventory_value' => 0,
- 'total_quantity' => 0,
- 'total_low_sell_quantity' => 0,
- 'total_retail' => 0
- ];
+ /**
+ * calculates the total value of the given inventory summary by summing all sub_total_values (see Inventory_summary::getData())
+ *
+ * @param array $inputs expects the reports-data-array which Inventory_summary::getData() returns
+ *
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $return = [ //TODO: This variable name should be refactored to reflect what it is... perhaps summary_data
+ 'total_inventory_value' => 0,
+ 'total_quantity' => 0,
+ 'total_low_sell_quantity' => 0,
+ 'total_retail' => 0
+ ];
- foreach($inputs as $input)
- {
- $return['total_inventory_value'] += $input['sub_total_value'];
- $return['total_quantity'] += $input['quantity'];
- $return['total_low_sell_quantity'] += $input['low_sell_quantity'];
- $return['total_retail'] += $input['unit_price'] * $input['quantity'];
- }
+ foreach($inputs as $input)
+ {
+ $return['total_inventory_value'] += $input['sub_total_value'];
+ $return['total_quantity'] += $input['quantity'];
+ $return['total_low_sell_quantity'] += $input['low_sell_quantity'];
+ $return['total_retail'] += $input['unit_price'] * $input['quantity'];
+ }
- return $return;
- }
+ return $return;
+ }
- /**
- * returns the array for the dropdown-element item-count in the form for the inventory summary-report
- *
- * @return array
- */
- public function getItemCountDropdownArray(): array
- {
- return [
- 'all' => lang('Reports.all'),
- 'zero_and_less' => lang('Reports.zero_and_less'),
- 'more_than_zero' => lang('Reports.more_than_zero')
- ];
- }
+ /**
+ * returns the array for the dropdown-element item-count in the form for the inventory summary-report
+ *
+ * @return array
+ */
+ public function getItemCountDropdownArray(): array
+ {
+ return [
+ 'all' => lang('Reports.all'),
+ 'zero_and_less' => lang('Reports.zero_and_less'),
+ 'more_than_zero' => lang('Reports.more_than_zero')
+ ];
+ }
}
diff --git a/app/Models/Reports/Report.php b/app/Models/Reports/Report.php
index 683f5f333..dc17acc3c 100644
--- a/app/Models/Reports/Report.php
+++ b/app/Models/Reports/Report.php
@@ -13,23 +13,23 @@ use CodeIgniter\Model;
*/
abstract class Report extends Model
{
- public function __construct()
- {
- parent::__construct();
- }
+ public function __construct()
+ {
+ parent::__construct();
+ }
- /**
- * Returns the column names used for the report
- */
- public abstract function getDataColumns(): array;
+ /**
+ * Returns the column names used for the report
+ */
+ public abstract function getDataColumns(): array;
- /**
- * Returns all the data to be populated into the report
- */
- public abstract function getData(array $inputs): array;
+ /**
+ * Returns all the data to be populated into the report
+ */
+ public abstract function getData(array $inputs): array;
- /**
- * Returns key=>value pairing of summary data for the report
- */
- public abstract function getSummaryData(array $inputs): array;
+ /**
+ * Returns key=>value pairing of summary data for the report
+ */
+ public abstract function getSummaryData(array $inputs): array;
}
diff --git a/app/Models/Reports/Specific_customer.php b/app/Models/Reports/Specific_customer.php
index 14dbdfd1a..09e5f7b4b 100644
--- a/app/Models/Reports/Specific_customer.php
+++ b/app/Models/Reports/Specific_customer.php
@@ -12,220 +12,220 @@ use App\Models\Sale;
*/
class Specific_customer extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $sale = model(Sale::class);
- $sale->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $sale = model(Sale::class);
+ $sale->create_temp_table($inputs);
+ }
- /**
- * @return array
- */
- public function getDataColumns(): array
- {
- return [
- 'summary' => [
- ['id' => lang('Reports.sale_id')],
- ['type_code' => lang('Reports.code_type')],
- ['sale_time' => lang('Reports.date'), 'sortable' => false],
- ['quantity' => lang('Reports.quantity')],
- ['employee_name' => lang('Reports.sold_by')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
- ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
- ['comment' => lang('Reports.comments')]
- ],
- 'details' => [
- lang('Reports.name'),
- lang('Reports.category'),
- lang('Reports.item_number'),
- lang('Reports.description'),
- lang('Reports.quantity'),
- lang('Reports.subtotal'),
- lang('Reports.tax'),
- lang('Reports.total'),
- lang('Reports.cost'),
- lang('Reports.profit'),
- lang('Reports.discount')
- ],
- 'details_rewards' => [
- lang('Reports.used'),
- lang('Reports.earned')
- ]
- ];
- }
+ /**
+ * @return array
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ 'summary' => [
+ ['id' => lang('Reports.sale_id')],
+ ['type_code' => lang('Reports.code_type')],
+ ['sale_time' => lang('Reports.date'), 'sortable' => false],
+ ['quantity' => lang('Reports.quantity')],
+ ['employee_name' => lang('Reports.sold_by')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
+ ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
+ ['comment' => lang('Reports.comments')]
+ ],
+ 'details' => [
+ lang('Reports.name'),
+ lang('Reports.category'),
+ lang('Reports.item_number'),
+ lang('Reports.description'),
+ lang('Reports.quantity'),
+ lang('Reports.subtotal'),
+ lang('Reports.tax'),
+ lang('Reports.total'),
+ lang('Reports.cost'),
+ lang('Reports.profit'),
+ lang('Reports.discount')
+ ],
+ 'details_rewards' => [
+ lang('Reports.used'),
+ lang('Reports.earned')
+ ]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('
- sale_id,
- MAX(CASE
- WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
- WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
- WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
- WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
- WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
- WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
- ELSE \'\'
- END) AS type_code,
- MAX(sale_status) as sale_status,
- MAX(sale_time) AS sale_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(employee_name) AS employee_name,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(comment) AS comment');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('
+ sale_id,
+ MAX(CASE
+ WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
+ WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
+ WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
+ WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
+ WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
+ WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
+ ELSE \'\'
+ END) AS type_code,
+ MAX(sale_status) as sale_status,
+ MAX(sale_time) AS sale_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(employee_name) AS employee_name,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(comment) AS comment');
- $builder->where('customer_id', $inputs['customer_id']); //TODO: Duplicated code
+ $builder->where('customer_id', $inputs['customer_id']); //TODO: Duplicated code
- if($inputs['payment_type'] == 'invoices')
- {
- $builder->where('sale_type', SALE_TYPE_INVOICE);
- }
- elseif($inputs['payment_type'] != 'all')
- {
- $builder->like('payment_type', lang('Sales.' . $inputs['payment_type']));
- }
+ if($inputs['payment_type'] == 'invoices')
+ {
+ $builder->where('sale_type', SALE_TYPE_INVOICE);
+ }
+ elseif($inputs['payment_type'] != 'all')
+ {
+ $builder->like('payment_type', lang('Sales.' . $inputs['payment_type']));
+ }
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- $builder->groupBy('sale_id'); //TODO: Duplicated code
- $builder->orderBy('MAX(sale_time)');
+ $builder->groupBy('sale_id'); //TODO: Duplicated code
+ $builder->orderBy('MAX(sale_time)');
- $data = [];
- $data['summary'] = $builder->get()->getResultArray();
- $data['details'] = [];
- $data['rewards'] = [];
+ $data = [];
+ $data['summary'] = $builder->get()->getResultArray();
+ $data['details'] = [];
+ $data['rewards'] = [];
- foreach($data['summary'] as $key => $value)
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
- $builder->where('sale_id', $value['sale_id']);
- $data['details'][$key] = $builder->get()->getResultArray();
+ foreach($data['summary'] as $key => $value)
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['details'][$key] = $builder->get()->getResultArray();
- $builder = $this->db->table('sales_reward_points');
- $builder->select('used, earned');
- $builder->where('sale_id', $value['sale_id']);
- $data['rewards'][$key] = $builder->get()->getResultArray();
- }
+ $builder = $this->db->table('sales_reward_points');
+ $builder->select('used, earned');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['rewards'][$key] = $builder->get()->getResultArray();
+ }
- return $data;
- }
+ return $data;
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
- $builder->where('customer_id', $inputs['customer_id']); //TODO: Duplicate code
+ $builder->where('customer_id', $inputs['customer_id']); //TODO: Duplicate code
- if($inputs['payment_type'] == 'invoices')
- {
- $builder->where('sale_type', SALE_TYPE_INVOICE);
- }
- elseif ($inputs['payment_type'] != 'all')
- {
- $builder->like('payment_type', lang('Sales.'.$inputs['payment_type']));
- }
+ if($inputs['payment_type'] == 'invoices')
+ {
+ $builder->where('sale_type', SALE_TYPE_INVOICE);
+ }
+ elseif ($inputs['payment_type'] != 'all')
+ {
+ $builder->like('payment_type', lang('Sales.'.$inputs['payment_type']));
+ }
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Specific_discount.php b/app/Models/Reports/Specific_discount.php
index eef71bd4f..2859dcbb2 100644
--- a/app/Models/Reports/Specific_discount.php
+++ b/app/Models/Reports/Specific_discount.php
@@ -12,205 +12,205 @@ use App\Models\Sale;
*/
class Specific_discount extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $sale = model(Sale::class);
- $sale->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $sale = model(Sale::class);
+ $sale->create_temp_table($inputs);
+ }
- /**
- * @return array
- */
- public function getDataColumns(): array
- { //TODO: Duplicated code
- return [
- 'summary' => [
- ['id' => lang('Reports.sale_id')],
- ['type_code' => lang('Reports.code_type')],
- ['sale_time' => lang('Reports.date'), 'sortable' => false],
- ['quantity' => lang('Reports.quantity')],
- ['employee_name' => lang('Reports.sold_by')],
- ['customer_name' => lang('Reports.sold_to')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
- ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
- ['comment' => lang('Reports.comments')]
- ],
- 'details' => [
- lang('Reports.name'),
- lang('Reports.category'),
- lang('Reports.item_number'),
- lang('Reports.description'),
- lang('Reports.quantity'),
- lang('Reports.subtotal'),
- lang('Reports.tax'),
- lang('Reports.total'),
- lang('Reports.cost'),
- lang('Reports.profit'),
- lang('Reports.discount')
- ],
- 'details_rewards' => [
- lang('Reports.used'),
- lang('Reports.earned')
- ]
- ];
- }
+ /**
+ * @return array
+ */
+ public function getDataColumns(): array
+ { //TODO: Duplicated code
+ return [
+ 'summary' => [
+ ['id' => lang('Reports.sale_id')],
+ ['type_code' => lang('Reports.code_type')],
+ ['sale_time' => lang('Reports.date'), 'sortable' => false],
+ ['quantity' => lang('Reports.quantity')],
+ ['employee_name' => lang('Reports.sold_by')],
+ ['customer_name' => lang('Reports.sold_to')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
+ ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
+ ['comment' => lang('Reports.comments')]
+ ],
+ 'details' => [
+ lang('Reports.name'),
+ lang('Reports.category'),
+ lang('Reports.item_number'),
+ lang('Reports.description'),
+ lang('Reports.quantity'),
+ lang('Reports.subtotal'),
+ lang('Reports.tax'),
+ lang('Reports.total'),
+ lang('Reports.cost'),
+ lang('Reports.profit'),
+ lang('Reports.discount')
+ ],
+ 'details_rewards' => [
+ lang('Reports.used'),
+ lang('Reports.earned')
+ ]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('
- sale_id,
- MAX(CASE
- WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
- WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
- WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
- WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
- WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
- WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
- ELSE \'\'
- END) AS type_code,
- MAX(sale_status) as sale_status,
- MAX(sale_time) AS sale_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(employee_name) AS employee_name,
- MAX(customer_name) AS customer_name,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(comment) AS comment');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('
+ sale_id,
+ MAX(CASE
+ WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
+ WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
+ WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
+ WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
+ WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
+ WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
+ ELSE \'\'
+ END) AS type_code,
+ MAX(sale_status) as sale_status,
+ MAX(sale_time) AS sale_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(employee_name) AS employee_name,
+ MAX(customer_name) AS customer_name,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(comment) AS comment');
- $builder->where('discount >=', $inputs['discount']); //TODO: Duplicated code
- $builder->where('discount_type', $inputs['discount_type']);
+ $builder->where('discount >=', $inputs['discount']); //TODO: Duplicated code
+ $builder->where('discount_type', $inputs['discount_type']);
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- $builder->groupBy('sale_id'); //TODO: Duplicated code
- $builder->orderBy('MAX(sale_time)');
+ $builder->groupBy('sale_id'); //TODO: Duplicated code
+ $builder->orderBy('MAX(sale_time)');
- $data = [];
- $data['summary'] = $builder->get()->getResultArray();
- $data['details'] = [];
- $data['rewards'] = [];
+ $data = [];
+ $data['summary'] = $builder->get()->getResultArray();
+ $data['details'] = [];
+ $data['rewards'] = [];
- foreach($data['summary'] as $key => $value)
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
- $builder->where('sale_id', $value['sale_id']);
- $data['details'][$key] = $builder->get()->getResultArray();
+ foreach($data['summary'] as $key => $value)
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['details'][$key] = $builder->get()->getResultArray();
- $builder = $this->db->table('sales_reward_points');
- $builder->select('used, earned');
- $builder->where('sale_id', $value['sale_id']);
- $data['rewards'][$key] = $builder->get()->getResultArray();
- }
+ $builder = $this->db->table('sales_reward_points');
+ $builder->select('used, earned');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['rewards'][$key] = $builder->get()->getResultArray();
+ }
- return $data;
- }
+ return $data;
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
- $builder->where('discount >=', $inputs['discount']); //TODO: Duplicated code
- $builder->where('discount_type', $inputs['discount_type']);
+ $builder->where('discount >=', $inputs['discount']); //TODO: Duplicated code
+ $builder->where('discount_type', $inputs['discount_type']);
- //TODO: this needs to be converted to a switch statement
- if($inputs['sale_type'] == 'complete')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'sales')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'quotes')
- {
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- }
- elseif($inputs['sale_type'] == 'work_orders')
- {
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- }
- elseif($inputs['sale_type'] == 'canceled')
- {
- $builder->where('sale_status', CANCELED);
- }
- elseif($inputs['sale_type'] == 'returns')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- }
+ //TODO: this needs to be converted to a switch statement
+ if($inputs['sale_type'] == 'complete')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'sales')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'quotes')
+ {
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ }
+ elseif($inputs['sale_type'] == 'work_orders')
+ {
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ }
+ elseif($inputs['sale_type'] == 'canceled')
+ {
+ $builder->where('sale_status', CANCELED);
+ }
+ elseif($inputs['sale_type'] == 'returns')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Specific_employee.php b/app/Models/Reports/Specific_employee.php
index b0667d60f..98edc1866 100644
--- a/app/Models/Reports/Specific_employee.php
+++ b/app/Models/Reports/Specific_employee.php
@@ -12,200 +12,200 @@ use App\Models\Sale;
*/
class Specific_employee extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $sale = model(Sale::class);
- $sale->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $sale = model(Sale::class);
+ $sale->create_temp_table($inputs);
+ }
- /**
- * @return array
- */
- public function getDataColumns(): array
- {
- return [
- 'summary' => [
- ['id' => lang('Reports.sale_id')],
- ['type_code' => lang('Reports.code_type')],
- ['sale_time' => lang('Reports.date'), 'sortable' => false],
- ['quantity' => lang('Reports.quantity')],
- ['customer_name' => lang('Reports.sold_to')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
- ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
- ['comment' => lang('Reports.comments')]
- ],
- 'details' => [
- lang('Reports.name'),
- lang('Reports.category'),
- lang('Reports.item_number'),
- lang('Reports.description'),
- lang('Reports.quantity'),
- lang('Reports.subtotal'),
- lang('Reports.tax'),
- lang('Reports.total'),
- lang('Reports.cost'),
- lang('Reports.profit'),
- lang('Reports.discount')
- ],
- 'details_rewards' => [
- lang('Reports.used'),
- lang('Reports.earned')
- ]
- ];
- }
+ /**
+ * @return array
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ 'summary' => [
+ ['id' => lang('Reports.sale_id')],
+ ['type_code' => lang('Reports.code_type')],
+ ['sale_time' => lang('Reports.date'), 'sortable' => false],
+ ['quantity' => lang('Reports.quantity')],
+ ['customer_name' => lang('Reports.sold_to')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
+ ['payment_type' => lang('Reports.payment_type'), 'sortable' => false],
+ ['comment' => lang('Reports.comments')]
+ ],
+ 'details' => [
+ lang('Reports.name'),
+ lang('Reports.category'),
+ lang('Reports.item_number'),
+ lang('Reports.description'),
+ lang('Reports.quantity'),
+ lang('Reports.subtotal'),
+ lang('Reports.tax'),
+ lang('Reports.total'),
+ lang('Reports.cost'),
+ lang('Reports.profit'),
+ lang('Reports.discount')
+ ],
+ 'details_rewards' => [
+ lang('Reports.used'),
+ lang('Reports.earned')
+ ]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('
- sale_id,
- MAX(CASE
- WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
- WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
- WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
- WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
- WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
- WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
- ELSE \'\'
- END) AS type_code,
- MAX(sale_status) as sale_status,
- MAX(sale_time) AS sale_time,
- SUM(quantity_purchased) AS items_purchased,
- MAX(customer_name) AS customer_name,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(payment_type) AS payment_type,
- MAX(comment) AS comment');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('
+ sale_id,
+ MAX(CASE
+ WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
+ WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
+ WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
+ WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
+ WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
+ WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
+ ELSE \'\'
+ END) AS type_code,
+ MAX(sale_status) as sale_status,
+ MAX(sale_time) AS sale_time,
+ SUM(quantity_purchased) AS items_purchased,
+ MAX(customer_name) AS customer_name,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(payment_type) AS payment_type,
+ MAX(comment) AS comment');
- $builder->where('employee_id', $inputs['employee_id']); //TODO: Duplicated code
+ $builder->where('employee_id', $inputs['employee_id']); //TODO: Duplicated code
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- $builder->groupBy('sale_id');
- $builder->orderBy('MAX(sale_time)');
+ $builder->groupBy('sale_id');
+ $builder->orderBy('MAX(sale_time)');
- $data = [];
- $data['summary'] = $builder->get()->getResultArray();
- $data['details'] = [];
- $data['rewards'] = [];
+ $data = [];
+ $data['summary'] = $builder->get()->getResultArray();
+ $data['details'] = [];
+ $data['rewards'] = [];
- foreach($data['summary'] as $key => $value)
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
- $builder->where('sale_id', $value['sale_id']);
- $data['details'][$key] = $builder->get()->getResultArray();
+ foreach($data['summary'] as $key => $value)
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('name, category, item_number, description, quantity_purchased, subtotal, tax, total, cost, profit, discount, discount_type');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['details'][$key] = $builder->get()->getResultArray();
- $builder = $this->db->table('sales_reward_points');
- $builder->select('used, earned');
- $builder->where('sale_id', $value['sale_id']);
- $data['rewards'][$key] = $builder->get()->getResultArray();
- }
+ $builder = $this->db->table('sales_reward_points');
+ $builder->select('used, earned');
+ $builder->where('sale_id', $value['sale_id']);
+ $data['rewards'][$key] = $builder->get()->getResultArray();
+ }
- return $data;
- }
+ return $data;
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
- $builder->where('employee_id', $inputs['employee_id']); //TODO: Duplicated code
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
+ $builder->where('employee_id', $inputs['employee_id']); //TODO: Duplicated code
- //TODO: this needs to be converted to a switch statement
- if($inputs['sale_type'] == 'complete')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'sales')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'quotes')
- {
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- }
- elseif($inputs['sale_type'] == 'work_orders')
- {
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- }
- elseif($inputs['sale_type'] == 'canceled')
- {
- $builder->where('sale_status', CANCELED);
- }
- elseif($inputs['sale_type'] == 'returns')
- {
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- }
+ //TODO: this needs to be converted to a switch statement
+ if($inputs['sale_type'] == 'complete')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'sales')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'quotes')
+ {
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ }
+ elseif($inputs['sale_type'] == 'work_orders')
+ {
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ }
+ elseif($inputs['sale_type'] == 'canceled')
+ {
+ $builder->where('sale_status', CANCELED);
+ }
+ elseif($inputs['sale_type'] == 'returns')
+ {
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Specific_supplier.php b/app/Models/Reports/Specific_supplier.php
index dee4ab45b..25bca87eb 100644
--- a/app/Models/Reports/Specific_supplier.php
+++ b/app/Models/Reports/Specific_supplier.php
@@ -12,167 +12,167 @@ use App\Models\Sale;
*/
class Specific_supplier extends Report
{
- /**
- * @param array $inputs
- * @return void
- */
- public function create(array $inputs): void
- {
- //Create our temp tables to work with the data in our report
- $sale = model(Sale::class);
- $sale->create_temp_table($inputs);
- }
+ /**
+ * @param array $inputs
+ * @return void
+ */
+ public function create(array $inputs): void
+ {
+ //Create our temp tables to work with the data in our report
+ $sale = model(Sale::class);
+ $sale->create_temp_table($inputs);
+ }
- /**
- * @return array[]
- */
- public function getDataColumns(): array
- {
- return [
- ['id' => lang('Reports.sale_id')],
- ['type_code' => lang('Reports.code_type')],
- ['sale_time' => lang('Reports.date'), 'sortable' => false],
- ['name' => lang('Reports.name')],
- ['category' => lang('Reports.category')],
- ['item_number' => lang('Reports.item_number')],
- ['quantity' => lang('Reports.quantity')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
- ['discount' => lang('Reports.discount')]
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function getDataColumns(): array
+ {
+ return [
+ ['id' => lang('Reports.sale_id')],
+ ['type_code' => lang('Reports.code_type')],
+ ['sale_time' => lang('Reports.date'), 'sortable' => false],
+ ['name' => lang('Reports.name')],
+ ['category' => lang('Reports.category')],
+ ['item_number' => lang('Reports.item_number')],
+ ['quantity' => lang('Reports.quantity')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter'],
+ ['discount' => lang('Reports.discount')]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('
- sale_id,
- MAX(CASE
- WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
- WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
- WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
- WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
- WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
- WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
- ELSE \'\'
- END) AS type_code,
- MAX(sale_status) as sale_status,
- MAX(sale_time) AS sale_time,
- MAX(name) AS name,
- MAX(category) AS category,
- MAX(item_number) AS item_number,
- SUM(quantity_purchased) AS items_purchased,
- SUM(subtotal) AS subtotal,
- SUM(tax) AS tax,
- SUM(total) AS total,
- SUM(cost) AS cost,
- SUM(profit) AS profit,
- MAX(discount_type) AS discount_type,
- MAX(discount) AS discount');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('
+ sale_id,
+ MAX(CASE
+ WHEN sale_type = ' . SALE_TYPE_POS . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_pos') . '\'
+ WHEN sale_type = ' . SALE_TYPE_INVOICE . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_invoice') . '\'
+ WHEN sale_type = ' . SALE_TYPE_WORK_ORDER . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_work_order') . '\'
+ WHEN sale_type = ' . SALE_TYPE_QUOTE . ' && sale_status = ' . SUSPENDED . ' THEN \'' . lang('Reports.code_quote') . '\'
+ WHEN sale_type = ' . SALE_TYPE_RETURN . ' && sale_status = ' . COMPLETED . ' THEN \'' . lang('Reports.code_return') . '\'
+ WHEN sale_status = ' . CANCELED . ' THEN \'' . lang('Reports.code_canceled') . '\'
+ ELSE \'\'
+ END) AS type_code,
+ MAX(sale_status) as sale_status,
+ MAX(sale_time) AS sale_time,
+ MAX(name) AS name,
+ MAX(category) AS category,
+ MAX(item_number) AS item_number,
+ SUM(quantity_purchased) AS items_purchased,
+ SUM(subtotal) AS subtotal,
+ SUM(tax) AS tax,
+ SUM(total) AS total,
+ SUM(cost) AS cost,
+ SUM(profit) AS profit,
+ MAX(discount_type) AS discount_type,
+ MAX(discount) AS discount');
- $builder->where('supplier_id', $inputs['supplier_id']); //TODO: Duplicated code
+ $builder->where('supplier_id', $inputs['supplier_id']); //TODO: Duplicated code
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- $builder->groupBy(['item_id', 'sale_id']);
- $builder->orderBy('MAX(sale_time)');
+ $builder->groupBy(['item_id', 'sale_id']);
+ $builder->orderBy('MAX(sale_time)');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items_temp');
- $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
- $builder->where('supplier_id', $inputs['supplier_id']);
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items_temp');
+ $builder->select('SUM(subtotal) AS subtotal, SUM(tax) AS tax, SUM(total) AS total, SUM(cost) AS cost, SUM(profit) AS profit');
+ $builder->where('supplier_id', $inputs['supplier_id']);
- switch($inputs['sale_type'])
- {
- case 'complete':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- break;
+ switch($inputs['sale_type'])
+ {
+ case 'complete':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ break;
- case 'sales':
- $builder->where('sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sale_type', SALE_TYPE_POS);
- $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- break;
+ case 'sales':
+ $builder->where('sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ break;
- case 'quotes':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_QUOTE);
- break;
+ case 'quotes':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_QUOTE);
+ break;
- case 'work_orders':
- $builder->where('sale_status', SUSPENDED);
- $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
- break;
+ case 'work_orders':
+ $builder->where('sale_status', SUSPENDED);
+ $builder->where('sale_type', SALE_TYPE_WORK_ORDER);
+ break;
- case 'canceled':
- $builder->where('sale_status', CANCELED);
- break;
+ case 'canceled':
+ $builder->where('sale_status', CANCELED);
+ break;
- case 'returns':
- $builder->where('sale_status', COMPLETED);
- $builder->where('sale_type', SALE_TYPE_RETURN);
- break;
- }
+ case 'returns':
+ $builder->where('sale_status', COMPLETED);
+ $builder->where('sale_type', SALE_TYPE_RETURN);
+ break;
+ }
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Summary_categories.php b/app/Models/Reports/Summary_categories.php
index 2ef185f1a..4ebec7b97 100644
--- a/app/Models/Reports/Summary_categories.php
+++ b/app/Models/Reports/Summary_categories.php
@@ -4,55 +4,55 @@ namespace App\Models\Reports;
class Summary_categories extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['category' => lang('Reports.category')],
- ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['category' => lang('Reports.category')],
+ ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param $builder
- * @return void
- */
- protected function _select(array $inputs, &$builder): void //TODO: Hungarian notation
- {
- parent::_select($inputs, $builder); //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param $builder
+ * @return void
+ */
+ protected function _select(array $inputs, &$builder): void //TODO: Hungarian notation
+ {
+ parent::_select($inputs, $builder); //TODO: hungarian notation
- $builder->select('
- items.category AS category,
- SUM(sales_items.quantity_purchased) AS quantity_purchased
- ');
- }
+ $builder->select('
+ items.category AS category,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased
+ ');
+ }
- /**
- * @param $builder
- * @return void
- */
- protected function _from(&$builder): void //TODO: hungarian notation
- {
- parent::_from($builder);
+ /**
+ * @param $builder
+ * @return void
+ */
+ protected function _from(&$builder): void //TODO: hungarian notation
+ {
+ parent::_from($builder);
- $builder->join('items AS items', 'sales_items.item_id = items.item_id', 'inner');
- }
+ $builder->join('items AS items', 'sales_items.item_id = items.item_id', 'inner');
+ }
- /**
- * @param $builder
- * @return void
- */
- protected function _group_order(&$builder): void //TODO: hungarian notation
- {
- $builder->groupBy('category');
- $builder->orderBy('category');
- }
+ /**
+ * @param $builder
+ * @return void
+ */
+ protected function _group_order(&$builder): void //TODO: hungarian notation
+ {
+ $builder->groupBy('category');
+ $builder->orderBy('category');
+ }
}
diff --git a/app/Models/Reports/Summary_customers.php b/app/Models/Reports/Summary_customers.php
index e12b073ea..7c0d61b83 100644
--- a/app/Models/Reports/Summary_customers.php
+++ b/app/Models/Reports/Summary_customers.php
@@ -4,57 +4,57 @@ namespace App\Models\Reports;
class Summary_customers extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['customer_name' => lang('Reports.customer')],
- ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
- ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['customer_name' => lang('Reports.customer')],
+ ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
+ ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _select(array $inputs, object &$builder): void //TODO: Hungarian notation
- {
- parent::_select($inputs, $builder); //TODO: Hungarian notation
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _select(array $inputs, object &$builder): void //TODO: Hungarian notation
+ {
+ parent::_select($inputs, $builder); //TODO: Hungarian notation
- $builder->select('
- MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer,
- SUM(sales_items.quantity_purchased) AS quantity_purchased,
- COUNT(DISTINCT sales.sale_id) AS sales
- ');
- }
+ $builder->select('
+ MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased,
+ COUNT(DISTINCT sales.sale_id) AS sales
+ ');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _from(object &$builder): void //TODO: Hungarian notation
- {
- parent::_from($builder); //TODO: Hungarian notation
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _from(object &$builder): void //TODO: Hungarian notation
+ {
+ parent::_from($builder); //TODO: Hungarian notation
- $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id');
- }
+ $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _group_order(object &$builder): void //TODO: Hungarian notation
- {
- $builder->groupBy('sales.customer_id');
- $builder->orderBy('customer_p.last_name');
- }
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _group_order(object &$builder): void //TODO: Hungarian notation
+ {
+ $builder->groupBy('sales.customer_id');
+ $builder->orderBy('customer_p.last_name');
+ }
}
diff --git a/app/Models/Reports/Summary_discounts.php b/app/Models/Reports/Summary_discounts.php
index f595c4d45..5e3f1c0d7 100644
--- a/app/Models/Reports/Summary_discounts.php
+++ b/app/Models/Reports/Summary_discounts.php
@@ -6,46 +6,46 @@ use Config\OSPOS;
class Summary_discounts extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['discount' => lang('Reports.discount'), 'sorter' => 'number_sorter'],
- ['count' => lang('Reports.count')],
- ['total' => lang('Reports.total')]
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['discount' => lang('Reports.discount'), 'sorter' => 'number_sorter'],
+ ['count' => lang('Reports.count')],
+ ['total' => lang('Reports.total')]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('sales_items AS sales_items');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $config = config(OSPOS::class)->settings;
+ $builder = $this->db->table('sales_items AS sales_items');
- if($inputs['discount_type'] == FIXED)
- {
- $builder->select('SUM(sales_items.discount) AS total, MAX(CONCAT("' . $config['currency_symbol'] . '",sales_items.discount)) AS discount, count(*) AS count');
- $builder->where('discount_type', FIXED);
- }
- elseif($inputs['discount_type'] == PERCENT) //TODO: === ?
- {
- $builder->select('SUM(item_unit_price) * sales_items.discount / 100.0 AS total, MAX(CONCAT(sales_items.discount, "%")) AS discount, count(*) AS count');
- $builder->where('discount_type', PERCENT);
- }
+ if($inputs['discount_type'] == FIXED)
+ {
+ $builder->select('SUM(sales_items.discount) AS total, MAX(CONCAT("' . $config['currency_symbol'] . '",sales_items.discount)) AS discount, count(*) AS count');
+ $builder->where('discount_type', FIXED);
+ }
+ elseif($inputs['discount_type'] == PERCENT) //TODO: === ?
+ {
+ $builder->select('SUM(item_unit_price) * sales_items.discount / 100.0 AS total, MAX(CONCAT(sales_items.discount, "%")) AS discount, count(*) AS count');
+ $builder->where('discount_type', PERCENT);
+ }
- $builder->where('discount >', 0);
- $builder->groupBy('sales_items.discount');
- $builder->orderBy('sales_items.discount');
+ $builder->where('discount >', 0);
+ $builder->groupBy('sales_items.discount');
+ $builder->orderBy('sales_items.discount');
- $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
+ $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
- $this->_where($inputs, $builder); //TODO: Hungarian notation
+ $this->_where($inputs, $builder); //TODO: Hungarian notation
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
}
diff --git a/app/Models/Reports/Summary_employees.php b/app/Models/Reports/Summary_employees.php
index f4477b3fe..897838ae4 100644
--- a/app/Models/Reports/Summary_employees.php
+++ b/app/Models/Reports/Summary_employees.php
@@ -4,57 +4,57 @@ namespace App\Models\Reports;
class Summary_employees extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['employee_name' => lang('Reports.employee')],
- ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
- ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['employee_name' => lang('Reports.employee')],
+ ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
+ ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
- {
- parent::_select($inputs, $builder);
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
+ {
+ parent::_select($inputs, $builder);
- $builder->select('
- MAX(CONCAT(employee_p.first_name, " ", employee_p.last_name)) AS employee,
- SUM(sales_items.quantity_purchased) AS quantity_purchased,
- COUNT(DISTINCT sales.sale_id) AS sales
- ');
- }
+ $builder->select('
+ MAX(CONCAT(employee_p.first_name, " ", employee_p.last_name)) AS employee,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased,
+ COUNT(DISTINCT sales.sale_id) AS sales
+ ');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _from(object &$builder): void //TODO: hungarian notation
- {
- parent::_from($builder);
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _from(object &$builder): void //TODO: hungarian notation
+ {
+ parent::_from($builder);
- $builder->join('people AS employee_p', 'sales.employee_id = employee_p.person_id');
- }
+ $builder->join('people AS employee_p', 'sales.employee_id = employee_p.person_id');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _group_order(object &$builder): void //TODO: hungarian notation
- {
- $builder->groupBy('sales.employee_id');
- $builder->orderBy('employee_p.last_name');
- }
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _group_order(object &$builder): void //TODO: hungarian notation
+ {
+ $builder->groupBy('sales.employee_id');
+ $builder->orderBy('employee_p.last_name');
+ }
}
diff --git a/app/Models/Reports/Summary_expenses_categories.php b/app/Models/Reports/Summary_expenses_categories.php
index a078e2110..573ca95a0 100644
--- a/app/Models/Reports/Summary_expenses_categories.php
+++ b/app/Models/Reports/Summary_expenses_categories.php
@@ -6,71 +6,71 @@ use Config\OSPOS;
class Summary_expenses_categories extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['category_name' => lang('Reports.expenses_category')],
- ['count' => lang('Reports.count')],
- ['total_amount' => lang('Reports.expenses_amount'), 'sorter' => 'number_sorter'],
- ['total_tax_amount' => lang('Reports.expenses_tax_amount'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['category_name' => lang('Reports.expenses_category')],
+ ['count' => lang('Reports.count')],
+ ['total_amount' => lang('Reports.expenses_amount'), 'sorter' => 'number_sorter'],
+ ['total_tax_amount' => lang('Reports.expenses_tax_amount'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('expenses AS expenses');
- $builder->select('expense_categories.category_name AS category_name, COUNT(expenses.expense_id) AS count, SUM(expenses.amount) AS total_amount, SUM(expenses.tax_amount) AS total_tax_amount');
- $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
+ $builder = $this->db->table('expenses AS expenses');
+ $builder->select('expense_categories.category_name AS category_name, COUNT(expenses.expense_id) AS count, SUM(expenses.amount) AS total_amount, SUM(expenses.tax_amount) AS total_tax_amount');
+ $builder->join('expense_categories AS expense_categories', 'expense_categories.expense_category_id = expenses.expense_category_id', 'LEFT');
- //TODO: convert this to ternary notation
- if(empty($config['date_or_time_format'])) //TODO: Duplicated code
- {
- $builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
+ //TODO: convert this to ternary notation
+ if(empty($config['date_or_time_format'])) //TODO: Duplicated code
+ {
+ $builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
- $builder->where('expenses.deleted', 0);
+ $builder->where('expenses.deleted', 0);
- $builder->groupBy('expense_categories.category_name');
- $builder->orderBy('expense_categories.category_name');
+ $builder->groupBy('expense_categories.category_name');
+ $builder->orderBy('expense_categories.category_name');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $config = config(OSPOS::class)->settings;
- $builder = $this->db->table('expenses AS expenses');
- $builder->select('SUM(expenses.amount) AS expenses_total_amount, SUM(expenses.tax_amount) AS expenses_total_tax_amount');
+ $builder = $this->db->table('expenses AS expenses');
+ $builder->select('SUM(expenses.amount) AS expenses_total_amount, SUM(expenses.tax_amount) AS expenses_total_tax_amount');
- if(empty($config['date_or_time_format'])) //TODO: Duplicated code
- {
- $builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
+ if(empty($config['date_or_time_format'])) //TODO: Duplicated code
+ {
+ $builder->where('DATE(expenses.date) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $builder->where('expenses.date BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
- $builder->where('expenses.deleted', 0);
+ $builder->where('expenses.deleted', 0);
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Summary_items.php b/app/Models/Reports/Summary_items.php
index a975a59fd..92c5b202f 100644
--- a/app/Models/Reports/Summary_items.php
+++ b/app/Models/Reports/Summary_items.php
@@ -4,61 +4,61 @@ namespace App\Models\Reports;
class Summary_items extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['item_name' => lang('Reports.item')],
- ['category' => lang('Reports.category')],
- ['cost_price' => lang('Reports.cost_price'), 'sorter' => 'number_sorter'],
- ['unit_price' => lang('Reports.unit_price'), 'sorter' => 'number_sorter'],
- ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['item_name' => lang('Reports.item')],
+ ['category' => lang('Reports.category')],
+ ['cost_price' => lang('Reports.cost_price'), 'sorter' => 'number_sorter'],
+ ['unit_price' => lang('Reports.unit_price'), 'sorter' => 'number_sorter'],
+ ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
- {
- parent::_select($inputs, $builder); //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
+ {
+ parent::_select($inputs, $builder); //TODO: hungarian notation
- $builder->select('
- MAX(items.name) AS name,
- MAX(items.category) AS category,
- MAX(items.cost_price) AS cost_price,
- MAX(items.unit_price) AS unit_price,
- SUM(sales_items.quantity_purchased) AS quantity_purchased
- ');
- }
+ $builder->select('
+ MAX(items.name) AS name,
+ MAX(items.category) AS category,
+ MAX(items.cost_price) AS cost_price,
+ MAX(items.unit_price) AS unit_price,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased
+ ');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _from(object &$builder): void //TODO: hungarian notation
- {
- parent::_from($builder);
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _from(object &$builder): void //TODO: hungarian notation
+ {
+ parent::_from($builder);
- $builder->join('items AS items', 'sales_items.item_id = items.item_id', 'inner');
- }
+ $builder->join('items AS items', 'sales_items.item_id = items.item_id', 'inner');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _group_order(object &$builder): void //TODO: hungarian notation
- {
- $builder->groupBy('items.item_id');
- $builder->orderBy('name');
- }
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _group_order(object &$builder): void //TODO: hungarian notation
+ {
+ $builder->groupBy('items.item_id');
+ $builder->orderBy('name');
+ }
}
diff --git a/app/Models/Reports/Summary_payments.php b/app/Models/Reports/Summary_payments.php
index aef2be78e..8148e6718 100644
--- a/app/Models/Reports/Summary_payments.php
+++ b/app/Models/Reports/Summary_payments.php
@@ -6,191 +6,191 @@ use Config\OSPOS;
class Summary_payments extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: Hungarian notation
- {
- return [
- ['trans_group' => lang('Reports.trans_group')],
- ['trans_type' => lang('Reports.trans_type')],
- ['trans_sales' => lang('Reports.sales')],
- ['trans_amount' => lang('Reports.trans_amount')],
- ['trans_payments' => lang('Reports.trans_payments')],
- ['trans_refunded' => lang('Reports.trans_refunded')],
- ['trans_due' => lang('Reports.trans_due')]
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: Hungarian notation
+ {
+ return [
+ ['trans_group' => lang('Reports.trans_group')],
+ ['trans_type' => lang('Reports.trans_type')],
+ ['trans_sales' => lang('Reports.sales')],
+ ['trans_amount' => lang('Reports.trans_amount')],
+ ['trans_payments' => lang('Reports.trans_payments')],
+ ['trans_refunded' => lang('Reports.trans_refunded')],
+ ['trans_due' => lang('Reports.trans_due')]
+ ];
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $cash_payment = lang('Sales.cash'); //TODO: This is never used. Should it be?
- $config = config(OSPOS::class)->settings;
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $cash_payment = lang('Sales.cash'); //TODO: This is never used. Should it be?
+ $config = config(OSPOS::class)->settings;
- $separator[] = [
- 'trans_group' => '
',
- 'trans_type' => '',
- 'trans_sales' => '',
- 'trans_amount' => '',
- 'trans_payments' => '',
- 'trans_refunded' => '',
- 'trans_due' => ''
- ];
+ $separator[] = [
+ 'trans_group' => '
',
+ 'trans_type' => '',
+ 'trans_sales' => '',
+ 'trans_amount' => '',
+ 'trans_payments' => '',
+ 'trans_refunded' => '',
+ 'trans_due' => ''
+ ];
- $where = ''; //TODO: Duplicated code
+ $where = ''; //TODO: Duplicated code
- //TODO: this needs to be converted to ternary notation
- if(empty($config['date_or_time_format']))
- {
- $where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
- }
- else
- {
- $where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
- }
+ //TODO: this needs to be converted to ternary notation
+ if(empty($config['date_or_time_format']))
+ {
+ $where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
+ }
+ else
+ {
+ $where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
+ }
- $this->create_summary_payments_temp_tables($where);
+ $this->create_summary_payments_temp_tables($where);
- $select = '\'' . lang('Reports.trans_sales') . '\' AS trans_group, ';
- $select .= '(CASE sale_type WHEN ' . SALE_TYPE_POS . ' THEN \'' . lang('Reports.code_pos')
- . '\' WHEN ' . SALE_TYPE_INVOICE . ' THEN \'' . lang('Sales.invoice')
- . '\' WHEN ' . SALE_TYPE_RETURN . ' THEN \'' . lang('Sales.return')
- . '\' END) AS trans_type, ';
- $select .= 'COUNT(sales.sale_id) AS trans_sales, ';
- $select .= 'SUM(sumpay_items.trans_amount) AS trans_amount, ';
- $select .= 'IFNULL(SUM(sumpay_payments.total_payments),0) AS trans_payments, ';
- $select .= 'IFNULL(SUM(sumpay_payments.total_cash_refund),0) AS trans_refunded, ';
- $select .= 'SUM(CASE WHEN sumpay_items.trans_amount - IFNULL(sumpay_payments.total_payments,0) > 0 THEN sumpay_items.trans_amount - IFNULL(sumpay_payments.total_payments,0) ELSE 0 END) as trans_due ';
+ $select = '\'' . lang('Reports.trans_sales') . '\' AS trans_group, ';
+ $select .= '(CASE sale_type WHEN ' . SALE_TYPE_POS . ' THEN \'' . lang('Reports.code_pos')
+ . '\' WHEN ' . SALE_TYPE_INVOICE . ' THEN \'' . lang('Sales.invoice')
+ . '\' WHEN ' . SALE_TYPE_RETURN . ' THEN \'' . lang('Sales.return')
+ . '\' END) AS trans_type, ';
+ $select .= 'COUNT(sales.sale_id) AS trans_sales, ';
+ $select .= 'SUM(sumpay_items.trans_amount) AS trans_amount, ';
+ $select .= 'IFNULL(SUM(sumpay_payments.total_payments),0) AS trans_payments, ';
+ $select .= 'IFNULL(SUM(sumpay_payments.total_cash_refund),0) AS trans_refunded, ';
+ $select .= 'SUM(CASE WHEN sumpay_items.trans_amount - IFNULL(sumpay_payments.total_payments,0) > 0 THEN sumpay_items.trans_amount - IFNULL(sumpay_payments.total_payments,0) ELSE 0 END) as trans_due ';
- $builder = $this->db->table('ospos_sales AS sales');
- $builder->select($select);
- $builder->join('sumpay_items_temp AS sumpay_items', 'sales.sale_id = sumpay_items.sale_id', 'left outer');
- $builder->join('sumpay_payments_temp AS sumpay_payments', 'sales.sale_id = sumpay_payments.sale_id', 'left outer');
- $builder->where('sales.sale_status', COMPLETED);
- $this->_where($inputs, $builder);
+ $builder = $this->db->table('ospos_sales AS sales');
+ $builder->select($select);
+ $builder->join('sumpay_items_temp AS sumpay_items', 'sales.sale_id = sumpay_items.sale_id', 'left outer');
+ $builder->join('sumpay_payments_temp AS sumpay_payments', 'sales.sale_id = sumpay_payments.sale_id', 'left outer');
+ $builder->where('sales.sale_status', COMPLETED);
+ $this->_where($inputs, $builder);
- $builder->groupBy('trans_type');
+ $builder->groupBy('trans_type');
- $sales = $builder->get()->getResultArray();
+ $sales = $builder->get()->getResultArray();
- // At this point in time refunds are assumed to be cash refunds.
- $total_cash_refund = 0;
- foreach($sales as $key => $sale_summary)
- {
- if($sale_summary['trans_refunded'] <> 0)
- {
- $total_cash_refund += $sale_summary['trans_refunded'];
- }
- }
+ // At this point in time refunds are assumed to be cash refunds.
+ $total_cash_refund = 0;
+ foreach($sales as $key => $sale_summary)
+ {
+ if($sale_summary['trans_refunded'] <> 0)
+ {
+ $total_cash_refund += $sale_summary['trans_refunded'];
+ }
+ }
- $select = '\'' . lang('Reports.trans_payments') . '\' AS trans_group, ';
- $select .= 'sales_payments.payment_type as trans_type, ';
- $select .= 'COUNT(sales.sale_id) AS trans_sales, ';
- $select .= 'SUM(payment_amount - cash_refund) AS trans_amount,';
- $select .= 'SUM(payment_amount) AS trans_payments,';
- $select .= 'SUM(cash_refund) AS trans_refunded, ';
- $select .= '0 AS trans_due ';
+ $select = '\'' . lang('Reports.trans_payments') . '\' AS trans_group, ';
+ $select .= 'sales_payments.payment_type as trans_type, ';
+ $select .= 'COUNT(sales.sale_id) AS trans_sales, ';
+ $select .= 'SUM(payment_amount - cash_refund) AS trans_amount,';
+ $select .= 'SUM(payment_amount) AS trans_payments,';
+ $select .= 'SUM(cash_refund) AS trans_refunded, ';
+ $select .= '0 AS trans_due ';
- $builder = $this->db->table('sales AS sales');
- $builder->select($select);
- $builder->join('sales_payments AS sales_payments', 'sales.sale_id = sales_payments.sale_id', 'left outer');
- $builder->where('sales.sale_status', COMPLETED);
- $this->_where($inputs, $builder);
+ $builder = $this->db->table('sales AS sales');
+ $builder->select($select);
+ $builder->join('sales_payments AS sales_payments', 'sales.sale_id = sales_payments.sale_id', 'left outer');
+ $builder->where('sales.sale_status', COMPLETED);
+ $this->_where($inputs, $builder);
- $builder->groupBy('sales_payments.payment_type');
+ $builder->groupBy('sales_payments.payment_type');
- $payments = $builder->get()->getResultArray();
+ $payments = $builder->get()->getResultArray();
- // consider Gift Card as only one type of payment and do not show "Gift Card: 1, Gift Card: 2, etc." in the total
- $gift_card_count = 0;
- $gift_card_amount = 0;
- foreach($payments as $key => $payment)
- {
- if(str_contains($payment['trans_type'], lang('Sales.giftcard')))
- {
- $gift_card_count += $payment['trans_sales'];
- $gift_card_amount += $payment['trans_amount'];
+ // consider Gift Card as only one type of payment and do not show "Gift Card: 1, Gift Card: 2, etc." in the total
+ $gift_card_count = 0;
+ $gift_card_amount = 0;
+ foreach($payments as $key => $payment)
+ {
+ if(str_contains($payment['trans_type'], lang('Sales.giftcard')))
+ {
+ $gift_card_count += $payment['trans_sales'];
+ $gift_card_amount += $payment['trans_amount'];
- // Remove the "Gift Card: 1", "Gift Card: 2", etc. payment string
- unset($payments[$key]);
- }
- }
+ // Remove the "Gift Card: 1", "Gift Card: 2", etc. payment string
+ unset($payments[$key]);
+ }
+ }
- if($gift_card_count > 0)
- {
- $payments[] = [
- 'trans_group' => lang('Reports.trans_payments'),
- 'trans_type' => lang('Sales.giftcard'),
- 'trans_sales' => $gift_card_count,
- 'trans_amount' => $gift_card_amount,
- 'trans_payments' => $gift_card_amount,
- 'trans_refunded' => 0,
- 'trans_due' => 0
- ];
- }
+ if($gift_card_count > 0)
+ {
+ $payments[] = [
+ 'trans_group' => lang('Reports.trans_payments'),
+ 'trans_type' => lang('Sales.giftcard'),
+ 'trans_sales' => $gift_card_count,
+ 'trans_amount' => $gift_card_amount,
+ 'trans_payments' => $gift_card_amount,
+ 'trans_refunded' => 0,
+ 'trans_due' => 0
+ ];
+ }
- return array_merge($sales, $separator, $payments);
- }
+ return array_merge($sales, $separator, $payments);
+ }
- /**
- * @param string $where
- * @return void
- */
- protected function create_summary_payments_temp_tables(string $where): void
- {
+ /**
+ * @param string $where
+ * @return void
+ */
+ protected function create_summary_payments_temp_tables(string $where): void
+ {
//TODO: convert to using QueryBuilder. Use App/Models/Reports/Summary_taxes.php getData() as a reference template
- $decimals = totals_decimals();
+ $decimals = totals_decimals();
- $trans_amount = 'SUM(CASE WHEN sales_items.discount_type = ' . PERCENT
- . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
- . ' ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END) AS trans_amount';
+ $trans_amount = 'SUM(CASE WHEN sales_items.discount_type = ' . PERCENT
+ . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
+ . ' ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END) AS trans_amount';
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_taxes_temp') .
- ' (INDEX(sale_id)) ENGINE=MEMORY
- (
- SELECT sales.sale_id, SUM(sales_taxes.sale_tax_amount) AS total_taxes
- FROM ' . $this->db->prefixTable('sales') . ' AS sales
- LEFT OUTER JOIN ' . $this->db->prefixTable('sales_taxes') . ' AS sales_taxes
- ON sales.sale_id = sales_taxes.sale_id
- WHERE ' . $where . ' AND sales_taxes.tax_type = \'1\'
- GROUP BY sale_id
- )'
- );
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_taxes_temp') .
+ ' (INDEX(sale_id)) ENGINE=MEMORY
+ (
+ SELECT sales.sale_id, SUM(sales_taxes.sale_tax_amount) AS total_taxes
+ FROM ' . $this->db->prefixTable('sales') . ' AS sales
+ LEFT OUTER JOIN ' . $this->db->prefixTable('sales_taxes') . ' AS sales_taxes
+ ON sales.sale_id = sales_taxes.sale_id
+ WHERE ' . $where . ' AND sales_taxes.tax_type = \'1\'
+ GROUP BY sale_id
+ )'
+ );
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_items_temp') .
- ' (INDEX(sale_id)) ENGINE=MEMORY
- (
- SELECT sales.sale_id, ' . $trans_amount
- . ' FROM ' . $this->db->prefixTable('sales') . ' AS sales '
- . 'LEFT OUTER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items '
- . 'ON sales.sale_id = sales_items.sale_id '
- . 'LEFT OUTER JOIN ' . $this->db->prefixTable('sumpay_taxes_temp') . ' AS sumpay_taxes '
- . 'ON sales.sale_id = sumpay_taxes.sale_id '
- . 'WHERE ' . $where . ' GROUP BY sale_id
- )'
- );
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_items_temp') .
+ ' (INDEX(sale_id)) ENGINE=MEMORY
+ (
+ SELECT sales.sale_id, ' . $trans_amount
+ . ' FROM ' . $this->db->prefixTable('sales') . ' AS sales '
+ . 'LEFT OUTER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items '
+ . 'ON sales.sale_id = sales_items.sale_id '
+ . 'LEFT OUTER JOIN ' . $this->db->prefixTable('sumpay_taxes_temp') . ' AS sumpay_taxes '
+ . 'ON sales.sale_id = sumpay_taxes.sale_id '
+ . 'WHERE ' . $where . ' GROUP BY sale_id
+ )'
+ );
- $this->db->query('UPDATE ' . $this->db->prefixTable('sumpay_items_temp') . ' AS sumpay_items '
- . 'SET trans_amount = trans_amount + IFNULL((SELECT total_taxes FROM ' . $this->db->prefixTable('sumpay_taxes_temp')
- . ' AS sumpay_taxes WHERE sumpay_items.sale_id = sumpay_taxes.sale_id),0)');
+ $this->db->query('UPDATE ' . $this->db->prefixTable('sumpay_items_temp') . ' AS sumpay_items '
+ . 'SET trans_amount = trans_amount + IFNULL((SELECT total_taxes FROM ' . $this->db->prefixTable('sumpay_taxes_temp')
+ . ' AS sumpay_taxes WHERE sumpay_items.sale_id = sumpay_taxes.sale_id),0)');
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_payments_temp') .
- ' (INDEX(sale_id)) ENGINE=MEMORY
- (
- SELECT sales.sale_id, COUNT(sales.sale_id) AS number_payments,
- SUM(CASE WHEN sales_payments.cash_adjustment = 0 THEN sales_payments.payment_amount ELSE 0 END) AS total_payments,
- SUM(CASE WHEN sales_payments.cash_adjustment = 1 THEN sales_payments.payment_amount ELSE 0 END) AS total_cash_adjustment,
- SUM(sales_payments.cash_refund) AS total_cash_refund
- FROM ' . $this->db->prefixTable('sales') . ' AS sales
- LEFT OUTER JOIN ' . $this->db->prefixTable('sales_payments') . ' AS sales_payments
- ON sales.sale_id = sales_payments.sale_id
- WHERE ' . $where . '
- GROUP BY sale_id
- )'
- );
- }
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sumpay_payments_temp') .
+ ' (INDEX(sale_id)) ENGINE=MEMORY
+ (
+ SELECT sales.sale_id, COUNT(sales.sale_id) AS number_payments,
+ SUM(CASE WHEN sales_payments.cash_adjustment = 0 THEN sales_payments.payment_amount ELSE 0 END) AS total_payments,
+ SUM(CASE WHEN sales_payments.cash_adjustment = 1 THEN sales_payments.payment_amount ELSE 0 END) AS total_cash_adjustment,
+ SUM(sales_payments.cash_refund) AS total_cash_refund
+ FROM ' . $this->db->prefixTable('sales') . ' AS sales
+ LEFT OUTER JOIN ' . $this->db->prefixTable('sales_payments') . ' AS sales_payments
+ ON sales.sale_id = sales_payments.sale_id
+ WHERE ' . $where . '
+ GROUP BY sale_id
+ )'
+ );
+ }
}
diff --git a/app/Models/Reports/Summary_report.php b/app/Models/Reports/Summary_report.php
index 161649d71..c96606b13 100644
--- a/app/Models/Reports/Summary_report.php
+++ b/app/Models/Reports/Summary_report.php
@@ -7,235 +7,235 @@ use CodeIgniter\Database\BaseBuilder;
abstract class Summary_report extends Report
{
- /**
- * Private interface implementing the core basic functionality for all reports
- */
- private function __common_select(array $inputs, &$builder): void //TODO: Hungarian notation
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * Private interface implementing the core basic functionality for all reports
+ */
+ private function __common_select(array $inputs, &$builder): void //TODO: Hungarian notation
+ {
+ $config = config(OSPOS::class)->settings;
//TODO: convert to using QueryBuilder. Use App/Models/Reports/Summary_taxes.php getData() as a reference template
- $where = ''; //TODO: Duplicated code
+ $where = ''; //TODO: Duplicated code
- if(empty($config['date_or_time_format']))
- {
- $where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
- }
- else
- {
- $where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
- }
+ if(empty($config['date_or_time_format']))
+ {
+ $where .= 'DATE(sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
+ }
+ else
+ {
+ $where .= 'sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
+ }
- $decimals = totals_decimals();
+ $decimals = totals_decimals();
- $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
- . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
- . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
+ $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
+ . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
+ . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
- $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)';
- $sales_tax = "IFNULL(SUM(sales_items_taxes.tax), 0)";
+ $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)';
+ $sales_tax = "IFNULL(SUM(sales_items_taxes.tax), 0)";
- $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
+ $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
- if($config['tax_included'])
- {
- $sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
- $sale_subtotal = "$sale_total - $sales_tax";
+ if($config['tax_included'])
+ {
+ $sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
+ $sale_subtotal = "$sale_total - $sales_tax";
- }
- else
- {
- $sale_subtotal = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
- $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
- }
+ }
+ else
+ {
+ $sale_subtotal = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
+ $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
+ }
- // create a temporary table to contain all the sum of taxes per sale item
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_taxes_temp') .
- ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY
- (
- SELECT sales_items_taxes.sale_id AS sale_id,
- sales_items_taxes.item_id AS item_id,
- sales_items_taxes.line AS line,
- SUM(ROUND(sales_items_taxes.item_tax_amount,' . $decimals . ')) AS tax
- FROM ' . $this->db->prefixTable('sales_items_taxes') . ' AS sales_items_taxes
- INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
- ON sales.sale_id = sales_items_taxes.sale_id
- INNER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items
- ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line
- WHERE ' . $where . '
- GROUP BY sale_id, item_id, line
- )'
- );
+ // create a temporary table to contain all the sum of taxes per sale item
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_taxes_temp') .
+ ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY
+ (
+ SELECT sales_items_taxes.sale_id AS sale_id,
+ sales_items_taxes.item_id AS item_id,
+ sales_items_taxes.line AS line,
+ SUM(ROUND(sales_items_taxes.item_tax_amount,' . $decimals . ')) AS tax
+ FROM ' . $this->db->prefixTable('sales_items_taxes') . ' AS sales_items_taxes
+ INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
+ ON sales.sale_id = sales_items_taxes.sale_id
+ INNER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items
+ ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line
+ WHERE ' . $where . '
+ GROUP BY sale_id, item_id, line
+ )'
+ );
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_payments_temp') .
- ' (PRIMARY KEY(sale_id), INDEX(sale_id))
- (
- SELECT payments.sale_id AS sale_id,
- SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
- SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
- SUM(payments.cash_refund) AS sale_cash_refund,
- GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
- FROM ' . $this->db->prefixTable('sales_payments') . ' AS payments
- INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
- ON sales.sale_id = payments.sale_id
- WHERE ' . $where . '
- GROUP BY sale_id
- )'
- );
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_payments_temp') .
+ ' (PRIMARY KEY(sale_id), INDEX(sale_id))
+ (
+ SELECT payments.sale_id AS sale_id,
+ SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
+ SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
+ SUM(payments.cash_refund) AS sale_cash_refund,
+ GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
+ FROM ' . $this->db->prefixTable('sales_payments') . ' AS payments
+ INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
+ ON sales.sale_id = payments.sale_id
+ WHERE ' . $where . '
+ GROUP BY sale_id
+ )'
+ );
- $builder->select("
- IFNULL($sale_subtotal, $sale_total) AS subtotal,
- $sales_tax AS tax,
- IFNULL($sale_total, $sale_subtotal) AS total,
- $sale_cost AS cost,
- (IFNULL($sale_subtotal, $sale_total) - $sale_cost) AS profit
- ");
- }
+ $builder->select("
+ IFNULL($sale_subtotal, $sale_total) AS subtotal,
+ $sales_tax AS tax,
+ IFNULL($sale_total, $sale_subtotal) AS total,
+ $sale_cost AS cost,
+ (IFNULL($sale_subtotal, $sale_total) - $sale_cost) AS profit
+ ");
+ }
- /**
- * @param BaseBuilder $builder
- * @return void
- */
- private function __common_from(BaseBuilder &$builder): void //TODO: hungarian notation
- {
- $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
- $builder->join('sales_items_taxes_temp AS sales_items_taxes',
- 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
- 'left outer');
- $builder->join('sales_payments_temp AS payments', 'sales.sale_id = payments.sale_id', 'LEFT OUTER');
- }
+ /**
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ private function __common_from(BaseBuilder &$builder): void //TODO: hungarian notation
+ {
+ $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
+ $builder->join('sales_items_taxes_temp AS sales_items_taxes',
+ 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
+ 'left outer');
+ $builder->join('sales_payments_temp AS payments', 'sales.sale_id = payments.sale_id', 'LEFT OUTER');
+ }
- /**
- * @param array $inputs
- * @param $builder
- * @return void
- */
- private function __common_where(array $inputs, &$builder): void
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * @param array $inputs
+ * @param $builder
+ * @return void
+ */
+ private function __common_where(array $inputs, &$builder): void
+ {
+ $config = config(OSPOS::class)->settings;
- //TODO: Probably going to need to rework these since you can't reference $builder without it's instantiation.
- if(empty($config['date_or_time_format'])) //TODO: Duplicated code
- {
- $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
+ //TODO: Probably going to need to rework these since you can't reference $builder without it's instantiation.
+ if(empty($config['date_or_time_format'])) //TODO: Duplicated code
+ {
+ $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
- if($inputs['location_id'] != 'all')
- {
- $builder->where('sales_items.item_location', $inputs['location_id']);
- }
+ if($inputs['location_id'] != 'all')
+ {
+ $builder->where('sales_items.item_location', $inputs['location_id']);
+ }
- if($inputs['sale_type'] == 'complete')
- {
- $builder->where('sales.sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sales.sale_type', SALE_TYPE_POS);
- $builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
- $builder->orWhere('sales.sale_type', SALE_TYPE_RETURN);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'sales')
- {
- $builder->where('sales.sale_status', COMPLETED);
- $builder->groupStart();
- $builder->where('sales.sale_type', SALE_TYPE_POS);
- $builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
- $builder->groupEnd();
- }
- elseif($inputs['sale_type'] == 'quotes')
- {
- $builder->where('sales.sale_status', SUSPENDED);
- $builder->where('sales.sale_type', SALE_TYPE_QUOTE);
- }
- elseif($inputs['sale_type'] == 'work_orders')
- {
- $builder->where('sales.sale_status', SUSPENDED);
- $builder->where('sales.sale_type', SALE_TYPE_WORK_ORDER);
- }
- elseif($inputs['sale_type'] == 'canceled')
- {
- $builder->where('sales.sale_status', CANCELED);
- }
- elseif($inputs['sale_type'] == 'returns')
- {
- $builder->where('sales.sale_status', COMPLETED);
- $builder->where('sales.sale_type', SALE_TYPE_RETURN);
- }
- }
+ if($inputs['sale_type'] == 'complete')
+ {
+ $builder->where('sales.sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sales.sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
+ $builder->orWhere('sales.sale_type', SALE_TYPE_RETURN);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'sales')
+ {
+ $builder->where('sales.sale_status', COMPLETED);
+ $builder->groupStart();
+ $builder->where('sales.sale_type', SALE_TYPE_POS);
+ $builder->orWhere('sales.sale_type', SALE_TYPE_INVOICE);
+ $builder->groupEnd();
+ }
+ elseif($inputs['sale_type'] == 'quotes')
+ {
+ $builder->where('sales.sale_status', SUSPENDED);
+ $builder->where('sales.sale_type', SALE_TYPE_QUOTE);
+ }
+ elseif($inputs['sale_type'] == 'work_orders')
+ {
+ $builder->where('sales.sale_status', SUSPENDED);
+ $builder->where('sales.sale_type', SALE_TYPE_WORK_ORDER);
+ }
+ elseif($inputs['sale_type'] == 'canceled')
+ {
+ $builder->where('sales.sale_status', CANCELED);
+ }
+ elseif($inputs['sale_type'] == 'returns')
+ {
+ $builder->where('sales.sale_status', COMPLETED);
+ $builder->where('sales.sale_type', SALE_TYPE_RETURN);
+ }
+ }
- /**
- * Protected class interface implemented by derived classes where required
- */
- abstract protected function _get_data_columns(): array; //TODO: hungarian notation
+ /**
+ * Protected class interface implemented by derived classes where required
+ */
+ abstract protected function _get_data_columns(): array; //TODO: hungarian notation
- /**
- * @param array $inputs
- * @param BaseBuilder $builder
- * @return void
- */
- protected function _select(array $inputs, BaseBuilder &$builder): void { $this->__common_select($inputs, $builder); } //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ protected function _select(array $inputs, BaseBuilder &$builder): void { $this->__common_select($inputs, $builder); } //TODO: hungarian notation
- /**
- * @param BaseBuilder $builder
- * @return void
- */
- protected function _from(BaseBuilder &$builder): void { $this->__common_from($builder); } //TODO: hungarian notation TODO: Do we need to pass &$builder to the __common_from()?
+ /**
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ protected function _from(BaseBuilder &$builder): void { $this->__common_from($builder); } //TODO: hungarian notation TODO: Do we need to pass &$builder to the __common_from()?
- /**
- * @param array $inputs
- * @param BaseBuilder $builder
- * @return void
- */
- protected function _where(array $inputs, BaseBuilder &$builder): void { $this->__common_where($inputs, $builder); } //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ protected function _where(array $inputs, BaseBuilder &$builder): void { $this->__common_where($inputs, $builder); } //TODO: hungarian notation
- /**
- * @param BaseBuilder $builder
- * @return void
- */
- protected function _group_order(BaseBuilder &$builder): void {} //TODO: hungarian notation
+ /**
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ protected function _group_order(BaseBuilder &$builder): void {} //TODO: hungarian notation
- /**
- * Public interface implementing the base abstract class,
- * in general it should not be extended unless there is a valid reason
- * like a non sale report (e.g. expenses)
- */
+ /**
+ * Public interface implementing the base abstract class,
+ * in general it should not be extended unless there is a valid reason
+ * like a non sale report (e.g. expenses)
+ */
- public function getDataColumns(): array
- {
- return $this->_get_data_columns();
- }
+ public function getDataColumns(): array
+ {
+ return $this->_get_data_columns();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_items AS sales_items');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items AS sales_items');
- $this->_select($inputs, $builder);
- $this->_from($builder);
- $this->_where($inputs, $builder);
- $this->_group_order($builder);
+ $this->_select($inputs, $builder);
+ $this->_from($builder);
+ $this->_where($inputs, $builder);
+ $this->_group_order($builder);
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getSummaryData(array $inputs): array
- {
- $builder = $this->db->table('sales_items AS sales_items');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getSummaryData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_items AS sales_items');
- $this->__common_select($inputs, $builder);
- $this->__common_from($builder);
- $this->_where($inputs, $builder);
+ $this->__common_select($inputs, $builder);
+ $this->__common_from($builder);
+ $this->_where($inputs, $builder);
- return $builder->get()->getRowArray();
- }
+ return $builder->get()->getRowArray();
+ }
}
diff --git a/app/Models/Reports/Summary_sales.php b/app/Models/Reports/Summary_sales.php
index 73afdaf34..1e9ed21ab 100644
--- a/app/Models/Reports/Summary_sales.php
+++ b/app/Models/Reports/Summary_sales.php
@@ -4,46 +4,46 @@ namespace App\Models\Reports;
class Summary_sales extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array
- {
- return [
- ['sale_date' => lang('Reports.date'), 'sortable' => false],
- ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
- ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array
+ {
+ return [
+ ['sale_date' => lang('Reports.date'), 'sortable' => false],
+ ['sales' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
+ ['quantity' => lang('Reports.quantity'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
- {
- parent::_select($inputs, $builder); //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
+ {
+ parent::_select($inputs, $builder); //TODO: hungarian notation
- $builder->select('
- DATE(sales.sale_time) AS sale_date,
- SUM(sales_items.quantity_purchased) AS quantity_purchased,
- COUNT(DISTINCT sales.sale_id) AS sales
- ');
- }
+ $builder->select('
+ DATE(sales.sale_time) AS sale_date,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased,
+ COUNT(DISTINCT sales.sale_id) AS sales
+ ');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _group_order(object &$builder): void //TODO: hungarian notation
- {
- $builder->groupBy('sale_date');
- $builder->orderBy('sale_date');
- }
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _group_order(object &$builder): void //TODO: hungarian notation
+ {
+ $builder->groupBy('sale_date');
+ $builder->orderBy('sale_date');
+ }
}
diff --git a/app/Models/Reports/Summary_sales_taxes.php b/app/Models/Reports/Summary_sales_taxes.php
index f774838c6..09565b8c1 100644
--- a/app/Models/Reports/Summary_sales_taxes.php
+++ b/app/Models/Reports/Summary_sales_taxes.php
@@ -6,72 +6,72 @@ use Config\OSPOS;
class Summary_sales_taxes extends Summary_report
{
- private array $config;
+ private array $config;
- public function __construct()
- {
- parent::__construct();
- $this->config = config(OSPOS::class)->settings;
- }
+ public function __construct()
+ {
+ parent::__construct();
+ $this->config = config(OSPOS::class)->settings;
+ }
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: hungarian notation
- {
- return [
- ['reporting_authority' => lang('Reports.authority')],
- ['jurisdiction_name' => lang('Reports.jurisdiction')],
- ['tax_category' => lang('Reports.tax_category')],
- ['tax_rate' => lang('Reports.tax_rate'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: hungarian notation
+ {
+ return [
+ ['reporting_authority' => lang('Reports.authority')],
+ ['jurisdiction_name' => lang('Reports.jurisdiction')],
+ ['tax_category' => lang('Reports.tax_category')],
+ ['tax_rate' => lang('Reports.tax_rate'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _where(array $inputs, object &$builder): void //TODO: hungarian notation
- {
- $builder->where('sales.sale_status', COMPLETED);
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _where(array $inputs, object &$builder): void //TODO: hungarian notation
+ {
+ $builder->where('sales.sale_status', COMPLETED);
- if(empty($this->config['date_or_time_format'])) //TODO: Duplicated code
- {
- $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
- }
+ if(empty($this->config['date_or_time_format'])) //TODO: Duplicated code
+ {
+ $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $builder = $this->db->table('sales_taxes');
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $builder = $this->db->table('sales_taxes');
- if(empty($this->config['date_or_time_format']))
- {
- $builder->where('DATE(sale_time) BETWEEN ' . $inputs['start_date'] . ' AND ' . $inputs['end_date']);
- }
- else
- {
- $builder->where('sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
+ if(empty($this->config['date_or_time_format']))
+ {
+ $builder->where('DATE(sale_time) BETWEEN ' . $inputs['start_date'] . ' AND ' . $inputs['end_date']);
+ }
+ else
+ {
+ $builder->where('sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
- $builder->select('reporting_authority, jurisdiction_name, tax_category, tax_rate, SUM(sale_tax_amount) AS tax');
- $builder->join('sales', 'sales_taxes.sale_id = sales.sale_id', 'left');
- $builder->join('tax_categories', 'sales_taxes.tax_category_id = tax_categories.tax_category_id', 'left');
- $builder->join('tax_jurisdictions', 'sales_taxes.jurisdiction_id = tax_jurisdictions.jurisdiction_id', 'left');
- $builder->groupBy('reporting_authority, jurisdiction_name, tax_category, tax_rate');
+ $builder->select('reporting_authority, jurisdiction_name, tax_category, tax_rate, SUM(sale_tax_amount) AS tax');
+ $builder->join('sales', 'sales_taxes.sale_id = sales.sale_id', 'left');
+ $builder->join('tax_categories', 'sales_taxes.tax_category_id = tax_categories.tax_category_id', 'left');
+ $builder->join('tax_jurisdictions', 'sales_taxes.jurisdiction_id = tax_jurisdictions.jurisdiction_id', 'left');
+ $builder->groupBy('reporting_authority, jurisdiction_name, tax_category, tax_rate');
- $query = $builder->get();
+ $query = $builder->get();
- return $query->getResultArray();
- }
+ return $query->getResultArray();
+ }
}
diff --git a/app/Models/Reports/Summary_suppliers.php b/app/Models/Reports/Summary_suppliers.php
index f8b5ea5f2..b13b94a84 100644
--- a/app/Models/Reports/Summary_suppliers.php
+++ b/app/Models/Reports/Summary_suppliers.php
@@ -4,57 +4,57 @@ namespace App\Models\Reports;
class Summary_suppliers extends Summary_report
{
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: hungarian notation
- {
- return [
- ['supplier_name' => lang('Reports.supplier')],
- ['quantity' => lang('Reports.quantity')],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
- ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
- ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: hungarian notation
+ {
+ return [
+ ['supplier_name' => lang('Reports.supplier')],
+ ['quantity' => lang('Reports.quantity')],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter'],
+ ['cost' => lang('Reports.cost'), 'sorter' => 'number_sorter'],
+ ['profit' => lang('Reports.profit'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param object $builder
- * @return void
- */
- protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
- {
- parent::_select($inputs, $builder); //TODO: hungarian notation
+ /**
+ * @param array $inputs
+ * @param object $builder
+ * @return void
+ */
+ protected function _select(array $inputs, object &$builder): void //TODO: hungarian notation
+ {
+ parent::_select($inputs, $builder); //TODO: hungarian notation
- $builder->select('
- MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")")) AS supplier,
- SUM(sales_items.quantity_purchased) AS quantity_purchased
- ');
- }
+ $builder->select('
+ MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")")) AS supplier,
+ SUM(sales_items.quantity_purchased) AS quantity_purchased
+ ');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _from(object &$builder): void //TODO: hungarian notation
- {
- parent::_from($builder); //TODO: hungarian notation
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _from(object &$builder): void //TODO: hungarian notation
+ {
+ parent::_from($builder); //TODO: hungarian notation
- $builder->join('items AS items', 'sales_items.item_id = items.item_id');
- $builder->join('suppliers AS supplier_c', 'items.supplier_id = supplier_c.person_id ');
- $builder->join('people AS supplier_p', 'items.supplier_id = supplier_p.person_id');
- }
+ $builder->join('items AS items', 'sales_items.item_id = items.item_id');
+ $builder->join('suppliers AS supplier_c', 'items.supplier_id = supplier_c.person_id ');
+ $builder->join('people AS supplier_p', 'items.supplier_id = supplier_p.person_id');
+ }
- /**
- * @param object $builder
- * @return void
- */
- protected function _group_order(object &$builder): void //TODO: hungarian notation
- {
- $builder->groupBy('items.supplier_id');
- $builder->orderBy('MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")"))');
- }
+ /**
+ * @param object $builder
+ * @return void
+ */
+ protected function _group_order(object &$builder): void //TODO: hungarian notation
+ {
+ $builder->groupBy('items.supplier_id');
+ $builder->orderBy('MAX(CONCAT(supplier_c.company_name, " (", supplier_p.first_name, " ", supplier_p.last_name, ")"))');
+ }
}
diff --git a/app/Models/Reports/Summary_taxes.php b/app/Models/Reports/Summary_taxes.php
index 9d89af77d..0c3d1c03b 100644
--- a/app/Models/Reports/Summary_taxes.php
+++ b/app/Models/Reports/Summary_taxes.php
@@ -6,99 +6,99 @@ use Config\OSPOS;
class Summary_taxes extends Summary_report
{
- private array $config;
+ private array $config;
- public function __construct()
- {
- parent::__construct();
- $this->config = config(OSPOS::class)->settings;
- }
+ public function __construct()
+ {
+ parent::__construct();
+ $this->config = config(OSPOS::class)->settings;
+ }
- /**
- * @return array[]
- */
- protected function _get_data_columns(): array //TODO: hungarian notation
- {
- return [
- ['tax_name' => lang('Reports.tax_name'), 'sortable' => false],
- ['tax_percent' => lang('Reports.tax_percent'), 'sorter' => 'number_sorter'],
- ['report_count' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
- ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
- ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
- ['total' => lang('Reports.total'), 'sorter' => 'number_sorter']
- ];
- }
+ /**
+ * @return array[]
+ */
+ protected function _get_data_columns(): array //TODO: hungarian notation
+ {
+ return [
+ ['tax_name' => lang('Reports.tax_name'), 'sortable' => false],
+ ['tax_percent' => lang('Reports.tax_percent'), 'sorter' => 'number_sorter'],
+ ['report_count' => lang('Reports.sales'), 'sorter' => 'number_sorter'],
+ ['subtotal' => lang('Reports.subtotal'), 'sorter' => 'number_sorter'],
+ ['tax' => lang('Reports.tax'), 'sorter' => 'number_sorter'],
+ ['total' => lang('Reports.total'), 'sorter' => 'number_sorter']
+ ];
+ }
- /**
- * @param array $inputs
- * @param $builder
- * @return void
- */
- protected function _where(array $inputs, &$builder): void //TODO: hungarian notation
- {
- $builder->where('sales.sale_status', COMPLETED);
+ /**
+ * @param array $inputs
+ * @param $builder
+ * @return void
+ */
+ protected function _where(array $inputs, &$builder): void //TODO: hungarian notation
+ {
+ $builder->where('sales.sale_status', COMPLETED);
- if(empty($this->config['date_or_time_format']))
- {
- $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
- }
+ if(empty($this->config['date_or_time_format']))
+ {
+ $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
+ }
- /**
- * @param array $inputs
- * @return array
- */
- public function getData(array $inputs): array
- {
- $decimals = totals_decimals();
- $db_prefix = $this->db->getPrefix();
+ /**
+ * @param array $inputs
+ * @return array
+ */
+ public function getData(array $inputs): array
+ {
+ $decimals = totals_decimals();
+ $db_prefix = $this->db->getPrefix();
- if($this->config['tax_included'])
- {
- $sale_total = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
- . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
- . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * (' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount) END)';
+ if($this->config['tax_included'])
+ {
+ $sale_total = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
+ . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
+ . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * (' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount) END)';
- $sale_subtotal = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
- . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals) "
- . 'ELSE ' . $db_prefix . 'sales_items.quantity_purchased * ' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount END * (100 / (100 + ' . $db_prefix . 'sales_items_taxes.percent)))';
- }
- else
- {
- $sale_total = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
- . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
- . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * ' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount END * (1 + (' . $db_prefix . 'sales_items_taxes.percent / 100)))';
+ $sale_subtotal = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
+ . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals) "
+ . 'ELSE ' . $db_prefix . 'sales_items.quantity_purchased * ' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount END * (100 / (100 + ' . $db_prefix . 'sales_items_taxes.percent)))';
+ }
+ else
+ {
+ $sale_total = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
+ . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
+ . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * ' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount END * (1 + (' . $db_prefix . 'sales_items_taxes.percent / 100)))';
- $sale_subtotal = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
- . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
- . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * (' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount) END)';
- }
+ $sale_subtotal = '(CASE WHEN ' . $db_prefix . 'sales_items.discount_type = ' . PERCENT
+ . " THEN " . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price - ROUND(" . $db_prefix . "sales_items.quantity_purchased * " . $db_prefix . "sales_items.item_unit_price * " . $db_prefix . "sales_items.discount / 100, $decimals)"
+ . ' ELSE ' . $db_prefix . 'sales_items.quantity_purchased * (' . $db_prefix . 'sales_items.item_unit_price - ' . $db_prefix . 'sales_items.discount) END)';
+ }
- $subquery_builder = $this->db->table('sales_items');
- $subquery_builder->select("name AS name, CONCAT(IFNULL(ROUND(percent, $decimals), 0), '%') AS percent, sales.sale_id AS sale_id, $sale_subtotal AS subtotal, IFNULL($db_prefix"."sales_items_taxes.item_tax_amount, 0) AS tax, IFNULL($sale_total, $sale_subtotal) AS total");
+ $subquery_builder = $this->db->table('sales_items');
+ $subquery_builder->select("name AS name, CONCAT(IFNULL(ROUND(percent, $decimals), 0), '%') AS percent, sales.sale_id AS sale_id, $sale_subtotal AS subtotal, IFNULL($db_prefix"."sales_items_taxes.item_tax_amount, 0) AS tax, IFNULL($sale_total, $sale_subtotal) AS total");
- $subquery_builder->join('sales', 'sales_items.sale_id = sales.sale_id', 'inner');
- $subquery_builder->join('sales_items_taxes', 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line', 'left outer');
+ $subquery_builder->join('sales', 'sales_items.sale_id = sales.sale_id', 'inner');
+ $subquery_builder->join('sales_items_taxes', 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line', 'left outer');
- $subquery_builder->where('sale_status', COMPLETED);
+ $subquery_builder->where('sale_status', COMPLETED);
- if(empty($this->config['date_or_time_format']))
- {
- $subquery_builder->where('DATE(' . $db_prefix . 'sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
- }
- else
- {
- $subquery_builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
- }
+ if(empty($this->config['date_or_time_format']))
+ {
+ $subquery_builder->where('DATE(' . $db_prefix . 'sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']));
+ }
+ else
+ {
+ $subquery_builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date'])));
+ }
- $builder = $this->db->newQuery()->fromSubquery($subquery_builder, 'temp_taxes');
- $builder->select("name, percent, COUNT(DISTINCT sale_id) AS count, ROUND(SUM(subtotal), $decimals) AS subtotal, ROUND(SUM(tax), $decimals) AS tax, ROUND(SUM(total), $decimals) total");
- $builder->groupBy('percent, name');
+ $builder = $this->db->newQuery()->fromSubquery($subquery_builder, 'temp_taxes');
+ $builder->select("name, percent, COUNT(DISTINCT sale_id) AS count, ROUND(SUM(subtotal), $decimals) AS subtotal, ROUND(SUM(tax), $decimals) AS tax, ROUND(SUM(total), $decimals) total");
+ $builder->groupBy('percent, name');
- return $builder->get()->getResultArray();
- }
+ return $builder->get()->getResultArray();
+ }
}
diff --git a/app/Models/Rewards.php b/app/Models/Rewards.php
index 60cde306d..6b313c5a5 100644
--- a/app/Models/Rewards.php
+++ b/app/Models/Rewards.php
@@ -8,38 +8,38 @@ use CodeIgniter\Model;
* Rewards class
*/
-class Rewards extends Model //TODO: This class is named with plural while the general practice is to name models singular
+class Rewards extends Model //TODO: This class is named with plural while the general practice is to name models singular
{
- protected $table = 'sales_reward_points';
- protected $primaryKey = 'id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'sale_id',
- 'earned',
- 'used'
- ];
+ protected $table = 'sales_reward_points';
+ protected $primaryKey = 'id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'sale_id',
+ 'earned',
+ 'used'
+ ];
- /**
- * Inserts or updates a rewards
- */
- public function save_value(array &$rewards_data, bool $rewards_id = false): bool
- {
- $builder = $this->db->table('sales_reward_points');
- if(!$rewards_id || !$this->exists($rewards_id)) //TODO: looks like we are missing the exists function in this class
- {
- if($builder->insert($rewards_data))
- {
- $rewards_data['id'] = $this->db->insertID();
+ /**
+ * Inserts or updates a rewards
+ */
+ public function save_value(array &$rewards_data, bool $rewards_id = false): bool
+ {
+ $builder = $this->db->table('sales_reward_points');
+ if(!$rewards_id || !$this->exists($rewards_id)) //TODO: looks like we are missing the exists function in this class
+ {
+ if($builder->insert($rewards_data))
+ {
+ $rewards_data['id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('id', $rewards_id);
+ $builder->where('id', $rewards_id);
- return $builder->update($rewards_data);
- }
+ return $builder->update($rewards_data);
+ }
}
diff --git a/app/Models/Sale.php b/app/Models/Sale.php
index c8200afa8..3f56d9321 100644
--- a/app/Models/Sale.php
+++ b/app/Models/Sale.php
@@ -14,1586 +14,1586 @@ use ReflectionException;
*/
class Sale extends Model
{
- protected $table = 'sales';
- protected $primaryKey = 'sale_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'sale_time',
- 'customer_id',
- 'employee_id',
- 'comment',
- 'quote_number',
- 'sale_status',
- 'invoice_number',
- 'dinner_table_id',
- 'work_order_number',
- 'sale_type'
- ];
-
- public function __construct()
- {
- parent::__construct();
- helper('text');
- }
-
- /**
- * Get sale info
- */
- public function get_info(int $sale_id): ResultInterface
- {
- $config = config(OSPOS::class)->settings;
- $this->create_temp_table (['sale_id' => $sale_id]);
-
- $decimals = totals_decimals();
- $sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
- $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
- $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
- . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
- . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
-
- $sale_total = $config['tax_included']
- ? "ROUND(SUM($sale_price), $decimals) + $cash_adjustment"
- : "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
-
- $sql = 'sales.sale_id AS sale_id,
- MAX(DATE(sales.sale_time)) AS sale_date,
- MAX(sales.sale_time) AS sale_time,
- MAX(sales.comment) AS comment,
- MAX(sales.sale_status) AS sale_status,
- MAX(sales.invoice_number) AS invoice_number,
- MAX(sales.quote_number) AS quote_number,
- MAX(sales.employee_id) AS employee_id,
- MAX(sales.customer_id) AS customer_id,
- MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name,
- MAX(customer_p.first_name) AS first_name,
- MAX(customer_p.last_name) AS last_name,
- MAX(customer_p.email) AS email,
- MAX(customer_p.comments) AS comments,
- MAX(IFnull(payments.sale_cash_adjustment, 0)) AS cash_adjustment,
- MAX(IFnull(payments.sale_cash_refund, 0)) AS cash_refund,
- ' . "
- $sale_total AS amount_due,
- MAX(IFnull(payments.sale_payment_amount, 0)) AS amount_tendered,
- (MAX(payments.sale_payment_amount)) - ($sale_total) AS change_due,
- " . '
- MAX(payments.payment_type) AS payment_type';
-
- $builder = $this->db->table('sales_items AS sales_items');
- $builder->select($sql);
-
- $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
- $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id', 'LEFT');
- $builder->join('customers AS customer', 'sales.customer_id = customer.person_id', 'LEFT');
- $builder->join('sales_payments_temp AS payments', 'sales.sale_id = payments.sale_id', 'LEFT OUTER');
- $builder->join('sales_items_taxes_temp AS sales_items_taxes',
- 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
- 'LEFT OUTER');
-
- $builder->where('sales.sale_id', $sale_id);
-
- $builder->groupBy('sales.sale_id');
- $builder->orderBy('sales.sale_time', 'asc');
-
- return $builder->get();
- }
-
- /**
- * Get number of rows for the takings (sales/manage) view
- */
- public function get_found_rows(string $search, array $filters): int
- {
- return $this->search($search, $filters, 0, 0, 'sales.sale_time', 'desc', true);
- }
-
- /**
- * Get the sales data for the takings (sales/manage) view
- */
- public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'sales.sale_time', ?string $order = 'desc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'sales.sale_time';
- if($order == null) $order = 'desc';
- if($count_only == null) $count_only = false;
-
- $config = config(OSPOS::class)->settings;
- $db_prefix = $this->db->getPrefix();
- $decimals = totals_decimals();
-
- //Only non-suspended records
- $where = 'sales.sale_status = 0 AND ';
- $where .= empty($config['date_or_time_format'])
- ? 'DATE(' . $db_prefix . 'sales.sale_time) BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date'])
- : 'sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']));
-
- $this->create_temp_table_sales_payments_data($where);
-
- $sale_price = 'CASE WHEN `sales_items`.`discount_type` = ' . PERCENT
- . " THEN `sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` - ROUND(`sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` * `sales_items`.`discount` / 100, $decimals) "
- . 'ELSE `sales_items`.`quantity_purchased` * (`sales_items`.`item_unit_price` - `sales_items`.`discount`) END';
-
- $sale_cost = 'SUM(`sales_items`.`item_cost_price` * `sales_items`.`quantity_purchased`)';
-
- $tax = 'IFNULL(SUM(`sales_items_taxes`.`tax`), 0)';
- $sales_tax = 'IFNULL(SUM(`sales_items_taxes`.`sales_tax`), 0)';
- $internal_tax = 'IFNULL(SUM(`sales_items_taxes`.`internal_tax`), 0)';
- $cash_adjustment = 'IFNULL(SUM(`payments`.`sale_cash_adjustment`), 0)';
-
- $sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax";
- $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
-
- $this->create_temp_table_sales_items_taxes_data($where);
-
- $builder = $this->db->table('sales_items AS sales_items');
-
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(DISTINCT `' . $db_prefix . 'sales`.`sale_id`) AS count');
- }
- else
- {
- $builder->select([
- '`' . $db_prefix . 'sales`.`sale_id` AS sale_id',
- 'MAX(DATE(`' . $db_prefix . 'sales`.`sale_time`)) AS sale_date',
- 'MAX(`' . $db_prefix . 'sales`.`sale_time`) AS sale_time',
- 'MAX(`' . $db_prefix . 'sales`.`invoice_number`) AS invoice_number',
- 'MAX(`' . $db_prefix . 'sales`.`quote_number`) AS quote_number',
- 'SUM(`sales_items`.`quantity_purchased`) AS items_purchased',
- 'MAX(CONCAT(`customer_p`.`first_name`, " ", `customer_p`.`last_name`)) AS customer_name',
- 'MAX(`customer`.`company_name`) AS company_name',
- $sale_subtotal . ' AS subtotal',
- $tax . ' AS tax',
- $sale_total . ' AS total',
- $sale_cost . ' AS cost',
- '(' . $sale_total . ' - ' . $sale_cost . ') AS profit',
- $sale_total . ' AS amount_due',
- 'MAX(`payments`.`sale_payment_amount`) AS amount_tendered',
- '(MAX(`payments`.`sale_payment_amount`)) - (' . $sale_total . ') AS change_due',
- 'MAX(`payments`.`payment_type`) AS payment_type'
- ], false);
- }
-
- $builder->join('sales', '`sales_items`.`sale_id` = `' . $db_prefix . 'sales`.`sale_id`', 'inner');
- $builder->join('people AS customer_p', '`' . $db_prefix . 'sales`.`customer_id` = `customer_p`.`person_id`', 'LEFT');
- $builder->join('customers AS customer', '`' . $db_prefix . 'sales`.`customer_id` = `customer`.`person_id`', 'LEFT');
- $builder->join('sales_payments_temp AS payments', '`' . $db_prefix . 'sales`.`sale_id` = `payments`.`sale_id`', 'LEFT OUTER');
- $builder->join(
- 'sales_items_taxes_temp AS sales_items_taxes',
- 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
- 'LEFT OUTER');
-
- $builder->where($where);
-
- $this->add_filters_to_query($search, $filters, $builder);
-
- //get_found_rows
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
-
- $builder->groupBy('sales.sale_id');
-
- //order by sale time by default
- $builder->orderBy($sort, $order);
-
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
-
- return $builder->get();
- }
-
- /**
- * Get the payment summary for the takings (sales/manage) view
- */
- public function get_payments_summary(string $search, array $filters): array
- {
- $config = config(OSPOS::class)->settings;
-
- // get payment summary
- $builder = $this->db->table('sales AS sales');
- $builder->select('payment_type, COUNT(payment_amount) AS count, SUM(payment_amount - cash_refund) AS payment_amount');
- $builder->join('sales_payments', 'sales_payments.sale_id = sales.sale_id');
- $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id', 'LEFT');
- $builder->join('customers AS customer', 'sales.customer_id = customer.person_id', 'LEFT');
-
- //TODO: This needs to be replaced with Ternary notation
- if(empty($config['date_or_time_format'])) //TODO: duplicated code. We should think about refactoring out a method.
- {
- $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
- }
- else
- {
- $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
- }
-
- if(!empty($search)) //TODO: duplicated code. We should think about refactoring out a method.
- {
- if($filters['is_valid_receipt'])
- {
- $pieces = explode(' ',$search);
- $builder->where('sales.sale_id', $pieces[1]);
- }
- else
- {
- $builder->groupStart();
- $builder->like('customer_p.last_name', $search); // customer last name
- $builder->orLike('customer_p.first_name', $search); // customer first name
- $builder->orLike('CONCAT(customer_p.first_name, " ", customer_p.last_name)', $search); // customer first and last name
- $builder->orLike('customer.company_name', $search); // customer company name
- $builder->groupEnd();
- }
- }
-
- //TODO: This needs to be converted to a switch statement
- if($filters['sale_type'] == 'sales') //TODO: we need to think about refactoring this block to a switch statement.
- {
- $builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount > 0');
- }
- elseif($filters['sale_type'] == 'quotes')
- {
- $builder->where('sales.sale_status = ' . SUSPENDED . ' AND sales.quote_number IS NOT NULL');
- }
- elseif($filters['sale_type'] == 'returns')
- {
- $builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount < 0');
- }
- elseif($filters['sale_type'] == 'all')
- {
- $builder->where('sales.sale_status = ' . COMPLETED);
- }
-
- //TODO: Avoid the double negatives
- if($filters['only_invoices'])
- {
- $builder->where('invoice_number IS NOT NULL');
- }
-
- if($filters['only_cash'])
- {
- $builder->like('payment_type', lang('Sales.cash'));
- }
-
- if($filters['only_due'])
- {
- $builder->like('payment_type', lang('Sales.due'));
- }
-
- if($filters['only_check'])
- {
- $builder->like('payment_type', lang('Sales.check'));
- }
-
- if($filters['only_creditcard'])
- {
- $builder->like('payment_type', lang('Sales.credit'));
- }
-
- $builder->groupBy('payment_type');
-
- $payments = $builder->get()->getResultArray();
-
- // consider Gift Card as only one type of payment and do not show "Gift Card: 1, Gift Card: 2, etc." in the total
- $gift_card_count = 0;
- $gift_card_amount = 0;
-
- foreach($payments as $key => $payment)
- {
- if(strstr($payment['payment_type'], lang('Sales.giftcard')))
- {
- $gift_card_count += $payment['count'];
- $gift_card_amount += $payment['payment_amount'];
-
- //remove the "Gift Card: 1", "Gift Card: 2", etc. payment string
- unset($payments[$key]);
- }
- }
-
- if($gift_card_count > 0)
- {
- $payments[] = ['payment_type' => lang('Sales.giftcard'), 'count' => $gift_card_count, 'payment_amount' => $gift_card_amount];
- }
-
- return $payments;
- }
-
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('sales');
-
- return $builder->countAllResults();
- }
-
- /**
- * Gets search suggestions
- */
- public function get_search_suggestions(string $search, int $limit = 25): array //TODO: $limit is never used.
- {
- $suggestions = [];
-
- if(!$this->is_valid_receipt($search))
- {
- $builder = $this->db->table('sales');
- $builder->distinct()->select('first_name, last_name');
- $builder->join('people', 'people.person_id = sales.customer_id');
- $builder->like('last_name', $search);
- $builder->orLike('first_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
- $builder->orLike('company_name', $search);
- $builder->orderBy('last_name', 'asc');
-
- foreach($builder->get()->getResultArray() as $result)
- {
- $suggestions[] = ['label' => $result['first_name'] . ' ' . $result['last_name']];
- }
- }
- else
- {
- $suggestions[] = ['label' => $search];
- }
-
- return $suggestions;
- }
-
- /**
- * Gets total of invoice rows
- */
- public function get_invoice_count(): int
- {
- $builder = $this->db->table('sales');
- $builder->where('invoice_number IS NOT NULL');
-
- return $builder->countAllResults();
- }
-
- /**
- * Gets sale by invoice number
- */
- public function get_sale_by_invoice_number(string $invoice_number): ResultInterface
- {
- $builder = $this->db->table('sales');
- $builder->where('invoice_number', $invoice_number);
-
- return $builder->get();
- }
-
- /**
- * @param string $year
- * @param int $start_from
- * @return int
- */
- public function get_invoice_number_for_year(string $year = '', int $start_from = 0): int
- {
- return $this->get_number_for_year('invoice_number', $year, $start_from);
- }
-
- /**
- * @param string $year
- * @param int $start_from
- * @return int
- */
- public function get_quote_number_for_year(string $year = '', int $start_from = 0): int
- {
- return $this->get_number_for_year('quote_number', $year, $start_from);
- }
-
- /**
- * Gets invoice number by year
- */
- private function get_number_for_year(string $field, string $year = '', int $start_from = 0): int
- {
- $year = $year == '' ? date('Y') : $year;
-
- $builder = $this->db->table('sales');
- $builder->select('COUNT( 1 ) AS number_year');
- $builder->where('DATE_FORMAT(sale_time, "%Y" ) = ', $year);
- $builder->where("$field IS NOT NULL");
- $result = $builder->get()->getRowArray();
-
- return ($start_from + $result['number_year']);
- }
-
- /**
- * Checks if valid receipt
- */
- public function is_valid_receipt(string &$receipt_sale_id): bool //TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int.
- {
- $config = config(OSPOS::class)->settings;
-
- if(!empty($receipt_sale_id))
- {
- //POS #
- $pieces = explode(' ', $receipt_sale_id);
-
- if(count($pieces) == 2 && preg_match('/(POS)/i', $pieces[0]))
- {
- return $this->exists($pieces[1]);
- }
- elseif($config['invoice_enable'])
- {
- $sale_info = $this->get_sale_by_invoice_number($receipt_sale_id);
-
- if($sale_info->getNumRows() > 0)
- {
- $receipt_sale_id = 'POS ' . $sale_info->getRow()->sale_id;
-
- return true;
- }
- }
- }
-
- return false;
- }
-
- /**
- * Checks if sale exists
- */
- public function exists(int $sale_id): bool
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Update sale
- */
- public function update($sale_id = null, $sale_data = null): bool
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
- $update_data = $sale_data;
- unset($update_data['payments']);
- $success = $builder->update($update_data);
-
- //touch payment only if update sale is successful and there is a payments object otherwise the result would be to delete all the payments associated to the sale
- if($success && !empty($sale_data['payments']))
- {
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- $builder = $this->db->table('sales_payments');
-
- // add new payments
- foreach($sale_data['payments'] as $payment)
- {
- $payment_id = $payment['payment_id'];
- $payment_type = $payment['payment_type'];
- $payment_amount = $payment['payment_amount'];
- $cash_refund = $payment['cash_refund'];
- $cash_adjustment = $payment['cash_adjustment'];
- $employee_id = $payment['employee_id'];
-
- if($payment_id == NEW_ENTRY && $payment_amount != 0)
- {
- // Add a new payment transaction
- $sales_payments_data = [
- 'sale_id' => $sale_id,
- 'payment_type' => $payment_type,
- 'payment_amount' => $payment_amount,
- 'cash_refund' => $cash_refund,
- 'cash_adjustment' => $cash_adjustment,
- 'employee_id' => $employee_id
- ];
- $success = $builder->insert($sales_payments_data);
- }
- elseif($payment_id != NEW_ENTRY)
- {
- if($payment_amount != 0)
- {
- // Update existing payment transactions (payment_type only)
- $sales_payments_data = [
- 'payment_type' => $payment_type,
- 'payment_amount' => $payment_amount,
- 'cash_refund' => $cash_refund,
- 'cash_adjustment' => $cash_adjustment
- ];
-
- $builder->where('payment_id', $payment_id);
- $success = $builder->update($sales_payments_data);
- }
- else
- {
- // Remove existing payment transactions with a payment amount of zero
- $success = $builder->delete(['payment_id' => $payment_id]);
- }
- }
- }
-
- $this->db->transComplete();
- $success &= $this->db->transStatus();
- }
-
- return $success;
- }
-
- /**
- * Save the sale information after the sales is complete but before the final document is printed
- * The sales_taxes variable needs to be initialized to an empty array before calling
- * @throws ReflectionException
- */
- public function save_value(int $sale_id, string &$sale_status, array &$items, int $customer_id, int $employee_id, string $comment, ?string $invoice_number,
- ?string $work_order_number, ?string $quote_number, int $sale_type, ?array $payments, ?int $dinner_table_id, ?array &$sales_taxes): int //TODO: this method returns the sale_id but the override is expecting it to return a bool. The signature needs to be reworked. Generally when there are more than 3 maybe 4 parameters, there's a good chance that an object needs to be passed rather than so many params.
- {
- $config = config(OSPOS::class)->settings;
- $attribute = model(Attribute::class);
- $customer = model(Customer::class);
- $giftcard = model(Giftcard::class);
- $inventory = model('Inventory');
- $item = model(Item::class);
-
- $item_quantity = model(Item_quantity::class);
-
- if($sale_id != NEW_ENTRY)
- {
- $this->clear_suspended_sale_detail($sale_id);
- }
-
- if(count($items) == 0) //TODO: ===
- {
- return -1; //TODO: Replace -1 with a constant
- }
-
- $sales_data = [
- 'sale_time' => date('Y-m-d H:i:s'),
- 'customer_id' => $customer->exists($customer_id) ? $customer_id : null,
- 'employee_id' => $employee_id,
- 'comment' => $comment,
- 'sale_status' => $sale_status,
- 'invoice_number' => $invoice_number,
- 'quote_number' => $quote_number,
- 'work_order_number'=> $work_order_number,
- 'dinner_table_id' => $dinner_table_id,
- 'sale_type' => $sale_type
- ];
-
- // Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
-
- if($sale_id == NEW_ENTRY)
- {
- $builder = $this->db->table('sales');
- $builder->insert($sales_data);
- $sale_id = $this->db->insertID();
- }
- else
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
- $builder->update($sales_data);
- }
-
- $total_amount = 0;
- $total_amount_used = 0;
-
- foreach($payments as $payment_id => $payment)
- {
- if(!empty(strstr($payment['payment_type'], lang('Sales.giftcard'))))
- {
- // We have a gift card, and we have to deduct the used value from the total value of the card.
- $splitpayment = explode( ':', $payment['payment_type'] ); //TODO: this variable doesn't follow our naming conventions. Probably should be refactored to split_payment.
- $cur_giftcard_value = $giftcard->get_giftcard_value( $splitpayment[1] ); //TODO: this should be refactored to $current_giftcard_value
- $giftcard->update_giftcard_value( $splitpayment[1], $cur_giftcard_value - $payment['payment_amount'] );
- }
- elseif(!empty(strstr($payment['payment_type'], lang('Sales.rewards'))))
- {
- $cur_rewards_value = $customer->get_info($customer_id)->points;
- $customer->update_reward_points_value($customer_id, $cur_rewards_value - $payment['payment_amount'] );
- $total_amount_used = floatval($total_amount_used) + floatval($payment['payment_amount']);
- }
-
- $sales_payments_data = [
- 'sale_id' => $sale_id,
- 'payment_type' => $payment['payment_type'],
- 'payment_amount' => $payment['payment_amount'],
- 'cash_refund' => $payment['cash_refund'],
- 'cash_adjustment' => $payment['cash_adjustment'],
- 'employee_id' => $employee_id
- ];
-
- $builder = $this->db->table('sales_payments');
- $builder->insert($sales_payments_data);
-
- $total_amount = floatval($total_amount) + floatval($payment['payment_amount']) - floatval($payment['cash_refund']);
- }
-
- $this->save_customer_rewards($customer_id, $sale_id, $total_amount, $total_amount_used);
-
- $customer = $customer->get_info($customer_id);
-
- foreach($items as $line => $item_data)
- {
- $cur_item_info = $item->get_info($item_data['item_id']);
-
- if($item_data['price'] == 0.00)
- {
- $item_data['discount'] = 0.00;
- }
-
- $sales_items_data = [
- 'sale_id' => $sale_id,
- 'item_id' => $item_data['item_id'],
- 'line' => $item_data['line'],
- 'description' => character_limiter($item_data['description'], 255),
- 'serialnumber' => character_limiter($item_data['serialnumber'], 30),
- 'quantity_purchased' => $item_data['quantity'],
- 'discount' => $item_data['discount'],
- 'discount_type' => $item_data['discount_type'],
- 'item_cost_price' => $item_data['cost_price'],
- 'item_unit_price' => $item_data['price'],
- 'item_location' => $item_data['item_location'],
- 'print_option' => $item_data['print_option']
- ];
-
- $builder = $this->db->table('sales_items');
- $builder->insert($sales_items_data);
-
- if($cur_item_info->stock_type == HAS_STOCK && $sale_status == COMPLETED) //TODO: === ?
- {
- // Update stock quantity if item type is a standard stock item and the sale is a standard sale
- $item_quantity_data = $item_quantity->get_item_quantity($item_data['item_id'], $item_data['item_location']);
-
- $item_quantity->save_value([
- 'quantity' => $item_quantity_data->quantity - $item_data['quantity'],
- 'item_id' => $item_data['item_id'],
- 'location_id' => $item_data['item_location']],
- $item_data['item_id'],
- $item_data['item_location']
- );
-
- // if an items was deleted but later returned it's restored with this rule
- if($item_data['quantity'] < 0)
- {
- $item->undelete($item_data['item_id']);
- }
-
- // Inventory Count Details
- $sale_remarks = 'POS ' . $sale_id; //TODO: Use string interpolation here.
- $inv_data = [
- 'trans_date' => date('Y-m-d H:i:s'),
- 'trans_items' => $item_data['item_id'],
- 'trans_user' => $employee_id,
- 'trans_location' => $item_data['item_location'],
- 'trans_comment' => $sale_remarks,
- 'trans_inventory' => -$item_data['quantity']
- ];
-
- $inventory->insert($inv_data, false);
- }
-
- $attribute->copy_attribute_links($item_data['item_id'], 'sale_id', $sale_id);
- }
-
- if($customer_id == NEW_ENTRY || $customer->taxable)
- {
- $this->save_sales_tax($sale_id, $sales_taxes[0]);
- $this->save_sales_items_taxes($sale_id, $sales_taxes[1]);
- }
-
- if($config['dinner_table_enable'])
- {
- $dinner_table = model(Dinner_table::class);
- if($sale_status == COMPLETED) //TODO: === ?
- {
- $dinner_table->release($dinner_table_id);
- }
- else
- {
- $dinner_table->occupy($dinner_table_id);
- }
- }
-
- $this->db->transComplete();
-
- return $this->db->transStatus() ? $sale_id : -1;
- }
-
- /**
- * Saves sale tax
- */
- public function save_sales_tax(int $sale_id, array $sales_taxes): void //TODO: should we return the result of the insert here as a bool?
- {
- $builder = $this->db->table('sales_taxes');
-
- foreach($sales_taxes as $line => $sales_tax)
- {
- $sales_tax['sale_id'] = $sale_id;
- $builder->insert($sales_tax);
- }
- }
-
- /**
- * Apply customer sales tax if the customer sales tax is enabled
- * The original tax is still supported if the user configures it,
- * but it won't make sense unless it's used exclusively for the purpose
- * of VAT tax which becomes a price component. VAT taxes must still be reported
- * as a separate tax entry on the invoice.
- */
- public function save_sales_items_taxes(int $sale_id, array $sales_item_taxes): void
- {
- $builder = $this->db->table('sales_items_taxes');
-
- foreach($sales_item_taxes as $line => $tax_item)
- {
- $sales_items_taxes = [
- 'sale_id' => $sale_id,
- 'item_id' => $tax_item['item_id'],
- 'line' => $tax_item['line'],
- 'name' => $tax_item['name'],
- 'percent' => $tax_item['percent'],
- 'tax_type' => $tax_item['tax_type'],
- 'rounding_code' => $tax_item['rounding_code'],
- 'cascade_sequence' => $tax_item['cascade_sequence'],
- 'item_tax_amount' => $tax_item['item_tax_amount'],
- 'sales_tax_code_id' => $tax_item['sales_tax_code_id'],
- 'tax_category_id' => $tax_item['tax_category_id'],
- 'jurisdiction_id' => $tax_item['jurisdiction_id']
- ];
-
- $builder->insert($sales_items_taxes);
- }
- }
-
- /**
- * Return the taxes that were charged
- */
- public function get_sales_taxes(int $sale_id): array
- {
- $builder = $this->db->table('sales_taxes');
- $builder->where('sale_id', $sale_id);
- $builder->orderBy('print_sequence', 'asc');
-
- $query = $builder->get();
-
- return $query->getResultArray();
- }
-
- /**
- * Return the taxes applied to a sale for a particular item
- */
- public function get_sales_item_taxes(int $sale_id, int $item_id): array
- {
- $builder = $this->db->table('sales_items_taxes');
- $builder->select('item_id, name, percent');
- $builder->where('sale_id',$sale_id);
- $builder->where('item_id',$item_id);
-
- //return an array of taxes for an item
- return $builder->get()->getResultArray();
- }
-
- /**
- * Deletes list of sales
- * @throws ReflectionException
- */
- public function delete_list(array $sale_ids, int $employee_id, bool $update_inventory = true): bool
- {
- $result = true;
-
- foreach($sale_ids as $sale_id)
- {
- $result &= $this->delete($sale_id, false, $update_inventory, $employee_id);
- }
-
- return $result;
- }
-
- /**
- * Restores list of sales
- */
- public function restore_list(array $sale_ids, int $employee_id, bool $update_inventory = true): bool //TODO: $employee_id and $update_inventory are never used in the function.
- {
- foreach($sale_ids as $sale_id)
- {
- $this->update_sale_status($sale_id, SUSPENDED);
- }
-
- return true;
- }
-
- /**
- * Delete sale. Hard deletes are not supported for sales transactions.
- * When a sale is "deleted" it is simply changed to a status of canceled.
- * However, if applicable the inventory still needs to be updated
- * @throws ReflectionException
- */
- public function delete($sale_id = null, bool $purge = false, bool $update_inventory = true, $employee_id = null): bool
- {
- // start a transaction to assure data integrity
- $this->db->transStart();
-
- $sale_status = $this->get_sale_status($sale_id);
-
- if($update_inventory && $sale_status == COMPLETED)
- {
- // defect, not all item deletions will be undone??
- // get array with all the items involved in the sale to update the inventory tracking
- $inventory = model('Inventory');
- $item = model(Item::class);
- $item_quantity = model(Item_quantity::class);
-
- $items = $this->get_sale_items($sale_id)->getResultArray();
-
- foreach($items as $item_data)
- {
- $cur_item_info = $item->get_info($item_data['item_id']);
-
- if($cur_item_info->stock_type == HAS_STOCK)
- {
- // create query to update inventory tracking
- $inv_data = [
- 'trans_date' => date('Y-m-d H:i:s'),
- 'trans_items' => $item_data['item_id'],
- 'trans_user' => $employee_id,
- 'trans_comment' => 'Deleting sale ' . $sale_id,
- 'trans_location' => $item_data['item_location'],
- 'trans_inventory' => $item_data['quantity_purchased']
- ];
- // update inventory
- $inventory->insert($inv_data, false);
-
- // update quantities
- $item_quantity->change_quantity($item_data['item_id'], $item_data['item_location'], $item_data['quantity_purchased']);
- }
- }
- }
-
- $this->update_sale_status($sale_id, CANCELED);
-
- // execute transaction
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- /**
- * Gets sale item
- */
- public function get_sale_items(int $sale_id): ResultInterface
- {
- $builder = $this->db->table('sales_items');
- $builder->where('sale_id', $sale_id);
-
- return $builder->get();
- }
-
- /**
- * Used by the invoice and receipt programs
- */
- public function get_sale_items_ordered(int $sale_id): ResultInterface
- {
- $config = config(OSPOS::class)->settings;
- $item = model(Item::class);
-
- $builder = $this->db->table('sales_items AS sales_items');
- $builder->select('
- sales_items.sale_id,
- sales_items.item_id,
- sales_items.description,
- serialnumber,
- line,
- quantity_purchased,
- item_cost_price,
- item_unit_price,
- discount,
- discount_type,
- item_location,
- print_option,
- ' . $item->get_item_name('name') . ',
- category,
- item_type,
- stock_type');
- $builder->join('items AS items', 'sales_items.item_id = items.item_id');
- $builder->where('sales_items.sale_id', $sale_id);
-
- // Entry sequence (this will render kits in the expected sequence)
- if($config['line_sequence'] == '0') //TODO: Replace these with constants and this should be converted to a switch.
- {
- $builder->orderBy('line', 'asc');
- }
- // Group by Stock Type (nonstock first - type 1, stock next - type 0)
- elseif($config['line_sequence'] == '1')
- {
- $builder->orderBy('stock_type', 'desc');
- $builder->orderBy('sales_items.description', 'asc');
- $builder->orderBy('items.name', 'asc');
- $builder->orderBy('items.qty_per_pack', 'asc');
- }
- // Group by Item Category
- elseif($config['line_sequence'] == '2')
- {
- $builder->orderBy('category', 'asc');
- $builder->orderBy('sales_items.description', 'asc');
- $builder->orderBy('items.name', 'asc');
- $builder->orderBy('items.qty_per_pack', 'asc');
- }
- // Group by entry sequence in descending sequence (the Standard)
- else
- {
- $builder->orderBy('line', 'desc');
- }
-
- return $builder->get();
- }
-
- /**
- * Gets sale payments
- */
- public function get_sale_payments(int $sale_id): ResultInterface
- {
- $builder = $this->db->table('sales_payments');
- $builder->where('sale_id', $sale_id);
-
- return $builder->get();
- }
-
- /**
- * Gets sale payment options
- */
- public function get_payment_options(bool $giftcard = true, bool $reward_points = true): array
- {
- $payments = get_payment_options();
-
- if($giftcard)
- {
- $payments[lang('Sales.giftcard')] = lang('Sales.giftcard');
- }
-
- if($reward_points)
- {
- $payments[lang('Sales.rewards')] = lang('Sales.rewards');
- }
- $sale_lib = new Sale_lib();
- if($sale_lib->get_mode() == 'sale_work_order')
- {
- $payments[lang('Sales.cash_deposit')] = lang('Sales.cash_deposit');
- $payments[lang('Sales.credit_deposit')] = lang('Sales.credit_deposit');
- }
-
- return $payments;
- }
-
- /**
- * Gets sale customer name
- */
- public function get_customer(int $sale_id): object
- {
- $customer = model(Customer::class);
-
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- return $customer->get_info($builder->get()->getRow()->customer_id);
- }
-
- /**
- * Gets sale employee name
- */
- public function get_employee(int $sale_id): object
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- $employee = model(Employee::class);
-
- return $employee->get_info($builder->get()->getRow()->employee_id);
- }
-
- /**
- * Checks if quote number exists
- */
- public function check_quote_number_exists(string $quote_number, string $sale_id = ''): bool
- {
- $builder = $this->db->table('sales');
- $builder->where('quote_number', $quote_number);
-
- if(!empty($sale_id))
- {
- $builder->where('sale_id !=', $sale_id);
- }
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Checks if invoice number exists
- */
- public function check_invoice_number_exists(string $invoice_number, string $sale_id = ''): bool
- {
- $builder = $this->db->table('sales');
- $builder->where('invoice_number', $invoice_number);
-
- if(!empty($sale_id))
- {
- $builder->where('sale_id !=', $sale_id);
- }
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Checks if work order number exists
- */
- public function check_work_order_number_exists(string $work_order_number, string $sale_id = ''): bool
- {
- $builder = $this->db->table('sales');
- $builder->where('invoice_number', $work_order_number);
- if(!empty($sale_id))
- {
- $builder->where('sale_id !=', $sale_id);
- }
-
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
-
- /**
- * Gets Giftcard value
- */
- public function get_giftcard_value(string $giftcardNumber): float
- {
- $giftcard = model(Giftcard::class);
-
- if(!$giftcard->exists($giftcard->get_giftcard_id($giftcardNumber))) //TODO: camelCase is used here for the variable name but we are using _ everywhere else. CI4 moved to camelCase... we should pick one and do that.
- {
- return 0;
- }
-
- $builder = $this->db->table('giftcards');
- $builder->where('giftcard_number', $giftcardNumber);
-
- return $builder->get()->getRow()->value;
- }
-
- /**
- * Creates sales temporary dimensional table
- * We create a temp table that allows us to do easy report/sales queries
- */
- public function create_temp_table(array $inputs): void
- {
- $config = config(OSPOS::class)->settings;
-
- if(empty($inputs['sale_id']))
- {
- if(empty($config['date_or_time_format'])) //TODO: This needs to be replaced with Ternary notation
- {
- $where = 'DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
- }
- else
- {
- $where = 'sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
- }
- }
- else
- {
- $where = 'sales.sale_id = ' . $this->db->escape($inputs['sale_id']);
- }
-
- $decimals = totals_decimals();
-
- $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
- . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
- . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
-
- $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)';
-
- $tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)';
- $sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
- $internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
- $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
-
- if($config['tax_included'])
- {
- $sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
- $sale_subtotal = "$sale_total - $internal_tax";
- }
- else
- {
- $sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax + $cash_adjustment";
- $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
- }
-
- // create a temporary table to contain all the sum of taxes per sale item
- $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_taxes_temp') .
- ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY
- (
- SELECT sales_items_taxes.sale_id AS sale_id,
- sales_items_taxes.item_id AS item_id,
- sales_items_taxes.line AS line,
- SUM(ROUND(sales_items_taxes.item_tax_amount, ' . $decimals . ')) AS tax,
- SUM(ROUND(CASE WHEN sales_items_taxes.tax_type = 0 THEN sales_items_taxes.item_tax_amount ELSE 0 END, ' . $decimals . ')) AS internal_tax,
- SUM(ROUND(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END, ' . $decimals . ')) AS sales_tax
- FROM ' . $this->db->prefixTable('sales_items_taxes') . ' AS sales_items_taxes
- INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
- ON sales.sale_id = sales_items_taxes.sale_id
- INNER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items
- ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line
- WHERE ' . $where . '
- GROUP BY sale_id, item_id, line
- )';
-
- $this->db->query($sql);
-
- // create a temporary table to contain all the payment types and amount
- $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_payments_temp') .
- ' (PRIMARY KEY(sale_id), INDEX(sale_id))
- (
- SELECT payments.sale_id AS sale_id,
- SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
- SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
- SUM(payments.cash_refund) AS sale_cash_refund,
- GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
- FROM ' . $this->db->prefixTable('sales_payments') . ' AS payments
- INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
- ON sales.sale_id = payments.sale_id
- WHERE ' . $where . '
- GROUP BY payments.sale_id
- )';
-
- $this->db->query($sql);
- $item = model(Item::class);
- $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp') .
- ' (INDEX(sale_date), INDEX(sale_time), INDEX(sale_id))
- (
- SELECT
- MAX(DATE(sales.sale_time)) AS sale_date,
- MAX(sales.sale_time) AS sale_time,
- sales.sale_id AS sale_id,
- MAX(sales.sale_status) AS sale_status,
- MAX(sales.sale_type) AS sale_type,
- MAX(sales.comment) AS comment,
- MAX(sales.invoice_number) AS invoice_number,
- MAX(sales.quote_number) AS quote_number,
- MAX(sales.customer_id) AS customer_id,
- MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name,
- MAX(customer_p.first_name) AS customer_first_name,
- MAX(customer_p.last_name) AS customer_last_name,
- MAX(customer_p.email) AS customer_email,
- MAX(customer_p.comments) AS customer_comments,
- MAX(customer.company_name) AS customer_company_name,
- MAX(sales.employee_id) AS employee_id,
- MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
- items.item_id AS item_id,
- MAX(' . $item->get_item_name() . ') AS name,
- MAX(items.item_number) AS item_number,
- MAX(items.category) AS category,
- MAX(items.supplier_id) AS supplier_id,
- MAX(sales_items.quantity_purchased) AS quantity_purchased,
- MAX(sales_items.item_cost_price) AS item_cost_price,
- MAX(sales_items.item_unit_price) AS item_unit_price,
- MAX(sales_items.discount) AS discount,
- sales_items.discount_type AS discount_type,
- sales_items.line AS line,
- MAX(sales_items.serialnumber) AS serialnumber,
- MAX(sales_items.item_location) AS item_location,
- MAX(sales_items.description) AS description,
- MAX(payments.payment_type) AS payment_type,
- MAX(payments.sale_payment_amount) AS sale_payment_amount,
- ' . "
- $sale_subtotal AS subtotal,
- $tax AS tax,
- $sale_total AS total,
- $sale_cost AS cost,
- ($sale_subtotal - $sale_cost) AS profit
- " . '
- FROM ' . $this->db->prefixTable('sales_items') . ' AS sales_items
- INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
- ON sales_items.sale_id = sales.sale_id
- INNER JOIN ' . $this->db->prefixTable('items') . ' AS items
- ON sales_items.item_id = items.item_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('sales_payments_temp') . ' AS payments
- ON sales_items.sale_id = payments.sale_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('suppliers') . ' AS supplier
- ON items.supplier_id = supplier.person_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('people') . ' AS customer_p
- ON sales.customer_id = customer_p.person_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('customers') . ' AS customer
- ON sales.customer_id = customer.person_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('people') . ' AS employee
- ON sales.employee_id = employee.person_id
- LEFT OUTER JOIN ' . $this->db->prefixTable('sales_items_taxes_temp') . ' AS sales_items_taxes
- ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line
- WHERE ' . $where . '
- GROUP BY sale_id, item_id, line
- )';
-
- $this->db->query($sql);
- }
-
- /**
- * Retrieves all sales that are in a suspended state
- */
- public function get_all_suspended(int $customer_id = null): array
- {
- if($customer_id == NEW_ENTRY)
- {
- $query = $this->db->query("SELECT sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' THEN quote_number WHEN sale_type = '".SALE_TYPE_WORK_ORDER."' THEN work_order_number else sale_id end as doc_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, employee_id, comment FROM "
- . $this->db->prefixTable('sales') . ' where sale_status = ' . SUSPENDED);
- }
- else
- {
- $query = $this->db->query("SELECT sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' THEN quote_number WHEN sale_type = '".SALE_TYPE_WORK_ORDER."' THEN work_order_number else sale_id end as doc_id, sale_status, sale_time, dinner_table_id, customer_id, employee_id, comment FROM "
- . $this->db->prefixTable('sales') . ' where sale_status = '. SUSPENDED .' AND customer_id = ' . $customer_id);
- }
-
- return $query->getResultArray() ?: [];
- }
-
- /**
- * Gets the dinner table for the selected sale
- */
- public function get_dinner_table(int $sale_id) //TODO: this is returning null or the table_id. We can keep it this way but multiple return types can't be declared until PHP 8.x
- {
- if($sale_id == NEW_ENTRY)
- {
- return null;
- }
-
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- return $builder->get()->getRow()->dinner_table_id;
- }
-
- /**
- * Gets the sale type for the selected sale
- */
- public function get_sale_type(int $sale_id)
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- return $builder->get()->getRow()->sale_type;
- }
-
- /**
- * Gets the sale status for the selected sale
- */
- public function get_sale_status(int $sale_id): int
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- return $builder->get()->getRow()->sale_status;
- }
-
- /**
- * @param int $sale_id
- * @param int $sale_status
- * @return void
- */
- public function update_sale_status(int $sale_id, int $sale_status): void
- {
- $builder = $this->db->table('sales');
-
- $builder->where('sale_id', $sale_id);
- $builder->update(['sale_status' => $sale_status]);
- }
-
- /**
- * Gets the quote_number for the selected sale
- */
- public function get_quote_number(int $sale_id): ?string
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- $row = $builder->get()->getRow();
-
- if($row != null)
- {
- return $row->quote_number;
- }
-
- return null;
- }
-
- /**
- * Gets the work order number for the selected sale
- */
- public function get_work_order_number(int $sale_id): ?string
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- $row = $builder->get()->getRow();
-
- if($row != null) //TODO: === ?
- {
- return $row->work_order_number;
- }
-
- return null;
- }
-
- /**
- * Gets the quote_number for the selected sale
- */
- public function get_comment(int $sale_id): ?string
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
-
- $row = $builder->get()->getRow();
-
- if($row != null) //TODO: === ?
- {
- return $row->comment;
- }
-
- return null;
- }
-
- /**
- * Gets total of suspended invoices rows
- */
- public function get_suspended_invoice_count(): int
- {
- $builder = $this->db->table('sales');
- $builder->where('invoice_number IS NOT NULL');
- $builder->where('sale_status', SUSPENDED);
-
- return $builder->countAllResults();
- }
-
- /**
- * Removes a selected sale from the sales table.
- * This function should only be called for suspended sales that are being restored to the current cart
- */
- public function delete_suspended_sale(int $sale_id): bool
- {
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
- $config = config(OSPOS::class)->settings;
-
- if($config['dinner_table_enable'])
- {
- $dinner_table = model(Dinner_table::class);
- $dinner_table_id = $this->get_dinner_table($sale_id);
- $dinner_table->release($dinner_table_id);
- }
-
- $this->update_sale_status($sale_id, CANCELED);
-
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- /**
- * This clears the sales detail for a given sale_id before the detail is re-saved.
- * This allows us to reuse the same sale_id
- */
- public function clear_suspended_sale_detail(int $sale_id): bool
- {
- $this->db->transStart();
- $config = config(OSPOS::class)->settings;
-
- if($config['dinner_table_enable'])
- {
- $dinner_table = model(Dinner_table::class);
- $dinner_table_id = $this->get_dinner_table($sale_id);
- $dinner_table->release($dinner_table_id);
- }
-
- $builder = $this->db->table('sales_payments');
- $builder->delete(['sale_id' => $sale_id]);
-
- $builder = $this->db->table('sales_items_taxes');
- $builder->delete(['sale_id' => $sale_id]);
-
- $builder = $this->db->table('sales_items');
- $builder->delete(['sale_id' => $sale_id]);
-
- $builder = $this->db->table('sales_taxes');
- $builder->delete(['sale_id' => $sale_id]);
-
- $this->db->transComplete();
-
- return $this->db->transStatus();
- }
-
- /**
- * Gets suspended sale info
- */
- public function get_suspended_sale_info(int $sale_id): ResultInterface
- {
- $builder = $this->db->table('sales');
- $builder->where('sale_id', $sale_id);
- $builder->join('people', 'people.person_id = sales.customer_id', 'LEFT');
- $builder->where('sale_status', SUSPENDED);
-
- return $builder->get();
- }
-
- /**
- * @param int $customer_id
- * @param int $sale_id
- * @param float $total_amount
- * @param float $total_amount_used
- */
- private function save_customer_rewards(int $customer_id, int $sale_id, float $total_amount, float $total_amount_used): void
- {
- $config = config(OSPOS::class)->settings;
-
- if(!empty($customer_id) && $config['customer_reward_enable'])
- {
- $customer = model(Customer::class);
- $customer_rewards = model(Customer_rewards::class);
- $rewards = model(Rewards::class);
-
- $package_id = $customer->get_info($customer_id)->package_id;
-
- if(!empty($package_id))
- {
- $points_percent = $customer_rewards->get_points_percent($package_id);
- $points = $customer->get_info($customer_id)->points;
- $points = ($points == null ? 0 : $points);
- $points_percent = ($points_percent == null ? 0 : $points_percent);
- $total_amount_earned = ($total_amount * $points_percent / 100);
- $points = $points + $total_amount_earned;
-
- $customer->update_reward_points_value($customer_id, $points);
-
- $rewards_data = ['sale_id' => $sale_id, 'earned' => $total_amount_earned, 'used' => $total_amount_used];
-
- $rewards->save_value($rewards_data);
- }
- }
- }
-
- /**
- * Creates a temporary table to store the sales_payments data
- *
- * @param string $where
- * @return array
- */
- private function create_temp_table_sales_payments_data(string $where): void
- {
- $builder = $this->db->table('sales_payments AS payments');
- $builder->select([
- 'payments.sale_id',
- 'SUM(CASE WHEN `payments`.`cash_adjustment` = 0 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_payment_amount',
- 'SUM(CASE WHEN `payments`.`cash_adjustment` = 1 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_cash_adjustment',
- 'GROUP_CONCAT(CONCAT(`payments`.`payment_type`, " ", (`payments`.`payment_amount` - `payments`.`cash_refund`)) SEPARATOR ", ") AS payment_type'
- ]);
- $builder->join('sales', 'sales.sale_id = payments.sale_id', 'inner');
- $builder->where($where);
- $builder->groupBy('payments.sale_id');
-
- $sub_query = $builder->getCompiledSelect();
- log_message('error', $sub_query);
-
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS '
- . $this->db->prefixTable('sales_payments_temp')
- . ' (PRIMARY KEY(`sale_id`), INDEX(`sale_id`)) AS (' . $sub_query . ')');
- }
-
- /**
- * Temporary table to store the sales_items_taxes data
- *
- * @param string $where
- * @return \CodeIgniter\Database\BaseBuilder
- */
- private function create_temp_table_sales_items_taxes_data(string $where): void
- {
-
- $builder = $this->db->table('sales_items_taxes AS sales_items_taxes');
- $builder->select([
- 'sales_items_taxes.sale_id AS sale_id',
- 'sales_items_taxes.item_id AS item_id',
- 'sales_items_taxes.line AS line',
- 'SUM(sales_items_taxes.item_tax_amount) AS tax',
- 'SUM(CASE WHEN sales_items_taxes.tax_type = 0 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS internal_tax',
- 'SUM(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS sales_tax'
- ]);
- $builder->join('sales', 'sales.sale_id = sales_items_taxes.sale_id', 'inner');
- $builder->join('sales_items', 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line', 'inner');
- $builder->where($where);
- $builder->groupBy(['sale_id', 'item_id', 'line']);
- $sub_query = $builder->getCompiledSelect();
-
- $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS '
- . $this->db->prefixTable('sales_items_taxes_temp')
- . ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY AS (' . $sub_query . ')');
- }
-
- /**
- * @param string $search
- * @param array $filters
- * @param BaseBuilder $builder
- * @return void
- */
- private function add_filters_to_query(string $search, array $filters, BaseBuilder $builder): void
- {
- if(!empty($search)) //TODO: this is duplicated code. We should think about refactoring out a method
- {
- if($filters['is_valid_receipt'])
- {
- $pieces = explode(' ', $search);
- $builder->where('sales.sale_id', $pieces[1]);
- }
- else
- {
- $builder->groupStart();
- // customer last name
- $builder->like('customer_p.last_name', $search);
- // customer first name
- $builder->orLike('customer_p.first_name', $search);
- // customer first and last name
- $builder->orLike('CONCAT(customer_p.first_name, " ", customer_p.last_name)', $search);
- // customer company name
- $builder->orLike('customer.company_name', $search);
- $builder->groupEnd();
- }
- }
-
- if($filters['location_id'] != 'all')
- {
- $builder->where('sales_items.item_location', $filters['location_id']);
- }
-
- if($filters['selected_customer'] != false)
- {
- $sale_lib = new Sale_lib();
- $builder->where('sales.customer_id', $sale_lib->get_customer());
- }
-
-
- if($filters['only_invoices'])
- {
- $builder->where('sales.invoice_number IS NOT NULL');
- }
-
- if($filters['only_cash'])
- {
- $builder->groupStart();
- $builder->like('payments.payment_type', lang('Sales.cash'));
- $builder->orWhere('payments.payment_type IS NULL');
- $builder->groupEnd();
- }
-
- if($filters['only_creditcard'])
- {
- $builder->like('payments.payment_type', lang('Sales.credit'));
- }
-
- if($filters['only_due'])
- {
- $builder->like('payments.payment_type', lang('Sales.due'));
- }
-
- if($filters['only_check'])
- {
- $builder->like('payments.payment_type', lang('Sales.check'));
- }
- }
+ protected $table = 'sales';
+ protected $primaryKey = 'sale_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'sale_time',
+ 'customer_id',
+ 'employee_id',
+ 'comment',
+ 'quote_number',
+ 'sale_status',
+ 'invoice_number',
+ 'dinner_table_id',
+ 'work_order_number',
+ 'sale_type'
+ ];
+
+ public function __construct()
+ {
+ parent::__construct();
+ helper('text');
+ }
+
+ /**
+ * Get sale info
+ */
+ public function get_info(int $sale_id): ResultInterface
+ {
+ $config = config(OSPOS::class)->settings;
+ $this->create_temp_table (['sale_id' => $sale_id]);
+
+ $decimals = totals_decimals();
+ $sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
+ $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
+ $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
+ . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
+ . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
+
+ $sale_total = $config['tax_included']
+ ? "ROUND(SUM($sale_price), $decimals) + $cash_adjustment"
+ : "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
+
+ $sql = 'sales.sale_id AS sale_id,
+ MAX(DATE(sales.sale_time)) AS sale_date,
+ MAX(sales.sale_time) AS sale_time,
+ MAX(sales.comment) AS comment,
+ MAX(sales.sale_status) AS sale_status,
+ MAX(sales.invoice_number) AS invoice_number,
+ MAX(sales.quote_number) AS quote_number,
+ MAX(sales.employee_id) AS employee_id,
+ MAX(sales.customer_id) AS customer_id,
+ MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name,
+ MAX(customer_p.first_name) AS first_name,
+ MAX(customer_p.last_name) AS last_name,
+ MAX(customer_p.email) AS email,
+ MAX(customer_p.comments) AS comments,
+ MAX(IFnull(payments.sale_cash_adjustment, 0)) AS cash_adjustment,
+ MAX(IFnull(payments.sale_cash_refund, 0)) AS cash_refund,
+ ' . "
+ $sale_total AS amount_due,
+ MAX(IFnull(payments.sale_payment_amount, 0)) AS amount_tendered,
+ (MAX(payments.sale_payment_amount)) - ($sale_total) AS change_due,
+ " . '
+ MAX(payments.payment_type) AS payment_type';
+
+ $builder = $this->db->table('sales_items AS sales_items');
+ $builder->select($sql);
+
+ $builder->join('sales AS sales', 'sales_items.sale_id = sales.sale_id', 'inner');
+ $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id', 'LEFT');
+ $builder->join('customers AS customer', 'sales.customer_id = customer.person_id', 'LEFT');
+ $builder->join('sales_payments_temp AS payments', 'sales.sale_id = payments.sale_id', 'LEFT OUTER');
+ $builder->join('sales_items_taxes_temp AS sales_items_taxes',
+ 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
+ 'LEFT OUTER');
+
+ $builder->where('sales.sale_id', $sale_id);
+
+ $builder->groupBy('sales.sale_id');
+ $builder->orderBy('sales.sale_time', 'asc');
+
+ return $builder->get();
+ }
+
+ /**
+ * Get number of rows for the takings (sales/manage) view
+ */
+ public function get_found_rows(string $search, array $filters): int
+ {
+ return $this->search($search, $filters, 0, 0, 'sales.sale_time', 'desc', true);
+ }
+
+ /**
+ * Get the sales data for the takings (sales/manage) view
+ */
+ public function search(string $search, array $filters, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'sales.sale_time', ?string $order = 'desc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'sales.sale_time';
+ if($order == null) $order = 'desc';
+ if($count_only == null) $count_only = false;
+
+ $config = config(OSPOS::class)->settings;
+ $db_prefix = $this->db->getPrefix();
+ $decimals = totals_decimals();
+
+ //Only non-suspended records
+ $where = 'sales.sale_status = 0 AND ';
+ $where .= empty($config['date_or_time_format'])
+ ? 'DATE(' . $db_prefix . 'sales.sale_time) BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date'])
+ : 'sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date']));
+
+ $this->create_temp_table_sales_payments_data($where);
+
+ $sale_price = 'CASE WHEN `sales_items`.`discount_type` = ' . PERCENT
+ . " THEN `sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` - ROUND(`sales_items`.`quantity_purchased` * `sales_items`.`item_unit_price` * `sales_items`.`discount` / 100, $decimals) "
+ . 'ELSE `sales_items`.`quantity_purchased` * (`sales_items`.`item_unit_price` - `sales_items`.`discount`) END';
+
+ $sale_cost = 'SUM(`sales_items`.`item_cost_price` * `sales_items`.`quantity_purchased`)';
+
+ $tax = 'IFNULL(SUM(`sales_items_taxes`.`tax`), 0)';
+ $sales_tax = 'IFNULL(SUM(`sales_items_taxes`.`sales_tax`), 0)';
+ $internal_tax = 'IFNULL(SUM(`sales_items_taxes`.`internal_tax`), 0)';
+ $cash_adjustment = 'IFNULL(SUM(`payments`.`sale_cash_adjustment`), 0)';
+
+ $sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax";
+ $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
+
+ $this->create_temp_table_sales_items_taxes_data($where);
+
+ $builder = $this->db->table('sales_items AS sales_items');
+
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(DISTINCT `' . $db_prefix . 'sales`.`sale_id`) AS count');
+ }
+ else
+ {
+ $builder->select([
+ '`' . $db_prefix . 'sales`.`sale_id` AS sale_id',
+ 'MAX(DATE(`' . $db_prefix . 'sales`.`sale_time`)) AS sale_date',
+ 'MAX(`' . $db_prefix . 'sales`.`sale_time`) AS sale_time',
+ 'MAX(`' . $db_prefix . 'sales`.`invoice_number`) AS invoice_number',
+ 'MAX(`' . $db_prefix . 'sales`.`quote_number`) AS quote_number',
+ 'SUM(`sales_items`.`quantity_purchased`) AS items_purchased',
+ 'MAX(CONCAT(`customer_p`.`first_name`, " ", `customer_p`.`last_name`)) AS customer_name',
+ 'MAX(`customer`.`company_name`) AS company_name',
+ $sale_subtotal . ' AS subtotal',
+ $tax . ' AS tax',
+ $sale_total . ' AS total',
+ $sale_cost . ' AS cost',
+ '(' . $sale_total . ' - ' . $sale_cost . ') AS profit',
+ $sale_total . ' AS amount_due',
+ 'MAX(`payments`.`sale_payment_amount`) AS amount_tendered',
+ '(MAX(`payments`.`sale_payment_amount`)) - (' . $sale_total . ') AS change_due',
+ 'MAX(`payments`.`payment_type`) AS payment_type'
+ ], false);
+ }
+
+ $builder->join('sales', '`sales_items`.`sale_id` = `' . $db_prefix . 'sales`.`sale_id`', 'inner');
+ $builder->join('people AS customer_p', '`' . $db_prefix . 'sales`.`customer_id` = `customer_p`.`person_id`', 'LEFT');
+ $builder->join('customers AS customer', '`' . $db_prefix . 'sales`.`customer_id` = `customer`.`person_id`', 'LEFT');
+ $builder->join('sales_payments_temp AS payments', '`' . $db_prefix . 'sales`.`sale_id` = `payments`.`sale_id`', 'LEFT OUTER');
+ $builder->join(
+ 'sales_items_taxes_temp AS sales_items_taxes',
+ 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line',
+ 'LEFT OUTER');
+
+ $builder->where($where);
+
+ $this->add_filters_to_query($search, $filters, $builder);
+
+ //get_found_rows
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
+
+ $builder->groupBy('sales.sale_id');
+
+ //order by sale time by default
+ $builder->orderBy($sort, $order);
+
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Get the payment summary for the takings (sales/manage) view
+ */
+ public function get_payments_summary(string $search, array $filters): array
+ {
+ $config = config(OSPOS::class)->settings;
+
+ // get payment summary
+ $builder = $this->db->table('sales AS sales');
+ $builder->select('payment_type, COUNT(payment_amount) AS count, SUM(payment_amount - cash_refund) AS payment_amount');
+ $builder->join('sales_payments', 'sales_payments.sale_id = sales.sale_id');
+ $builder->join('people AS customer_p', 'sales.customer_id = customer_p.person_id', 'LEFT');
+ $builder->join('customers AS customer', 'sales.customer_id = customer.person_id', 'LEFT');
+
+ //TODO: This needs to be replaced with Ternary notation
+ if(empty($config['date_or_time_format'])) //TODO: duplicated code. We should think about refactoring out a method.
+ {
+ $builder->where('DATE(sales.sale_time) BETWEEN ' . $this->db->escape($filters['start_date']) . ' AND ' . $this->db->escape($filters['end_date']));
+ }
+ else
+ {
+ $builder->where('sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($filters['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($filters['end_date'])));
+ }
+
+ if(!empty($search)) //TODO: duplicated code. We should think about refactoring out a method.
+ {
+ if($filters['is_valid_receipt'])
+ {
+ $pieces = explode(' ',$search);
+ $builder->where('sales.sale_id', $pieces[1]);
+ }
+ else
+ {
+ $builder->groupStart();
+ $builder->like('customer_p.last_name', $search); // customer last name
+ $builder->orLike('customer_p.first_name', $search); // customer first name
+ $builder->orLike('CONCAT(customer_p.first_name, " ", customer_p.last_name)', $search); // customer first and last name
+ $builder->orLike('customer.company_name', $search); // customer company name
+ $builder->groupEnd();
+ }
+ }
+
+ //TODO: This needs to be converted to a switch statement
+ if($filters['sale_type'] == 'sales') //TODO: we need to think about refactoring this block to a switch statement.
+ {
+ $builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount > 0');
+ }
+ elseif($filters['sale_type'] == 'quotes')
+ {
+ $builder->where('sales.sale_status = ' . SUSPENDED . ' AND sales.quote_number IS NOT NULL');
+ }
+ elseif($filters['sale_type'] == 'returns')
+ {
+ $builder->where('sales.sale_status = ' . COMPLETED . ' AND payment_amount < 0');
+ }
+ elseif($filters['sale_type'] == 'all')
+ {
+ $builder->where('sales.sale_status = ' . COMPLETED);
+ }
+
+ //TODO: Avoid the double negatives
+ if($filters['only_invoices'])
+ {
+ $builder->where('invoice_number IS NOT NULL');
+ }
+
+ if($filters['only_cash'])
+ {
+ $builder->like('payment_type', lang('Sales.cash'));
+ }
+
+ if($filters['only_due'])
+ {
+ $builder->like('payment_type', lang('Sales.due'));
+ }
+
+ if($filters['only_check'])
+ {
+ $builder->like('payment_type', lang('Sales.check'));
+ }
+
+ if($filters['only_creditcard'])
+ {
+ $builder->like('payment_type', lang('Sales.credit'));
+ }
+
+ $builder->groupBy('payment_type');
+
+ $payments = $builder->get()->getResultArray();
+
+ // consider Gift Card as only one type of payment and do not show "Gift Card: 1, Gift Card: 2, etc." in the total
+ $gift_card_count = 0;
+ $gift_card_amount = 0;
+
+ foreach($payments as $key => $payment)
+ {
+ if(strstr($payment['payment_type'], lang('Sales.giftcard')))
+ {
+ $gift_card_count += $payment['count'];
+ $gift_card_amount += $payment['payment_amount'];
+
+ //remove the "Gift Card: 1", "Gift Card: 2", etc. payment string
+ unset($payments[$key]);
+ }
+ }
+
+ if($gift_card_count > 0)
+ {
+ $payments[] = ['payment_type' => lang('Sales.giftcard'), 'count' => $gift_card_count, 'payment_amount' => $gift_card_amount];
+ }
+
+ return $payments;
+ }
+
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('sales');
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Gets search suggestions
+ */
+ public function get_search_suggestions(string $search, int $limit = 25): array //TODO: $limit is never used.
+ {
+ $suggestions = [];
+
+ if(!$this->is_valid_receipt($search))
+ {
+ $builder = $this->db->table('sales');
+ $builder->distinct()->select('first_name, last_name');
+ $builder->join('people', 'people.person_id = sales.customer_id');
+ $builder->like('last_name', $search);
+ $builder->orLike('first_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+ $builder->orLike('company_name', $search);
+ $builder->orderBy('last_name', 'asc');
+
+ foreach($builder->get()->getResultArray() as $result)
+ {
+ $suggestions[] = ['label' => $result['first_name'] . ' ' . $result['last_name']];
+ }
+ }
+ else
+ {
+ $suggestions[] = ['label' => $search];
+ }
+
+ return $suggestions;
+ }
+
+ /**
+ * Gets total of invoice rows
+ */
+ public function get_invoice_count(): int
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('invoice_number IS NOT NULL');
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Gets sale by invoice number
+ */
+ public function get_sale_by_invoice_number(string $invoice_number): ResultInterface
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('invoice_number', $invoice_number);
+
+ return $builder->get();
+ }
+
+ /**
+ * @param string $year
+ * @param int $start_from
+ * @return int
+ */
+ public function get_invoice_number_for_year(string $year = '', int $start_from = 0): int
+ {
+ return $this->get_number_for_year('invoice_number', $year, $start_from);
+ }
+
+ /**
+ * @param string $year
+ * @param int $start_from
+ * @return int
+ */
+ public function get_quote_number_for_year(string $year = '', int $start_from = 0): int
+ {
+ return $this->get_number_for_year('quote_number', $year, $start_from);
+ }
+
+ /**
+ * Gets invoice number by year
+ */
+ private function get_number_for_year(string $field, string $year = '', int $start_from = 0): int
+ {
+ $year = $year == '' ? date('Y') : $year;
+
+ $builder = $this->db->table('sales');
+ $builder->select('COUNT( 1 ) AS number_year');
+ $builder->where('DATE_FORMAT(sale_time, "%Y" ) = ', $year);
+ $builder->where("$field IS NOT NULL");
+ $result = $builder->get()->getRowArray();
+
+ return ($start_from + $result['number_year']);
+ }
+
+ /**
+ * Checks if valid receipt
+ */
+ public function is_valid_receipt(string &$receipt_sale_id): bool //TODO: like the others, maybe this should be an array rather than a delimited string... either that or the parameter name needs to be changed. $receipt_sale_id implies that it's an int.
+ {
+ $config = config(OSPOS::class)->settings;
+
+ if(!empty($receipt_sale_id))
+ {
+ //POS #
+ $pieces = explode(' ', $receipt_sale_id);
+
+ if(count($pieces) == 2 && preg_match('/(POS)/i', $pieces[0]))
+ {
+ return $this->exists($pieces[1]);
+ }
+ elseif($config['invoice_enable'])
+ {
+ $sale_info = $this->get_sale_by_invoice_number($receipt_sale_id);
+
+ if($sale_info->getNumRows() > 0)
+ {
+ $receipt_sale_id = 'POS ' . $sale_info->getRow()->sale_id;
+
+ return true;
+ }
+ }
+ }
+
+ return false;
+ }
+
+ /**
+ * Checks if sale exists
+ */
+ public function exists(int $sale_id): bool
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Update sale
+ */
+ public function update($sale_id = null, $sale_data = null): bool
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+ $update_data = $sale_data;
+ unset($update_data['payments']);
+ $success = $builder->update($update_data);
+
+ //touch payment only if update sale is successful and there is a payments object otherwise the result would be to delete all the payments associated to the sale
+ if($success && !empty($sale_data['payments']))
+ {
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ $builder = $this->db->table('sales_payments');
+
+ // add new payments
+ foreach($sale_data['payments'] as $payment)
+ {
+ $payment_id = $payment['payment_id'];
+ $payment_type = $payment['payment_type'];
+ $payment_amount = $payment['payment_amount'];
+ $cash_refund = $payment['cash_refund'];
+ $cash_adjustment = $payment['cash_adjustment'];
+ $employee_id = $payment['employee_id'];
+
+ if($payment_id == NEW_ENTRY && $payment_amount != 0)
+ {
+ // Add a new payment transaction
+ $sales_payments_data = [
+ 'sale_id' => $sale_id,
+ 'payment_type' => $payment_type,
+ 'payment_amount' => $payment_amount,
+ 'cash_refund' => $cash_refund,
+ 'cash_adjustment' => $cash_adjustment,
+ 'employee_id' => $employee_id
+ ];
+ $success = $builder->insert($sales_payments_data);
+ }
+ elseif($payment_id != NEW_ENTRY)
+ {
+ if($payment_amount != 0)
+ {
+ // Update existing payment transactions (payment_type only)
+ $sales_payments_data = [
+ 'payment_type' => $payment_type,
+ 'payment_amount' => $payment_amount,
+ 'cash_refund' => $cash_refund,
+ 'cash_adjustment' => $cash_adjustment
+ ];
+
+ $builder->where('payment_id', $payment_id);
+ $success = $builder->update($sales_payments_data);
+ }
+ else
+ {
+ // Remove existing payment transactions with a payment amount of zero
+ $success = $builder->delete(['payment_id' => $payment_id]);
+ }
+ }
+ }
+
+ $this->db->transComplete();
+ $success &= $this->db->transStatus();
+ }
+
+ return $success;
+ }
+
+ /**
+ * Save the sale information after the sales is complete but before the final document is printed
+ * The sales_taxes variable needs to be initialized to an empty array before calling
+ * @throws ReflectionException
+ */
+ public function save_value(int $sale_id, string &$sale_status, array &$items, int $customer_id, int $employee_id, string $comment, ?string $invoice_number,
+ ?string $work_order_number, ?string $quote_number, int $sale_type, ?array $payments, ?int $dinner_table_id, ?array &$sales_taxes): int //TODO: this method returns the sale_id but the override is expecting it to return a bool. The signature needs to be reworked. Generally when there are more than 3 maybe 4 parameters, there's a good chance that an object needs to be passed rather than so many params.
+ {
+ $config = config(OSPOS::class)->settings;
+ $attribute = model(Attribute::class);
+ $customer = model(Customer::class);
+ $giftcard = model(Giftcard::class);
+ $inventory = model('Inventory');
+ $item = model(Item::class);
+
+ $item_quantity = model(Item_quantity::class);
+
+ if($sale_id != NEW_ENTRY)
+ {
+ $this->clear_suspended_sale_detail($sale_id);
+ }
+
+ if(count($items) == 0) //TODO: ===
+ {
+ return -1; //TODO: Replace -1 with a constant
+ }
+
+ $sales_data = [
+ 'sale_time' => date('Y-m-d H:i:s'),
+ 'customer_id' => $customer->exists($customer_id) ? $customer_id : null,
+ 'employee_id' => $employee_id,
+ 'comment' => $comment,
+ 'sale_status' => $sale_status,
+ 'invoice_number' => $invoice_number,
+ 'quote_number' => $quote_number,
+ 'work_order_number'=> $work_order_number,
+ 'dinner_table_id' => $dinner_table_id,
+ 'sale_type' => $sale_type
+ ];
+
+ // Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+
+ if($sale_id == NEW_ENTRY)
+ {
+ $builder = $this->db->table('sales');
+ $builder->insert($sales_data);
+ $sale_id = $this->db->insertID();
+ }
+ else
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+ $builder->update($sales_data);
+ }
+
+ $total_amount = 0;
+ $total_amount_used = 0;
+
+ foreach($payments as $payment_id => $payment)
+ {
+ if(!empty(strstr($payment['payment_type'], lang('Sales.giftcard'))))
+ {
+ // We have a gift card, and we have to deduct the used value from the total value of the card.
+ $splitpayment = explode( ':', $payment['payment_type'] ); //TODO: this variable doesn't follow our naming conventions. Probably should be refactored to split_payment.
+ $cur_giftcard_value = $giftcard->get_giftcard_value( $splitpayment[1] ); //TODO: this should be refactored to $current_giftcard_value
+ $giftcard->update_giftcard_value( $splitpayment[1], $cur_giftcard_value - $payment['payment_amount'] );
+ }
+ elseif(!empty(strstr($payment['payment_type'], lang('Sales.rewards'))))
+ {
+ $cur_rewards_value = $customer->get_info($customer_id)->points;
+ $customer->update_reward_points_value($customer_id, $cur_rewards_value - $payment['payment_amount'] );
+ $total_amount_used = floatval($total_amount_used) + floatval($payment['payment_amount']);
+ }
+
+ $sales_payments_data = [
+ 'sale_id' => $sale_id,
+ 'payment_type' => $payment['payment_type'],
+ 'payment_amount' => $payment['payment_amount'],
+ 'cash_refund' => $payment['cash_refund'],
+ 'cash_adjustment' => $payment['cash_adjustment'],
+ 'employee_id' => $employee_id
+ ];
+
+ $builder = $this->db->table('sales_payments');
+ $builder->insert($sales_payments_data);
+
+ $total_amount = floatval($total_amount) + floatval($payment['payment_amount']) - floatval($payment['cash_refund']);
+ }
+
+ $this->save_customer_rewards($customer_id, $sale_id, $total_amount, $total_amount_used);
+
+ $customer = $customer->get_info($customer_id);
+
+ foreach($items as $line => $item_data)
+ {
+ $cur_item_info = $item->get_info($item_data['item_id']);
+
+ if($item_data['price'] == 0.00)
+ {
+ $item_data['discount'] = 0.00;
+ }
+
+ $sales_items_data = [
+ 'sale_id' => $sale_id,
+ 'item_id' => $item_data['item_id'],
+ 'line' => $item_data['line'],
+ 'description' => character_limiter($item_data['description'], 255),
+ 'serialnumber' => character_limiter($item_data['serialnumber'], 30),
+ 'quantity_purchased' => $item_data['quantity'],
+ 'discount' => $item_data['discount'],
+ 'discount_type' => $item_data['discount_type'],
+ 'item_cost_price' => $item_data['cost_price'],
+ 'item_unit_price' => $item_data['price'],
+ 'item_location' => $item_data['item_location'],
+ 'print_option' => $item_data['print_option']
+ ];
+
+ $builder = $this->db->table('sales_items');
+ $builder->insert($sales_items_data);
+
+ if($cur_item_info->stock_type == HAS_STOCK && $sale_status == COMPLETED) //TODO: === ?
+ {
+ // Update stock quantity if item type is a standard stock item and the sale is a standard sale
+ $item_quantity_data = $item_quantity->get_item_quantity($item_data['item_id'], $item_data['item_location']);
+
+ $item_quantity->save_value([
+ 'quantity' => $item_quantity_data->quantity - $item_data['quantity'],
+ 'item_id' => $item_data['item_id'],
+ 'location_id' => $item_data['item_location']],
+ $item_data['item_id'],
+ $item_data['item_location']
+ );
+
+ // if an items was deleted but later returned it's restored with this rule
+ if($item_data['quantity'] < 0)
+ {
+ $item->undelete($item_data['item_id']);
+ }
+
+ // Inventory Count Details
+ $sale_remarks = 'POS ' . $sale_id; //TODO: Use string interpolation here.
+ $inv_data = [
+ 'trans_date' => date('Y-m-d H:i:s'),
+ 'trans_items' => $item_data['item_id'],
+ 'trans_user' => $employee_id,
+ 'trans_location' => $item_data['item_location'],
+ 'trans_comment' => $sale_remarks,
+ 'trans_inventory' => -$item_data['quantity']
+ ];
+
+ $inventory->insert($inv_data, false);
+ }
+
+ $attribute->copy_attribute_links($item_data['item_id'], 'sale_id', $sale_id);
+ }
+
+ if($customer_id == NEW_ENTRY || $customer->taxable)
+ {
+ $this->save_sales_tax($sale_id, $sales_taxes[0]);
+ $this->save_sales_items_taxes($sale_id, $sales_taxes[1]);
+ }
+
+ if($config['dinner_table_enable'])
+ {
+ $dinner_table = model(Dinner_table::class);
+ if($sale_status == COMPLETED) //TODO: === ?
+ {
+ $dinner_table->release($dinner_table_id);
+ }
+ else
+ {
+ $dinner_table->occupy($dinner_table_id);
+ }
+ }
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus() ? $sale_id : -1;
+ }
+
+ /**
+ * Saves sale tax
+ */
+ public function save_sales_tax(int $sale_id, array $sales_taxes): void //TODO: should we return the result of the insert here as a bool?
+ {
+ $builder = $this->db->table('sales_taxes');
+
+ foreach($sales_taxes as $line => $sales_tax)
+ {
+ $sales_tax['sale_id'] = $sale_id;
+ $builder->insert($sales_tax);
+ }
+ }
+
+ /**
+ * Apply customer sales tax if the customer sales tax is enabled
+ * The original tax is still supported if the user configures it,
+ * but it won't make sense unless it's used exclusively for the purpose
+ * of VAT tax which becomes a price component. VAT taxes must still be reported
+ * as a separate tax entry on the invoice.
+ */
+ public function save_sales_items_taxes(int $sale_id, array $sales_item_taxes): void
+ {
+ $builder = $this->db->table('sales_items_taxes');
+
+ foreach($sales_item_taxes as $line => $tax_item)
+ {
+ $sales_items_taxes = [
+ 'sale_id' => $sale_id,
+ 'item_id' => $tax_item['item_id'],
+ 'line' => $tax_item['line'],
+ 'name' => $tax_item['name'],
+ 'percent' => $tax_item['percent'],
+ 'tax_type' => $tax_item['tax_type'],
+ 'rounding_code' => $tax_item['rounding_code'],
+ 'cascade_sequence' => $tax_item['cascade_sequence'],
+ 'item_tax_amount' => $tax_item['item_tax_amount'],
+ 'sales_tax_code_id' => $tax_item['sales_tax_code_id'],
+ 'tax_category_id' => $tax_item['tax_category_id'],
+ 'jurisdiction_id' => $tax_item['jurisdiction_id']
+ ];
+
+ $builder->insert($sales_items_taxes);
+ }
+ }
+
+ /**
+ * Return the taxes that were charged
+ */
+ public function get_sales_taxes(int $sale_id): array
+ {
+ $builder = $this->db->table('sales_taxes');
+ $builder->where('sale_id', $sale_id);
+ $builder->orderBy('print_sequence', 'asc');
+
+ $query = $builder->get();
+
+ return $query->getResultArray();
+ }
+
+ /**
+ * Return the taxes applied to a sale for a particular item
+ */
+ public function get_sales_item_taxes(int $sale_id, int $item_id): array
+ {
+ $builder = $this->db->table('sales_items_taxes');
+ $builder->select('item_id, name, percent');
+ $builder->where('sale_id',$sale_id);
+ $builder->where('item_id',$item_id);
+
+ //return an array of taxes for an item
+ return $builder->get()->getResultArray();
+ }
+
+ /**
+ * Deletes list of sales
+ * @throws ReflectionException
+ */
+ public function delete_list(array $sale_ids, int $employee_id, bool $update_inventory = true): bool
+ {
+ $result = true;
+
+ foreach($sale_ids as $sale_id)
+ {
+ $result &= $this->delete($sale_id, false, $update_inventory, $employee_id);
+ }
+
+ return $result;
+ }
+
+ /**
+ * Restores list of sales
+ */
+ public function restore_list(array $sale_ids, int $employee_id, bool $update_inventory = true): bool //TODO: $employee_id and $update_inventory are never used in the function.
+ {
+ foreach($sale_ids as $sale_id)
+ {
+ $this->update_sale_status($sale_id, SUSPENDED);
+ }
+
+ return true;
+ }
+
+ /**
+ * Delete sale. Hard deletes are not supported for sales transactions.
+ * When a sale is "deleted" it is simply changed to a status of canceled.
+ * However, if applicable the inventory still needs to be updated
+ * @throws ReflectionException
+ */
+ public function delete($sale_id = null, bool $purge = false, bool $update_inventory = true, $employee_id = null): bool
+ {
+ // start a transaction to assure data integrity
+ $this->db->transStart();
+
+ $sale_status = $this->get_sale_status($sale_id);
+
+ if($update_inventory && $sale_status == COMPLETED)
+ {
+ // defect, not all item deletions will be undone??
+ // get array with all the items involved in the sale to update the inventory tracking
+ $inventory = model('Inventory');
+ $item = model(Item::class);
+ $item_quantity = model(Item_quantity::class);
+
+ $items = $this->get_sale_items($sale_id)->getResultArray();
+
+ foreach($items as $item_data)
+ {
+ $cur_item_info = $item->get_info($item_data['item_id']);
+
+ if($cur_item_info->stock_type == HAS_STOCK)
+ {
+ // create query to update inventory tracking
+ $inv_data = [
+ 'trans_date' => date('Y-m-d H:i:s'),
+ 'trans_items' => $item_data['item_id'],
+ 'trans_user' => $employee_id,
+ 'trans_comment' => 'Deleting sale ' . $sale_id,
+ 'trans_location' => $item_data['item_location'],
+ 'trans_inventory' => $item_data['quantity_purchased']
+ ];
+ // update inventory
+ $inventory->insert($inv_data, false);
+
+ // update quantities
+ $item_quantity->change_quantity($item_data['item_id'], $item_data['item_location'], $item_data['quantity_purchased']);
+ }
+ }
+ }
+
+ $this->update_sale_status($sale_id, CANCELED);
+
+ // execute transaction
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ /**
+ * Gets sale item
+ */
+ public function get_sale_items(int $sale_id): ResultInterface
+ {
+ $builder = $this->db->table('sales_items');
+ $builder->where('sale_id', $sale_id);
+
+ return $builder->get();
+ }
+
+ /**
+ * Used by the invoice and receipt programs
+ */
+ public function get_sale_items_ordered(int $sale_id): ResultInterface
+ {
+ $config = config(OSPOS::class)->settings;
+ $item = model(Item::class);
+
+ $builder = $this->db->table('sales_items AS sales_items');
+ $builder->select('
+ sales_items.sale_id,
+ sales_items.item_id,
+ sales_items.description,
+ serialnumber,
+ line,
+ quantity_purchased,
+ item_cost_price,
+ item_unit_price,
+ discount,
+ discount_type,
+ item_location,
+ print_option,
+ ' . $item->get_item_name('name') . ',
+ category,
+ item_type,
+ stock_type');
+ $builder->join('items AS items', 'sales_items.item_id = items.item_id');
+ $builder->where('sales_items.sale_id', $sale_id);
+
+ // Entry sequence (this will render kits in the expected sequence)
+ if($config['line_sequence'] == '0') //TODO: Replace these with constants and this should be converted to a switch.
+ {
+ $builder->orderBy('line', 'asc');
+ }
+ // Group by Stock Type (nonstock first - type 1, stock next - type 0)
+ elseif($config['line_sequence'] == '1')
+ {
+ $builder->orderBy('stock_type', 'desc');
+ $builder->orderBy('sales_items.description', 'asc');
+ $builder->orderBy('items.name', 'asc');
+ $builder->orderBy('items.qty_per_pack', 'asc');
+ }
+ // Group by Item Category
+ elseif($config['line_sequence'] == '2')
+ {
+ $builder->orderBy('category', 'asc');
+ $builder->orderBy('sales_items.description', 'asc');
+ $builder->orderBy('items.name', 'asc');
+ $builder->orderBy('items.qty_per_pack', 'asc');
+ }
+ // Group by entry sequence in descending sequence (the Standard)
+ else
+ {
+ $builder->orderBy('line', 'desc');
+ }
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets sale payments
+ */
+ public function get_sale_payments(int $sale_id): ResultInterface
+ {
+ $builder = $this->db->table('sales_payments');
+ $builder->where('sale_id', $sale_id);
+
+ return $builder->get();
+ }
+
+ /**
+ * Gets sale payment options
+ */
+ public function get_payment_options(bool $giftcard = true, bool $reward_points = true): array
+ {
+ $payments = get_payment_options();
+
+ if($giftcard)
+ {
+ $payments[lang('Sales.giftcard')] = lang('Sales.giftcard');
+ }
+
+ if($reward_points)
+ {
+ $payments[lang('Sales.rewards')] = lang('Sales.rewards');
+ }
+ $sale_lib = new Sale_lib();
+ if($sale_lib->get_mode() == 'sale_work_order')
+ {
+ $payments[lang('Sales.cash_deposit')] = lang('Sales.cash_deposit');
+ $payments[lang('Sales.credit_deposit')] = lang('Sales.credit_deposit');
+ }
+
+ return $payments;
+ }
+
+ /**
+ * Gets sale customer name
+ */
+ public function get_customer(int $sale_id): object
+ {
+ $customer = model(Customer::class);
+
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ return $customer->get_info($builder->get()->getRow()->customer_id);
+ }
+
+ /**
+ * Gets sale employee name
+ */
+ public function get_employee(int $sale_id): object
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ $employee = model(Employee::class);
+
+ return $employee->get_info($builder->get()->getRow()->employee_id);
+ }
+
+ /**
+ * Checks if quote number exists
+ */
+ public function check_quote_number_exists(string $quote_number, string $sale_id = ''): bool
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('quote_number', $quote_number);
+
+ if(!empty($sale_id))
+ {
+ $builder->where('sale_id !=', $sale_id);
+ }
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Checks if invoice number exists
+ */
+ public function check_invoice_number_exists(string $invoice_number, string $sale_id = ''): bool
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('invoice_number', $invoice_number);
+
+ if(!empty($sale_id))
+ {
+ $builder->where('sale_id !=', $sale_id);
+ }
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Checks if work order number exists
+ */
+ public function check_work_order_number_exists(string $work_order_number, string $sale_id = ''): bool
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('invoice_number', $work_order_number);
+ if(!empty($sale_id))
+ {
+ $builder->where('sale_id !=', $sale_id);
+ }
+
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
+
+ /**
+ * Gets Giftcard value
+ */
+ public function get_giftcard_value(string $giftcardNumber): float
+ {
+ $giftcard = model(Giftcard::class);
+
+ if(!$giftcard->exists($giftcard->get_giftcard_id($giftcardNumber))) //TODO: camelCase is used here for the variable name but we are using _ everywhere else. CI4 moved to camelCase... we should pick one and do that.
+ {
+ return 0;
+ }
+
+ $builder = $this->db->table('giftcards');
+ $builder->where('giftcard_number', $giftcardNumber);
+
+ return $builder->get()->getRow()->value;
+ }
+
+ /**
+ * Creates sales temporary dimensional table
+ * We create a temp table that allows us to do easy report/sales queries
+ */
+ public function create_temp_table(array $inputs): void
+ {
+ $config = config(OSPOS::class)->settings;
+
+ if(empty($inputs['sale_id']))
+ {
+ if(empty($config['date_or_time_format'])) //TODO: This needs to be replaced with Ternary notation
+ {
+ $where = 'DATE(sales.sale_time) BETWEEN ' . $this->db->escape($inputs['start_date']) . ' AND ' . $this->db->escape($inputs['end_date']);
+ }
+ else
+ {
+ $where = 'sales.sale_time BETWEEN ' . $this->db->escape(rawurldecode($inputs['start_date'])) . ' AND ' . $this->db->escape(rawurldecode($inputs['end_date']));
+ }
+ }
+ else
+ {
+ $where = 'sales.sale_id = ' . $this->db->escape($inputs['sale_id']);
+ }
+
+ $decimals = totals_decimals();
+
+ $sale_price = 'CASE WHEN sales_items.discount_type = ' . PERCENT
+ . " THEN sales_items.quantity_purchased * sales_items.item_unit_price - ROUND(sales_items.quantity_purchased * sales_items.item_unit_price * sales_items.discount / 100, $decimals) "
+ . 'ELSE sales_items.quantity_purchased * (sales_items.item_unit_price - sales_items.discount) END';
+
+ $sale_cost = 'SUM(sales_items.item_cost_price * sales_items.quantity_purchased)';
+
+ $tax = 'IFNULL(SUM(sales_items_taxes.tax), 0)';
+ $sales_tax = 'IFNULL(SUM(sales_items_taxes.sales_tax), 0)';
+ $internal_tax = 'IFNULL(SUM(sales_items_taxes.internal_tax), 0)';
+ $cash_adjustment = 'IFNULL(SUM(payments.sale_cash_adjustment), 0)';
+
+ if($config['tax_included'])
+ {
+ $sale_total = "ROUND(SUM($sale_price), $decimals) + $cash_adjustment";
+ $sale_subtotal = "$sale_total - $internal_tax";
+ }
+ else
+ {
+ $sale_subtotal = "ROUND(SUM($sale_price), $decimals) - $internal_tax + $cash_adjustment";
+ $sale_total = "ROUND(SUM($sale_price), $decimals) + $sales_tax + $cash_adjustment";
+ }
+
+ // create a temporary table to contain all the sum of taxes per sale item
+ $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_taxes_temp') .
+ ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY
+ (
+ SELECT sales_items_taxes.sale_id AS sale_id,
+ sales_items_taxes.item_id AS item_id,
+ sales_items_taxes.line AS line,
+ SUM(ROUND(sales_items_taxes.item_tax_amount, ' . $decimals . ')) AS tax,
+ SUM(ROUND(CASE WHEN sales_items_taxes.tax_type = 0 THEN sales_items_taxes.item_tax_amount ELSE 0 END, ' . $decimals . ')) AS internal_tax,
+ SUM(ROUND(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END, ' . $decimals . ')) AS sales_tax
+ FROM ' . $this->db->prefixTable('sales_items_taxes') . ' AS sales_items_taxes
+ INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
+ ON sales.sale_id = sales_items_taxes.sale_id
+ INNER JOIN ' . $this->db->prefixTable('sales_items') . ' AS sales_items
+ ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line
+ WHERE ' . $where . '
+ GROUP BY sale_id, item_id, line
+ )';
+
+ $this->db->query($sql);
+
+ // create a temporary table to contain all the payment types and amount
+ $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_payments_temp') .
+ ' (PRIMARY KEY(sale_id), INDEX(sale_id))
+ (
+ SELECT payments.sale_id AS sale_id,
+ SUM(CASE WHEN payments.cash_adjustment = 0 THEN payments.payment_amount ELSE 0 END) AS sale_payment_amount,
+ SUM(CASE WHEN payments.cash_adjustment = 1 THEN payments.payment_amount ELSE 0 END) AS sale_cash_adjustment,
+ SUM(payments.cash_refund) AS sale_cash_refund,
+ GROUP_CONCAT(CONCAT(payments.payment_type, " ", (payments.payment_amount - payments.cash_refund)) SEPARATOR ", ") AS payment_type
+ FROM ' . $this->db->prefixTable('sales_payments') . ' AS payments
+ INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
+ ON sales.sale_id = payments.sale_id
+ WHERE ' . $where . '
+ GROUP BY payments.sale_id
+ )';
+
+ $this->db->query($sql);
+ $item = model(Item::class);
+ $sql = 'CREATE TEMPORARY TABLE IF NOT EXISTS ' . $this->db->prefixTable('sales_items_temp') .
+ ' (INDEX(sale_date), INDEX(sale_time), INDEX(sale_id))
+ (
+ SELECT
+ MAX(DATE(sales.sale_time)) AS sale_date,
+ MAX(sales.sale_time) AS sale_time,
+ sales.sale_id AS sale_id,
+ MAX(sales.sale_status) AS sale_status,
+ MAX(sales.sale_type) AS sale_type,
+ MAX(sales.comment) AS comment,
+ MAX(sales.invoice_number) AS invoice_number,
+ MAX(sales.quote_number) AS quote_number,
+ MAX(sales.customer_id) AS customer_id,
+ MAX(CONCAT(customer_p.first_name, " ", customer_p.last_name)) AS customer_name,
+ MAX(customer_p.first_name) AS customer_first_name,
+ MAX(customer_p.last_name) AS customer_last_name,
+ MAX(customer_p.email) AS customer_email,
+ MAX(customer_p.comments) AS customer_comments,
+ MAX(customer.company_name) AS customer_company_name,
+ MAX(sales.employee_id) AS employee_id,
+ MAX(CONCAT(employee.first_name, " ", employee.last_name)) AS employee_name,
+ items.item_id AS item_id,
+ MAX(' . $item->get_item_name() . ') AS name,
+ MAX(items.item_number) AS item_number,
+ MAX(items.category) AS category,
+ MAX(items.supplier_id) AS supplier_id,
+ MAX(sales_items.quantity_purchased) AS quantity_purchased,
+ MAX(sales_items.item_cost_price) AS item_cost_price,
+ MAX(sales_items.item_unit_price) AS item_unit_price,
+ MAX(sales_items.discount) AS discount,
+ sales_items.discount_type AS discount_type,
+ sales_items.line AS line,
+ MAX(sales_items.serialnumber) AS serialnumber,
+ MAX(sales_items.item_location) AS item_location,
+ MAX(sales_items.description) AS description,
+ MAX(payments.payment_type) AS payment_type,
+ MAX(payments.sale_payment_amount) AS sale_payment_amount,
+ ' . "
+ $sale_subtotal AS subtotal,
+ $tax AS tax,
+ $sale_total AS total,
+ $sale_cost AS cost,
+ ($sale_subtotal - $sale_cost) AS profit
+ " . '
+ FROM ' . $this->db->prefixTable('sales_items') . ' AS sales_items
+ INNER JOIN ' . $this->db->prefixTable('sales') . ' AS sales
+ ON sales_items.sale_id = sales.sale_id
+ INNER JOIN ' . $this->db->prefixTable('items') . ' AS items
+ ON sales_items.item_id = items.item_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('sales_payments_temp') . ' AS payments
+ ON sales_items.sale_id = payments.sale_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('suppliers') . ' AS supplier
+ ON items.supplier_id = supplier.person_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('people') . ' AS customer_p
+ ON sales.customer_id = customer_p.person_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('customers') . ' AS customer
+ ON sales.customer_id = customer.person_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('people') . ' AS employee
+ ON sales.employee_id = employee.person_id
+ LEFT OUTER JOIN ' . $this->db->prefixTable('sales_items_taxes_temp') . ' AS sales_items_taxes
+ ON sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.item_id = sales_items_taxes.item_id AND sales_items.line = sales_items_taxes.line
+ WHERE ' . $where . '
+ GROUP BY sale_id, item_id, line
+ )';
+
+ $this->db->query($sql);
+ }
+
+ /**
+ * Retrieves all sales that are in a suspended state
+ */
+ public function get_all_suspended(int $customer_id = null): array
+ {
+ if($customer_id == NEW_ENTRY)
+ {
+ $query = $this->db->query("SELECT sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' THEN quote_number WHEN sale_type = '".SALE_TYPE_WORK_ORDER."' THEN work_order_number else sale_id end as doc_id, sale_id as suspended_sale_id, sale_status, sale_time, dinner_table_id, customer_id, employee_id, comment FROM "
+ . $this->db->prefixTable('sales') . ' where sale_status = ' . SUSPENDED);
+ }
+ else
+ {
+ $query = $this->db->query("SELECT sale_id, case when sale_type = '".SALE_TYPE_QUOTE."' THEN quote_number WHEN sale_type = '".SALE_TYPE_WORK_ORDER."' THEN work_order_number else sale_id end as doc_id, sale_status, sale_time, dinner_table_id, customer_id, employee_id, comment FROM "
+ . $this->db->prefixTable('sales') . ' where sale_status = '. SUSPENDED .' AND customer_id = ' . $customer_id);
+ }
+
+ return $query->getResultArray() ?: [];
+ }
+
+ /**
+ * Gets the dinner table for the selected sale
+ */
+ public function get_dinner_table(int $sale_id) //TODO: this is returning null or the table_id. We can keep it this way but multiple return types can't be declared until PHP 8.x
+ {
+ if($sale_id == NEW_ENTRY)
+ {
+ return null;
+ }
+
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ return $builder->get()->getRow()->dinner_table_id;
+ }
+
+ /**
+ * Gets the sale type for the selected sale
+ */
+ public function get_sale_type(int $sale_id)
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ return $builder->get()->getRow()->sale_type;
+ }
+
+ /**
+ * Gets the sale status for the selected sale
+ */
+ public function get_sale_status(int $sale_id): int
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ return $builder->get()->getRow()->sale_status;
+ }
+
+ /**
+ * @param int $sale_id
+ * @param int $sale_status
+ * @return void
+ */
+ public function update_sale_status(int $sale_id, int $sale_status): void
+ {
+ $builder = $this->db->table('sales');
+
+ $builder->where('sale_id', $sale_id);
+ $builder->update(['sale_status' => $sale_status]);
+ }
+
+ /**
+ * Gets the quote_number for the selected sale
+ */
+ public function get_quote_number(int $sale_id): ?string
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ $row = $builder->get()->getRow();
+
+ if($row != null)
+ {
+ return $row->quote_number;
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the work order number for the selected sale
+ */
+ public function get_work_order_number(int $sale_id): ?string
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ $row = $builder->get()->getRow();
+
+ if($row != null) //TODO: === ?
+ {
+ return $row->work_order_number;
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets the quote_number for the selected sale
+ */
+ public function get_comment(int $sale_id): ?string
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+
+ $row = $builder->get()->getRow();
+
+ if($row != null) //TODO: === ?
+ {
+ return $row->comment;
+ }
+
+ return null;
+ }
+
+ /**
+ * Gets total of suspended invoices rows
+ */
+ public function get_suspended_invoice_count(): int
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('invoice_number IS NOT NULL');
+ $builder->where('sale_status', SUSPENDED);
+
+ return $builder->countAllResults();
+ }
+
+ /**
+ * Removes a selected sale from the sales table.
+ * This function should only be called for suspended sales that are being restored to the current cart
+ */
+ public function delete_suspended_sale(int $sale_id): bool
+ {
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
+ $config = config(OSPOS::class)->settings;
+
+ if($config['dinner_table_enable'])
+ {
+ $dinner_table = model(Dinner_table::class);
+ $dinner_table_id = $this->get_dinner_table($sale_id);
+ $dinner_table->release($dinner_table_id);
+ }
+
+ $this->update_sale_status($sale_id, CANCELED);
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ /**
+ * This clears the sales detail for a given sale_id before the detail is re-saved.
+ * This allows us to reuse the same sale_id
+ */
+ public function clear_suspended_sale_detail(int $sale_id): bool
+ {
+ $this->db->transStart();
+ $config = config(OSPOS::class)->settings;
+
+ if($config['dinner_table_enable'])
+ {
+ $dinner_table = model(Dinner_table::class);
+ $dinner_table_id = $this->get_dinner_table($sale_id);
+ $dinner_table->release($dinner_table_id);
+ }
+
+ $builder = $this->db->table('sales_payments');
+ $builder->delete(['sale_id' => $sale_id]);
+
+ $builder = $this->db->table('sales_items_taxes');
+ $builder->delete(['sale_id' => $sale_id]);
+
+ $builder = $this->db->table('sales_items');
+ $builder->delete(['sale_id' => $sale_id]);
+
+ $builder = $this->db->table('sales_taxes');
+ $builder->delete(['sale_id' => $sale_id]);
+
+ $this->db->transComplete();
+
+ return $this->db->transStatus();
+ }
+
+ /**
+ * Gets suspended sale info
+ */
+ public function get_suspended_sale_info(int $sale_id): ResultInterface
+ {
+ $builder = $this->db->table('sales');
+ $builder->where('sale_id', $sale_id);
+ $builder->join('people', 'people.person_id = sales.customer_id', 'LEFT');
+ $builder->where('sale_status', SUSPENDED);
+
+ return $builder->get();
+ }
+
+ /**
+ * @param int $customer_id
+ * @param int $sale_id
+ * @param float $total_amount
+ * @param float $total_amount_used
+ */
+ private function save_customer_rewards(int $customer_id, int $sale_id, float $total_amount, float $total_amount_used): void
+ {
+ $config = config(OSPOS::class)->settings;
+
+ if(!empty($customer_id) && $config['customer_reward_enable'])
+ {
+ $customer = model(Customer::class);
+ $customer_rewards = model(Customer_rewards::class);
+ $rewards = model(Rewards::class);
+
+ $package_id = $customer->get_info($customer_id)->package_id;
+
+ if(!empty($package_id))
+ {
+ $points_percent = $customer_rewards->get_points_percent($package_id);
+ $points = $customer->get_info($customer_id)->points;
+ $points = ($points == null ? 0 : $points);
+ $points_percent = ($points_percent == null ? 0 : $points_percent);
+ $total_amount_earned = ($total_amount * $points_percent / 100);
+ $points = $points + $total_amount_earned;
+
+ $customer->update_reward_points_value($customer_id, $points);
+
+ $rewards_data = ['sale_id' => $sale_id, 'earned' => $total_amount_earned, 'used' => $total_amount_used];
+
+ $rewards->save_value($rewards_data);
+ }
+ }
+ }
+
+ /**
+ * Creates a temporary table to store the sales_payments data
+ *
+ * @param string $where
+ * @return array
+ */
+ private function create_temp_table_sales_payments_data(string $where): void
+ {
+ $builder = $this->db->table('sales_payments AS payments');
+ $builder->select([
+ 'payments.sale_id',
+ 'SUM(CASE WHEN `payments`.`cash_adjustment` = 0 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_payment_amount',
+ 'SUM(CASE WHEN `payments`.`cash_adjustment` = 1 THEN `payments`.`payment_amount` ELSE 0 END) AS sale_cash_adjustment',
+ 'GROUP_CONCAT(CONCAT(`payments`.`payment_type`, " ", (`payments`.`payment_amount` - `payments`.`cash_refund`)) SEPARATOR ", ") AS payment_type'
+ ]);
+ $builder->join('sales', 'sales.sale_id = payments.sale_id', 'inner');
+ $builder->where($where);
+ $builder->groupBy('payments.sale_id');
+
+ $sub_query = $builder->getCompiledSelect();
+ log_message('error', $sub_query);
+
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS '
+ . $this->db->prefixTable('sales_payments_temp')
+ . ' (PRIMARY KEY(`sale_id`), INDEX(`sale_id`)) AS (' . $sub_query . ')');
+ }
+
+ /**
+ * Temporary table to store the sales_items_taxes data
+ *
+ * @param string $where
+ * @return \CodeIgniter\Database\BaseBuilder
+ */
+ private function create_temp_table_sales_items_taxes_data(string $where): void
+ {
+
+ $builder = $this->db->table('sales_items_taxes AS sales_items_taxes');
+ $builder->select([
+ 'sales_items_taxes.sale_id AS sale_id',
+ 'sales_items_taxes.item_id AS item_id',
+ 'sales_items_taxes.line AS line',
+ 'SUM(sales_items_taxes.item_tax_amount) AS tax',
+ 'SUM(CASE WHEN sales_items_taxes.tax_type = 0 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS internal_tax',
+ 'SUM(CASE WHEN sales_items_taxes.tax_type = 1 THEN sales_items_taxes.item_tax_amount ELSE 0 END) AS sales_tax'
+ ]);
+ $builder->join('sales', 'sales.sale_id = sales_items_taxes.sale_id', 'inner');
+ $builder->join('sales_items', 'sales_items.sale_id = sales_items_taxes.sale_id AND sales_items.line = sales_items_taxes.line', 'inner');
+ $builder->where($where);
+ $builder->groupBy(['sale_id', 'item_id', 'line']);
+ $sub_query = $builder->getCompiledSelect();
+
+ $this->db->query('CREATE TEMPORARY TABLE IF NOT EXISTS '
+ . $this->db->prefixTable('sales_items_taxes_temp')
+ . ' (INDEX(sale_id), INDEX(item_id)) ENGINE=MEMORY AS (' . $sub_query . ')');
+ }
+
+ /**
+ * @param string $search
+ * @param array $filters
+ * @param BaseBuilder $builder
+ * @return void
+ */
+ private function add_filters_to_query(string $search, array $filters, BaseBuilder $builder): void
+ {
+ if(!empty($search)) //TODO: this is duplicated code. We should think about refactoring out a method
+ {
+ if($filters['is_valid_receipt'])
+ {
+ $pieces = explode(' ', $search);
+ $builder->where('sales.sale_id', $pieces[1]);
+ }
+ else
+ {
+ $builder->groupStart();
+ // customer last name
+ $builder->like('customer_p.last_name', $search);
+ // customer first name
+ $builder->orLike('customer_p.first_name', $search);
+ // customer first and last name
+ $builder->orLike('CONCAT(customer_p.first_name, " ", customer_p.last_name)', $search);
+ // customer company name
+ $builder->orLike('customer.company_name', $search);
+ $builder->groupEnd();
+ }
+ }
+
+ if($filters['location_id'] != 'all')
+ {
+ $builder->where('sales_items.item_location', $filters['location_id']);
+ }
+
+ if($filters['selected_customer'] != false)
+ {
+ $sale_lib = new Sale_lib();
+ $builder->where('sales.customer_id', $sale_lib->get_customer());
+ }
+
+
+ if($filters['only_invoices'])
+ {
+ $builder->where('sales.invoice_number IS NOT NULL');
+ }
+
+ if($filters['only_cash'])
+ {
+ $builder->groupStart();
+ $builder->like('payments.payment_type', lang('Sales.cash'));
+ $builder->orWhere('payments.payment_type IS NULL');
+ $builder->groupEnd();
+ }
+
+ if($filters['only_creditcard'])
+ {
+ $builder->like('payments.payment_type', lang('Sales.credit'));
+ }
+
+ if($filters['only_due'])
+ {
+ $builder->like('payments.payment_type', lang('Sales.due'));
+ }
+
+ if($filters['only_check'])
+ {
+ $builder->like('payments.payment_type', lang('Sales.check'));
+ }
+ }
}
diff --git a/app/Models/Stock_location.php b/app/Models/Stock_location.php
index e8b852d55..db5bdac47 100644
--- a/app/Models/Stock_location.php
+++ b/app/Models/Stock_location.php
@@ -16,273 +16,273 @@ use CodeIgniter\Session\Session;
*/
class Stock_location extends Model
{
- protected $table = 'stock_locations';
- protected $primaryKey = 'location_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'location_name',
- 'deleted'
- ];
+ protected $table = 'stock_locations';
+ protected $primaryKey = 'location_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'location_name',
+ 'deleted'
+ ];
- private Session $session;
- private Employee $employee;
+ private Session $session;
+ private Employee $employee;
- public function __construct()
- {
- parent::__construct();
+ public function __construct()
+ {
+ parent::__construct();
- $this->session = session();
- }
+ $this->session = session();
+ }
- /**
- * @param int $location_id
- * @return bool
- */
- public function exists(int $location_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('stock_locations');
- $builder->where('location_id', $location_id);
+ /**
+ * @param int $location_id
+ * @return bool
+ */
+ public function exists(int $location_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->where('location_id', $location_id);
- return ($builder->get()->getNumRows() >= 1);
- }
+ return ($builder->get()->getNumRows() >= 1);
+ }
- /**
- * @return ResultInterface
- */
- public function get_all(): ResultInterface
- {
- $builder = $this->db->table('stock_locations');
- $builder->where('deleted', 0);
+ /**
+ * @return ResultInterface
+ */
+ public function get_all(): ResultInterface
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->where('deleted', 0);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $module_id
- * @return ResultInterface
- */
- public function get_undeleted_all(string $module_id = 'items'): ResultInterface
- {
- $builder = $this->db->table('stock_locations');
- $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
- $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
- $builder->where('person_id', $this->session->get('person_id'));
- $builder->like('permissions.permission_id', $module_id, 'after');
- $builder->where('deleted', 0);
+ /**
+ * @param string $module_id
+ * @return ResultInterface
+ */
+ public function get_undeleted_all(string $module_id = 'items'): ResultInterface
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
+ $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
+ $builder->where('person_id', $this->session->get('person_id'));
+ $builder->like('permissions.permission_id', $module_id, 'after');
+ $builder->where('deleted', 0);
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $module_id
- * @return bool
- */
- public function show_locations(string $module_id = 'items'): bool
- {
- $stock_locations = $this->get_allowed_locations($module_id);
+ /**
+ * @param string $module_id
+ * @return bool
+ */
+ public function show_locations(string $module_id = 'items'): bool
+ {
+ $stock_locations = $this->get_allowed_locations($module_id);
- return count($stock_locations) > 1;
- }
+ return count($stock_locations) > 1;
+ }
- /**
- * @return bool
- */
- public function multiple_locations(): bool
- {
- return $this->get_all()->getNumRows() > 1;
- }
+ /**
+ * @return bool
+ */
+ public function multiple_locations(): bool
+ {
+ return $this->get_all()->getNumRows() > 1;
+ }
- /**
- * @param string $module_id
- * @return array
- */
- public function get_allowed_locations(string $module_id = 'items'): array
- {
- $stock = $this->get_undeleted_all($module_id)->getResultArray();
- $stock_locations = [];
+ /**
+ * @param string $module_id
+ * @return array
+ */
+ public function get_allowed_locations(string $module_id = 'items'): array
+ {
+ $stock = $this->get_undeleted_all($module_id)->getResultArray();
+ $stock_locations = [];
- foreach($stock as $location_data)
- {
- $stock_locations[$location_data['location_id']] = $location_data['location_name'];
- }
+ foreach($stock as $location_data)
+ {
+ $stock_locations[$location_data['location_id']] = $location_data['location_name'];
+ }
- return $stock_locations;
- }
+ return $stock_locations;
+ }
- /**
- * @param int $location_id
- * @param string $module_id
- * @return bool
- */
- public function is_allowed_location(int $location_id, string $module_id = 'items'): bool
- {
- $builder = $this->db->table('stock_locations');
- $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
- $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
- $builder->where('person_id', $this->session->get('person_id'));
- $builder->like('permissions.permission_id', $module_id, 'after');
- $builder->where('stock_locations.location_id', $location_id);
- $builder->where('deleted', 0);
+ /**
+ * @param int $location_id
+ * @param string $module_id
+ * @return bool
+ */
+ public function is_allowed_location(int $location_id, string $module_id = 'items'): bool
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
+ $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
+ $builder->where('person_id', $this->session->get('person_id'));
+ $builder->like('permissions.permission_id', $module_id, 'after');
+ $builder->where('stock_locations.location_id', $location_id);
+ $builder->where('deleted', 0);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * @param string $module_id
- * @return int
- */
- public function get_default_location_id(string $module_id = 'items'): int
- {
- $builder = $this->db->table('stock_locations');
- $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
- $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
- $builder->where('person_id', $this->session->get('person_id'));
- $builder->like('permissions.permission_id', $module_id, 'after');
- $builder->where('deleted', 0);
- $builder->limit(1);
+ /**
+ * @param string $module_id
+ * @return int
+ */
+ public function get_default_location_id(string $module_id = 'items'): int
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->join('permissions AS permissions', 'permissions.location_id = stock_locations.location_id');
+ $builder->join('grants AS grants', 'grants.permission_id = permissions.permission_id');
+ $builder->where('person_id', $this->session->get('person_id'));
+ $builder->like('permissions.permission_id', $module_id, 'after');
+ $builder->where('deleted', 0);
+ $builder->limit(1);
- return $builder->get()->getRow()->location_id; //TODO: this is puking. Trying to get property 'location_id' of non-object
- }
+ return $builder->get()->getRow()->location_id; //TODO: this is puking. Trying to get property 'location_id' of non-object
+ }
- /**
- * @param int $location_id
- * @return string
- */
- public function get_location_name(int $location_id): string
- {
- $builder = $this->db->table('stock_locations');
- $builder->where('location_id', $location_id);
+ /**
+ * @param int $location_id
+ * @return string
+ */
+ public function get_location_name(int $location_id): string
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->where('location_id', $location_id);
- return $builder->get()->getRow()->location_name;
- }
+ return $builder->get()->getRow()->location_name;
+ }
- /**
- * @param string $location_name
- * @return int
- */
- public function get_location_id(string $location_name): int
- {
- $builder = $this->db->table('stock_locations');
- $builder->where('location_name', $location_name);
+ /**
+ * @param string $location_name
+ * @return int
+ */
+ public function get_location_id(string $location_name): int
+ {
+ $builder = $this->db->table('stock_locations');
+ $builder->where('location_name', $location_name);
- return $builder->get()->getRow()->location_id;
- }
+ return $builder->get()->getRow()->location_id;
+ }
- /**
- * @param array $location_data
- * @param int $location_id
- * @return bool
- */
- public function save_value(array &$location_data, int $location_id): bool
- {
- $location_name = $location_data['location_name'];
+ /**
+ * @param array $location_data
+ * @param int $location_id
+ * @return bool
+ */
+ public function save_value(array &$location_data, int $location_id): bool
+ {
+ $location_name = $location_data['location_name'];
- $location_data_to_save = ['location_name' => $location_name, 'deleted' => 0];
+ $location_data_to_save = ['location_name' => $location_name, 'deleted' => 0];
- if(!$this->exists($location_id))
- {
- $this->db->transStart();
+ if(!$this->exists($location_id))
+ {
+ $this->db->transStart();
- $builder = $this->db->table('stock_locations');
- $builder->insert($location_data_to_save);
- $location_id = $this->db->insertID();
+ $builder = $this->db->table('stock_locations');
+ $builder->insert($location_data_to_save);
+ $location_id = $this->db->insertID();
- $this->_insert_new_permission('items', $location_id, $location_name); //TODO: need to refactor out the hungarian notation.
- $this->_insert_new_permission('sales', $location_id, $location_name);
- $this->_insert_new_permission('receivings', $location_id, $location_name);
+ $this->_insert_new_permission('items', $location_id, $location_name); //TODO: need to refactor out the hungarian notation.
+ $this->_insert_new_permission('sales', $location_id, $location_name);
+ $this->_insert_new_permission('receivings', $location_id, $location_name);
- // insert quantities for existing items
- $item = model(Item::class);
- $builder = $this->db->table('item_quantities');
- $items = $item->get_all();
+ // insert quantities for existing items
+ $item = model(Item::class);
+ $builder = $this->db->table('item_quantities');
+ $items = $item->get_all();
- foreach($items->getResultArray() as $item)
- {
- $quantity_data = [
- 'item_id' => $item['item_id'],
- 'location_id' => $location_id,
- 'quantity' => 0
- ];
- $builder->insert($quantity_data);
- }
+ foreach($items->getResultArray() as $item)
+ {
+ $quantity_data = [
+ 'item_id' => $item['item_id'],
+ 'location_id' => $location_id,
+ 'quantity' => 0
+ ];
+ $builder->insert($quantity_data);
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- return $this->db->transStatus();
- }
+ return $this->db->transStatus();
+ }
- $original_location_name = $this->get_location_name($location_id);
+ $original_location_name = $this->get_location_name($location_id);
- if($original_location_name != $location_name)
- {
- $builder = $this->db->table('permissions');
- $builder->delete(['location_id' => $location_id]);
+ if($original_location_name != $location_name)
+ {
+ $builder = $this->db->table('permissions');
+ $builder->delete(['location_id' => $location_id]);
- $this->_insert_new_permission('items', $location_id, $location_name);
- $this->_insert_new_permission('sales', $location_id, $location_name);
- $this->_insert_new_permission('receivings', $location_id, $location_name);
- }
+ $this->_insert_new_permission('items', $location_id, $location_name);
+ $this->_insert_new_permission('sales', $location_id, $location_name);
+ $this->_insert_new_permission('receivings', $location_id, $location_name);
+ }
- $builder = $this->db->table('stock_locations');
- $builder->where('location_id', $location_id);
+ $builder = $this->db->table('stock_locations');
+ $builder->where('location_id', $location_id);
- return $builder->update($location_data_to_save);
- }
+ return $builder->update($location_data_to_save);
+ }
- /**
- * @param string $module
- * @param int $location_id
- * @param string $location_name
- * @return void
- */
- private function _insert_new_permission(string $module, int $location_id, string $location_name): void //TODO: refactor out hungarian notation
- {
- // insert new permission for stock location
- $permission_id = $module . '_' . str_replace(' ', '_', $location_name); //TODO: String interpolation
- $permission_data = ['permission_id' => $permission_id, 'module_id' => $module, 'location_id' => $location_id];
+ /**
+ * @param string $module
+ * @param int $location_id
+ * @param string $location_name
+ * @return void
+ */
+ private function _insert_new_permission(string $module, int $location_id, string $location_name): void //TODO: refactor out hungarian notation
+ {
+ // insert new permission for stock location
+ $permission_id = $module . '_' . str_replace(' ', '_', $location_name); //TODO: String interpolation
+ $permission_data = ['permission_id' => $permission_id, 'module_id' => $module, 'location_id' => $location_id];
- $builder = $this->db->table('permissions');
- $builder->insert($permission_data);
+ $builder = $this->db->table('permissions');
+ $builder->insert($permission_data);
- // insert grants for new permission
- $employee = model(Employee::class);
- $employees = $employee->get_all();
+ // insert grants for new permission
+ $employee = model(Employee::class);
+ $employees = $employee->get_all();
- $builder = $this->db->table('grants');
+ $builder = $this->db->table('grants');
- foreach($employees->getResultArray() as $employee)
- {
- $this->employee = model(Employee::class);
+ foreach($employees->getResultArray() as $employee)
+ {
+ $this->employee = model(Employee::class);
- // Retrieve the menu_group assigned to the grant for the module and use that for the new stock locations
- $menu_group = $this->employee->get_menu_group($module, $employee['person_id']);
+ // Retrieve the menu_group assigned to the grant for the module and use that for the new stock locations
+ $menu_group = $this->employee->get_menu_group($module, $employee['person_id']);
- $grants_data = ['permission_id' => $permission_id, 'person_id' => $employee['person_id'], 'menu_group' => $menu_group];
+ $grants_data = ['permission_id' => $permission_id, 'person_id' => $employee['person_id'], 'menu_group' => $menu_group];
- $builder->insert($grants_data);
- }
- }
+ $builder->insert($grants_data);
+ }
+ }
- /**
- * Deletes one item
- * @param int|null $location_id
- * @param bool $purge
- * @return bool
- */
- public function delete($location_id = null, bool $purge = false): bool
- {
- $this->db->transStart();
+ /**
+ * Deletes one item
+ * @param int|null $location_id
+ * @param bool $purge
+ * @return bool
+ */
+ public function delete($location_id = null, bool $purge = false): bool
+ {
+ $this->db->transStart();
- $builder = $this->db->table('stock_locations');
- $builder->where('location_id', $location_id);
- $builder->update(['deleted' => 1]);
+ $builder = $this->db->table('stock_locations');
+ $builder->where('location_id', $location_id);
+ $builder->update(['deleted' => 1]);
- $builder = $this->db->table('permissions');
- $builder->delete(['location_id' => $location_id]);
+ $builder = $this->db->table('permissions');
+ $builder->delete(['location_id' => $location_id]);
- $this->db->transComplete();
+ $this->db->transComplete();
- return $this->db->transStatus();
- }
+ return $this->db->transStatus();
+ }
}
diff --git a/app/Models/Supplier.php b/app/Models/Supplier.php
index 6bdc9618a..ccacf2645 100644
--- a/app/Models/Supplier.php
+++ b/app/Models/Supplier.php
@@ -9,330 +9,330 @@ use CodeIgniter\Database\ResultInterface;
*/
class Supplier extends Person
{
- protected $table = 'suppliers';
- protected $primaryKey = 'person_id';
- protected $useAutoIncrement = false;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'company_name',
- 'account_number',
- 'tax_id',
- 'deleted',
- 'agency_name',
- 'category'
- ];
+ protected $table = 'suppliers';
+ protected $primaryKey = 'person_id';
+ protected $useAutoIncrement = false;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'company_name',
+ 'account_number',
+ 'tax_id',
+ 'deleted',
+ 'agency_name',
+ 'category'
+ ];
- /**
- * Determines if a given person_id is a customer
- */
- public function exists(int $person_id): bool
- {
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'people.person_id = suppliers.person_id');
- $builder->where('suppliers.person_id', $person_id);
+ /**
+ * Determines if a given person_id is a customer
+ */
+ public function exists(int $person_id): bool
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'people.person_id = suppliers.person_id');
+ $builder->where('suppliers.person_id', $person_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('suppliers');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Returns all the suppliers
- */
- public function get_all(int $limit = 0, int $offset = 0, int $category = GOODS_SUPPLIER): ResultInterface
- {
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('category', $category);
- $builder->where('deleted', 0);
- $builder->orderBy('company_name', 'asc');
+ /**
+ * Returns all the suppliers
+ */
+ public function get_all(int $limit = 0, int $offset = 0, int $category = GOODS_SUPPLIER): ResultInterface
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('category', $category);
+ $builder->where('deleted', 0);
+ $builder->orderBy('company_name', 'asc');
- if($limit > 0)
- {
- $builder->limit($limit, $offset);
- }
+ if($limit > 0)
+ {
+ $builder->limit($limit, $offset);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets information about a particular supplier
- */
- public function get_info(?int $person_id): object
- {
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'people.person_id = suppliers.person_id');
- $builder->where('suppliers.person_id', $person_id);
- $query = $builder->get();
+ /**
+ * Gets information about a particular supplier
+ */
+ public function get_info(?int $person_id): object
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'people.person_id = suppliers.person_id');
+ $builder->where('suppliers.person_id', $person_id);
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object, as $supplier_id is NOT a supplier
- $person_obj = parent::get_info(NEW_ENTRY);
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object, as $supplier_id is NOT a supplier
+ $person_obj = parent::get_info(NEW_ENTRY);
- //Get all the fields from supplier table
- //append those fields to base parent object, we have a complete empty object
- foreach($this->db->getFieldNames('suppliers') as $field)
- {
- $person_obj->$field = '';
- }
+ //Get all the fields from supplier table
+ //append those fields to base parent object, we have a complete empty object
+ foreach($this->db->getFieldNames('suppliers') as $field)
+ {
+ $person_obj->$field = '';
+ }
- return $person_obj;
- }
- }
+ return $person_obj;
+ }
+ }
- /**
- * Gets information about multiple suppliers
- */
- public function get_multiple_info(array $person_ids): ResultInterface
- {
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'people.person_id = suppliers.person_id');
- $builder->whereIn('suppliers.person_id', $person_ids);
- $builder->orderBy('last_name', 'asc');
+ /**
+ * Gets information about multiple suppliers
+ */
+ public function get_multiple_info(array $person_ids): ResultInterface
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'people.person_id = suppliers.person_id');
+ $builder->whereIn('suppliers.person_id', $person_ids);
+ $builder->orderBy('last_name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a suppliers
- */
- public function save_supplier(array &$person_data, array &$supplier_data, int $supplier_id = NEW_ENTRY): bool
- {
- $success = false;
+ /**
+ * Inserts or updates a suppliers
+ */
+ public function save_supplier(array &$person_data, array &$supplier_data, int $supplier_id = NEW_ENTRY): bool
+ {
+ $success = false;
- //Run these queries as a transaction, we want to make sure we do all or nothing
- $this->db->transStart();
+ //Run these queries as a transaction, we want to make sure we do all or nothing
+ $this->db->transStart();
- if(parent::save_value($person_data,$supplier_id))
- {
- $builder = $this->db->table('suppliers');
- if($supplier_id == NEW_ENTRY || !$this->exists($supplier_id))
- {
- $supplier_data['person_id'] = $person_data['person_id'];
- $success = $builder->insert($supplier_data);
- }
- else
- {
- $builder->where('person_id', $supplier_id);
- $success = $builder->update($supplier_data);
- }
- }
+ if(parent::save_value($person_data,$supplier_id))
+ {
+ $builder = $this->db->table('suppliers');
+ if($supplier_id == NEW_ENTRY || !$this->exists($supplier_id))
+ {
+ $supplier_data['person_id'] = $person_data['person_id'];
+ $success = $builder->insert($supplier_data);
+ }
+ else
+ {
+ $builder->where('person_id', $supplier_id);
+ $success = $builder->update($supplier_data);
+ }
+ }
- $this->db->transComplete();
+ $this->db->transComplete();
- $success &= $this->db->transStatus();
+ $success &= $this->db->transStatus();
- return $success;
- }
+ return $success;
+ }
- /**
- * Deletes one supplier
- */
- public function delete($supplier_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('suppliers');
- $builder->where('person_id', $supplier_id);
+ /**
+ * Deletes one supplier
+ */
+ public function delete($supplier_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->where('person_id', $supplier_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Deletes a list of suppliers
- */
- public function delete_list(array $person_ids): bool
- {
- $builder = $this->db->table('suppliers');
- $builder->whereIn('person_id', $person_ids);
+ /**
+ * Deletes a list of suppliers
+ */
+ public function delete_list(array $person_ids): bool
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->whereIn('person_id', $person_ids);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Get search suggestions to find suppliers
- */
- public function get_search_suggestions(string $search, int $limit = 25, bool $unique = false): array //TODO: Parent is looking for the 2nd parameter to be an int
- {
- $suggestions = [];
+ /**
+ * Get search suggestions to find suppliers
+ */
+ public function get_search_suggestions(string $search, int $limit = 25, bool $unique = false): array //TODO: Parent is looking for the 2nd parameter to be an int
+ {
+ $suggestions = [];
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('company_name', $search);
- $builder->orderBy('company_name', 'asc');
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('company_name', $search);
+ $builder->orderBy('company_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->company_name];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->company_name];
+ }
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->distinct();
- $builder->like('agency_name', $search);
- $builder->where('agency_name IS NOT NULL');
- $builder->orderBy('agency_name', 'asc');
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->distinct();
+ $builder->like('agency_name', $search);
+ $builder->where('agency_name IS NOT NULL');
+ $builder->orderBy('agency_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->agency_name];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->agency_name];
+ }
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
- $builder->orderBy('last_name', 'asc');
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
+ $builder->orderBy('last_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->first_name . ' ' . $row->last_name];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->first_name . ' ' . $row->last_name];
+ }
- if(!$unique)
- {
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('email', $search);
- $builder->orderBy('email', 'asc');
+ if(!$unique)
+ {
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('email', $search);
+ $builder->orderBy('email', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->email];
+ }
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('phone_number', $search);
- $builder->orderBy('phone_number', 'asc');
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('phone_number', $search);
+ $builder->orderBy('phone_number', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->phone_number];
+ }
- $builder = $this->db->table('suppliers');
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->where('deleted', 0);
- $builder->like('account_number', $search);
- $builder->orderBy('account_number', 'asc');
+ $builder = $this->db->table('suppliers');
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->where('deleted', 0);
+ $builder->like('account_number', $search);
+ $builder->orderBy('account_number', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->person_id, 'label' => $row->account_number];
- }
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->person_id, 'label' => $row->account_number];
+ }
+ }
- //only return $limit suggestions
- if(count($suggestions) > $limit) //TODO: this can be replaced with return count($suggestions) > $limit ? array_slice($suggestions, 0, $limit) : $suggestions
- {
- $suggestions = array_slice($suggestions, 0, $limit);
- }
+ //only return $limit suggestions
+ if(count($suggestions) > $limit) //TODO: this can be replaced with return count($suggestions) > $limit ? array_slice($suggestions, 0, $limit) : $suggestions
+ {
+ $suggestions = array_slice($suggestions, 0, $limit);
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'last_name', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'last_name', 'asc', true);
+ }
- /**
- * Perform a search on suppliers
- */
- public function search(string $search, ?int $rows = 25, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- //Set default values on null
- $rows = $rows ?? 25;
- $limit_from = $limit_from ?? 0;
- $sort = $sort ?? 'last_name';
- $order = $order ?? 'asc';
- $count_only = $count_only ?? false;
+ /**
+ * Perform a search on suppliers
+ */
+ public function search(string $search, ?int $rows = 25, ?int $limit_from = 0, ?string $sort = 'last_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ //Set default values on null
+ $rows = $rows ?? 25;
+ $limit_from = $limit_from ?? 0;
+ $sort = $sort ?? 'last_name';
+ $order = $order ?? 'asc';
+ $count_only = $count_only ?? false;
- $builder = $this->db->table('suppliers AS suppliers');
+ $builder = $this->db->table('suppliers AS suppliers');
- //get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(suppliers.person_id) as count');
- }
+ //get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(suppliers.person_id) as count');
+ }
- $builder->join('people', 'suppliers.person_id = people.person_id');
- $builder->groupStart();
- $builder->like('first_name', $search);
- $builder->orLike('last_name', $search);
- $builder->orLike('company_name', $search);
- $builder->orLike('agency_name', $search);
- $builder->orLike('email', $search);
- $builder->orLike('phone_number', $search);
- $builder->orLike('account_number', $search);
- $builder->orLike('CONCAT(first_name, " ", last_name)', $search); //TODO: According to PHPStorm, this line down to the return is repeated in Customer.php and Employee.php... perhaps refactoring a method in a library could be helpful?
- $builder->groupEnd();
- $builder->where('deleted', 0);
+ $builder->join('people', 'suppliers.person_id = people.person_id');
+ $builder->groupStart();
+ $builder->like('first_name', $search);
+ $builder->orLike('last_name', $search);
+ $builder->orLike('company_name', $search);
+ $builder->orLike('agency_name', $search);
+ $builder->orLike('email', $search);
+ $builder->orLike('phone_number', $search);
+ $builder->orLike('account_number', $search);
+ $builder->orLike('CONCAT(first_name, " ", last_name)', $search); //TODO: According to PHPStorm, this line down to the return is repeated in Customer.php and Employee.php... perhaps refactoring a method in a library could be helpful?
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Return supplier categories
- */
- public function get_categories(): array
- {
- return [
- GOODS_SUPPLIER => lang('Suppliers.goods'),
- COST_SUPPLIER => lang('Suppliers.cost')
- ];
- }
+ /**
+ * Return supplier categories
+ */
+ public function get_categories(): array
+ {
+ return [
+ GOODS_SUPPLIER => lang('Suppliers.goods'),
+ COST_SUPPLIER => lang('Suppliers.cost')
+ ];
+ }
- /**
- * Return a category name given its id.
- * @param int $supplier_type Constant representing the type of supplier.
- * @return string Language string for the given supplier type.
- */
- public function get_category_name(int $supplier_type): string
- {
- if($supplier_type == 0)
- {
- return lang('Suppliers.goods');
- }
- else
- {
- return lang('Suppliers.cost');
- }
- }
+ /**
+ * Return a category name given its id.
+ * @param int $supplier_type Constant representing the type of supplier.
+ * @return string Language string for the given supplier type.
+ */
+ public function get_category_name(int $supplier_type): string
+ {
+ if($supplier_type == 0)
+ {
+ return lang('Suppliers.goods');
+ }
+ else
+ {
+ return lang('Suppliers.cost');
+ }
+ }
}
diff --git a/app/Models/Tax.php b/app/Models/Tax.php
index 460135400..02f11b28e 100644
--- a/app/Models/Tax.php
+++ b/app/Models/Tax.php
@@ -11,319 +11,319 @@ use stdClass;
*/
class Tax extends Model
{
- protected $table = 'tax_rates';
- protected $primaryKey = 'tax_rate_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'rate_tax_code_id',
- 'rate_tax_category_id',
- 'rate_jurisdiction_id',
- 'tax_rate',
- 'tax_rounding_code'
- ];
+ protected $table = 'tax_rates';
+ protected $primaryKey = 'tax_rate_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'rate_tax_code_id',
+ 'rate_tax_category_id',
+ 'rate_jurisdiction_id',
+ 'tax_rate',
+ 'tax_rounding_code'
+ ];
- /**
- * Determines if a given row is on file
- */
- public function exists(int $tax_rate_id): bool
- {
- $builder = $this->db->table('tax_rates');
- $builder->where('tax_rate_id', $tax_rate_id);
+ /**
+ * Determines if a given row is on file
+ */
+ public function exists(int $tax_rate_id): bool
+ {
+ $builder = $this->db->table('tax_rates');
+ $builder->where('tax_rate_id', $tax_rate_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('tax_rates');
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('tax_rates');
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets list of tax rates that are assigned to a particular tax category
- */
- public function get_tax_category_usage(int $tax_category_id): int
- {
- $builder = $this->db->table('tax_rates');
- $builder->where('rate_tax_category_id', $tax_category_id);
+ /**
+ * Gets list of tax rates that are assigned to a particular tax category
+ */
+ public function get_tax_category_usage(int $tax_category_id): int
+ {
+ $builder = $this->db->table('tax_rates');
+ $builder->where('rate_tax_category_id', $tax_category_id);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets the row for a particular id
- */
- public function get_info(int $tax_rate_id): object
- {
- $builder = $this->db->table('tax_rates');
- $builder->select('tax_rate_id');
- $builder->select('rate_tax_code_id');
- $builder->select('tax_code');
- $builder->select('tax_code_name');
- $builder->select('rate_jurisdiction_id');
- $builder->select('jurisdiction_name');
- $builder->select('rate_tax_category_id');
- $builder->select('tax_category');
- $builder->select('tax_rate');
- $builder->select('tax_rounding_code');
+ /**
+ * Gets the row for a particular id
+ */
+ public function get_info(int $tax_rate_id): object
+ {
+ $builder = $this->db->table('tax_rates');
+ $builder->select('tax_rate_id');
+ $builder->select('rate_tax_code_id');
+ $builder->select('tax_code');
+ $builder->select('tax_code_name');
+ $builder->select('rate_jurisdiction_id');
+ $builder->select('jurisdiction_name');
+ $builder->select('rate_tax_category_id');
+ $builder->select('tax_category');
+ $builder->select('tax_rate');
+ $builder->select('tax_rounding_code');
- $builder->join('tax_codes',
- 'rate_tax_code_id = tax_code_id', 'LEFT');
- $builder->join('tax_categories',
- 'rate_tax_category_id = tax_category_id', 'LEFT');
- $builder->join('tax_jurisdictions',
- 'rate_jurisdiction_id = jurisdiction_id', 'LEFT');
- $builder->where('tax_rate_id', $tax_rate_id);
+ $builder->join('tax_codes',
+ 'rate_tax_code_id = tax_code_id', 'LEFT');
+ $builder->join('tax_categories',
+ 'rate_tax_category_id = tax_category_id', 'LEFT');
+ $builder->join('tax_jurisdictions',
+ 'rate_jurisdiction_id = jurisdiction_id', 'LEFT');
+ $builder->where('tax_rate_id', $tax_rate_id);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: probably should use === here since getNumRows() returns an int.
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object
- $tax_rate_obj = new stdClass();
- $tax_rate_obj->tax_rate_id = null;
- $tax_rate_obj->rate_tax_code_id = null;
- $tax_rate_obj->tax_code = '';
- $tax_rate_obj->tax_code_name = '';
- $tax_rate_obj->rate_tax_category_id = null;
- $tax_rate_obj->tax_category = '';
- $tax_rate_obj->tax_rate = 0.0;
- $tax_rate_obj->tax_rounding_code = '0';
- $tax_rate_obj->rate_jurisdiction_id = null;
- $tax_rate_obj->jurisdiction_name = '';
+ if($query->getNumRows() == 1) //TODO: probably should use === here since getNumRows() returns an int.
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object
+ $tax_rate_obj = new stdClass();
+ $tax_rate_obj->tax_rate_id = null;
+ $tax_rate_obj->rate_tax_code_id = null;
+ $tax_rate_obj->tax_code = '';
+ $tax_rate_obj->tax_code_name = '';
+ $tax_rate_obj->rate_tax_category_id = null;
+ $tax_rate_obj->tax_category = '';
+ $tax_rate_obj->tax_rate = 0.0;
+ $tax_rate_obj->tax_rounding_code = '0';
+ $tax_rate_obj->rate_jurisdiction_id = null;
+ $tax_rate_obj->jurisdiction_name = '';
- return $tax_rate_obj;
- }
- }
+ return $tax_rate_obj;
+ }
+ }
- /**
- * Get taxes to be collected for a given tax code
- */
- public function get_taxes(int $tax_code_id, int $tax_category_id): array
- {
- $sql = 'select tax_rate_id, rate_tax_code_id, tax_code, tax_code_name, tax_type, cascade_sequence, rate_tax_category_id, tax_category,
- rate_jurisdiction_id, jurisdiction_name, tax_group, tax_rate, tax_rounding_code,tax_categories.tax_group_sequence + tax_jurisdictions.tax_group_sequence as tax_group_sequence
- from ' . $this->db->prefixTable('tax_rates') . '
- left outer join ' . $this->db->prefixTable('tax_codes') . ' on rate_tax_code_id = tax_code_id
- left outer join ' . $this->db->prefixTable('tax_categories') . ' as tax_categories on rate_tax_category_id = tax_category_id
- left outer join ' . $this->db->prefixTable('tax_jurisdictions') . ' as tax_jurisdictions on rate_jurisdiction_id = jurisdiction_id
- where rate_tax_code_id = ' . $this->db->escape($tax_code_id) . ' and rate_tax_category_id = ' . $this->db->escape($tax_category_id) . '
- order by cascade_sequence, tax_group, jurisdiction_name, tax_jurisdictions.tax_group_sequence + tax_categories.tax_group_sequence';
+ /**
+ * Get taxes to be collected for a given tax code
+ */
+ public function get_taxes(int $tax_code_id, int $tax_category_id): array
+ {
+ $sql = 'select tax_rate_id, rate_tax_code_id, tax_code, tax_code_name, tax_type, cascade_sequence, rate_tax_category_id, tax_category,
+ rate_jurisdiction_id, jurisdiction_name, tax_group, tax_rate, tax_rounding_code,tax_categories.tax_group_sequence + tax_jurisdictions.tax_group_sequence as tax_group_sequence
+ from ' . $this->db->prefixTable('tax_rates') . '
+ left outer join ' . $this->db->prefixTable('tax_codes') . ' on rate_tax_code_id = tax_code_id
+ left outer join ' . $this->db->prefixTable('tax_categories') . ' as tax_categories on rate_tax_category_id = tax_category_id
+ left outer join ' . $this->db->prefixTable('tax_jurisdictions') . ' as tax_jurisdictions on rate_jurisdiction_id = jurisdiction_id
+ where rate_tax_code_id = ' . $this->db->escape($tax_code_id) . ' and rate_tax_category_id = ' . $this->db->escape($tax_category_id) . '
+ order by cascade_sequence, tax_group, jurisdiction_name, tax_jurisdictions.tax_group_sequence + tax_categories.tax_group_sequence';
- $query = $this->db->query($sql);
+ $query = $this->db->query($sql);
- return $query->getResultArray() ?: [];
- }
+ return $query->getResultArray() ?: [];
+ }
- /**
- * Gets information about a particular tax_code
- */
- public function get_rate_info(int $tax_code_id, int $tax_category_id): object
- {
- $builder = $this->db->table('tax_rates');
- $builder->join('tax_categories', 'rate_tax_category_id = tax_category_id');
- $builder->where('rate_tax_code_id', $tax_code_id);
- $builder->where('rate_tax_category_id', $tax_category_id);
+ /**
+ * Gets information about a particular tax_code
+ */
+ public function get_rate_info(int $tax_code_id, int $tax_category_id): object
+ {
+ $builder = $this->db->table('tax_rates');
+ $builder->join('tax_categories', 'rate_tax_category_id = tax_category_id');
+ $builder->where('rate_tax_code_id', $tax_code_id);
+ $builder->where('rate_tax_category_id', $tax_category_id);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: this should probably be ===
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object
- $tax_rate_obj = new stdClass();
+ if($query->getNumRows() == 1) //TODO: this should probably be ===
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object
+ $tax_rate_obj = new stdClass();
- //Get all the fields from tax_codes table
- foreach($this->db->getFieldNames('tax_rates') as $field)
- {
- $tax_rate_obj->$field = '';
- }
- //Get all the fields from tax_rates table
- foreach($this->db->getFieldNames('tax_categories') as $field)
- {
- $tax_rate_obj->$field = '';
- }
+ //Get all the fields from tax_codes table
+ foreach($this->db->getFieldNames('tax_rates') as $field)
+ {
+ $tax_rate_obj->$field = '';
+ }
+ //Get all the fields from tax_rates table
+ foreach($this->db->getFieldNames('tax_categories') as $field)
+ {
+ $tax_rate_obj->$field = '';
+ }
- return $tax_rate_obj;
- }
- }
+ return $tax_rate_obj;
+ }
+ }
- /**
- Inserts or updates a tax_rates entry
- */
- public function save_value(array &$tax_rate_data, int $tax_rate_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('tax_rates');
- if($tax_rate_id == NEW_ENTRY || !$this->exists($tax_rate_id))
- {
- if($builder->insert($tax_rate_data))
- {
- $tax_rate_data['tax_rate_id'] = $this->db->insertID();
+ /**
+ Inserts or updates a tax_rates entry
+ */
+ public function save_value(array &$tax_rate_data, int $tax_rate_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('tax_rates');
+ if($tax_rate_id == NEW_ENTRY || !$this->exists($tax_rate_id))
+ {
+ if($builder->insert($tax_rate_data))
+ {
+ $tax_rate_data['tax_rate_id'] = $this->db->insertID();
- return true;
- }
- }
- else
- {
- $builder->where('tax_rate_id', $tax_rate_id);
+ return true;
+ }
+ }
+ else
+ {
+ $builder->where('tax_rate_id', $tax_rate_id);
- if($builder->update($tax_rate_data))
- {
- return true;
- }
- }
+ if($builder->update($tax_rate_data))
+ {
+ return true;
+ }
+ }
- return false;
- }
+ return false;
+ }
- /**
- * Deletes a single tax rate entry
- */
- public function delete($tax_rate_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('tax_rates');
+ /**
+ * Deletes a single tax rate entry
+ */
+ public function delete($tax_rate_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('tax_rates');
- return $builder->delete(['tax_rate_id' => $tax_rate_id]);
- }
+ return $builder->delete(['tax_rate_id' => $tax_rate_id]);
+ }
- /**
- * Deletes a list of tax rates
- */
- public function delete_list(array $tax_rate_ids): bool
- {
- $builder = $this->db->table('tax_rates');
- $builder->whereIn('tax_rate_id', $tax_rate_ids);
+ /**
+ * Deletes a list of tax rates
+ */
+ public function delete_list(array $tax_rate_ids): bool
+ {
+ $builder = $this->db->table('tax_rates');
+ $builder->whereIn('tax_rate_id', $tax_rate_ids);
- return $builder->delete();
- }
+ return $builder->delete();
+ }
- /**
- * Gets tax_codes
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'tax_code_name', 'asc', true);
- }
+ /**
+ * Gets tax_codes
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'tax_code_name', 'asc', true);
+ }
- /**
- * Performs a search on tax_rates
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_code_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'tax_code_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Performs a search on tax_rates
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_code_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'tax_code_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('tax_rates');
+ $builder = $this->db->table('tax_rates');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(tax_rate_id) as count');
- } else
- {
- $builder->select('tax_rate_id');
- $builder->select('tax_code');
- $builder->select('rate_tax_code_id');
- $builder->select('tax_code_name');
- $builder->select('rate_jurisdiction_id');
- $builder->select('jurisdiction_name');
- $builder->select('rate_tax_category_id');
- $builder->select('tax_category');
- $builder->select('tax_rate');
- $builder->select('tax_rounding_code');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(tax_rate_id) as count');
+ } else
+ {
+ $builder->select('tax_rate_id');
+ $builder->select('tax_code');
+ $builder->select('rate_tax_code_id');
+ $builder->select('tax_code_name');
+ $builder->select('rate_jurisdiction_id');
+ $builder->select('jurisdiction_name');
+ $builder->select('rate_tax_category_id');
+ $builder->select('tax_category');
+ $builder->select('tax_rate');
+ $builder->select('tax_rounding_code');
+ }
- $builder->join('tax_codes', 'rate_tax_code_id = tax_code_id', 'LEFT');
- $builder->join('tax_categories', 'rate_tax_category_id = tax_category_id', 'LEFT');
- $builder->join('tax_jurisdictions', 'rate_jurisdiction_id = jurisdiction_id', 'LEFT');
+ $builder->join('tax_codes', 'rate_tax_code_id = tax_code_id', 'LEFT');
+ $builder->join('tax_categories', 'rate_tax_category_id = tax_category_id', 'LEFT');
+ $builder->join('tax_jurisdictions', 'rate_jurisdiction_id = jurisdiction_id', 'LEFT');
- if(!empty($search))
- {
- $builder->like('rate_tax_code', $search);
- $builder->orLike('tax_code_name', $search);
- }
+ if(!empty($search))
+ {
+ $builder->like('rate_tax_code', $search);
+ $builder->orLike('tax_code_name', $search);
+ }
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $tax_code_type
- * @return string
- */
- public function get_tax_code_type_name(string $tax_code_type): string //TODO: if this is being called from the view and passed through GET params then it will come through as a string... better if we can get it as an int though.
- {
- if($tax_code_type == '0') //TODO: ===. Also, replace this with ternary notation. The whole function becomes a nice one-liner.
- {
- return lang('Taxes.tax_included');
- }
- else
- {
- return lang('Taxes.tax_excluded');
- }
- }
+ /**
+ * @param string $tax_code_type
+ * @return string
+ */
+ public function get_tax_code_type_name(string $tax_code_type): string //TODO: if this is being called from the view and passed through GET params then it will come through as a string... better if we can get it as an int though.
+ {
+ if($tax_code_type == '0') //TODO: ===. Also, replace this with ternary notation. The whole function becomes a nice one-liner.
+ {
+ return lang('Taxes.tax_included');
+ }
+ else
+ {
+ return lang('Taxes.tax_excluded');
+ }
+ }
- /**
- * @param int $tax_category_id
- * @return string
- */
- public function get_tax_category(int $tax_category_id): string
- {
- $builder = $this->db->table('tax_categories');
- $builder->select('tax_category');
- $builder->where('tax_category_id', $tax_category_id);
+ /**
+ * @param int $tax_category_id
+ * @return string
+ */
+ public function get_tax_category(int $tax_category_id): string
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->select('tax_category');
+ $builder->where('tax_category_id', $tax_category_id);
- return $builder->get()->getRow()->tax_category;
- }
+ return $builder->get()->getRow()->tax_category;
+ }
- /**
- * @return ResultInterface
- */
- public function get_all_tax_categories(): ResultInterface
- {
- $builder = $this->db->table('tax_categories');
- $builder->orderBy('tax_category_id');
+ /**
+ * @return ResultInterface
+ */
+ public function get_all_tax_categories(): ResultInterface
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->orderBy('tax_category_id');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $tax_category
- * @return int
- */
- public function get_tax_category_id(string $tax_category): int //TODO: $tax_category is not used in this function and get_tax_category_id() is not called in the code. It may be that this needs to be deprecated and removed.
- {
- $builder = $this->db->table('tax_categories');
- $builder->select('tax_category_id');
+ /**
+ * @param string $tax_category
+ * @return int
+ */
+ public function get_tax_category_id(string $tax_category): int //TODO: $tax_category is not used in this function and get_tax_category_id() is not called in the code. It may be that this needs to be deprecated and removed.
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->select('tax_category_id');
- return $builder->get()->getRow()->tax_category_id;
- }
+ return $builder->get()->getRow()->tax_category_id;
+ }
}
diff --git a/app/Models/Tax_category.php b/app/Models/Tax_category.php
index d73e03702..606605180 100644
--- a/app/Models/Tax_category.php
+++ b/app/Models/Tax_category.php
@@ -12,276 +12,276 @@ use stdClass;
class Tax_category extends Model
{
- protected $table = 'tax_categories';
- protected $primaryKey = 'tax_category_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'tax_category',
- 'tax_group_sequence',
- 'deleted'
- ];
+ protected $table = 'tax_categories';
+ protected $primaryKey = 'tax_category_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'tax_category',
+ 'tax_group_sequence',
+ 'deleted'
+ ];
- /**
- * Determines if it exists in the table
- */
- public function exists(int $tax_category_id): bool
- {
- $builder = $this->db->table('tax_categories');
- $builder->where('tax_category_id', $tax_category_id);
+ /**
+ * Determines if it exists in the table
+ */
+ public function exists(int $tax_category_id): bool
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->where('tax_category_id', $tax_category_id);
- return ($builder->get()->getNumRows() == 1); //TODO: probably should be ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: probably should be ===
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('tax_categories');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about the particular record
- */
- public function get_info(int $tax_category_id): object
- {
- $builder = $this->db->table('tax_categories');
- $builder->where('tax_category_id', $tax_category_id);
- $builder->where('deleted', 0);
- $query = $builder->get();
+ /**
+ * Gets information about the particular record
+ */
+ public function get_info(int $tax_category_id): object
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->where('tax_category_id', $tax_category_id);
+ $builder->where('deleted', 0);
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: probably should be === since getNumRows returns an int
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object
- $tax_category_obj = new stdClass();
+ if($query->getNumRows() == 1) //TODO: probably should be === since getNumRows returns an int
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object
+ $tax_category_obj = new stdClass();
- //Get all the fields from the table
- foreach($this->db->getFieldNames('tax_categories') as $field)
- {
- $tax_category_obj->$field = ''; //TODO: This logic doesn't make sense to me... it appears that each field is being assigned to '' rather than the result. Shouldn't this be $tax_category_obj->field = $field;?
- }
- return $tax_category_obj;
- }
- }
+ //Get all the fields from the table
+ foreach($this->db->getFieldNames('tax_categories') as $field)
+ {
+ $tax_category_obj->$field = ''; //TODO: This logic doesn't make sense to me... it appears that each field is being assigned to '' rather than the result. Shouldn't this be $tax_category_obj->field = $field;?
+ }
+ return $tax_category_obj;
+ }
+ }
- /**
- * Returns all rows from the table
- *///TODO: I think we should work toward having all these get_all functions with the same signature. It makes it easier to use them. This signature is different from the others.
- public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface //TODO: $no_deleted needs a new name. $not_deleted is the correct grammar, but it's a bit confusing by naming the variable a negative. Probably better to name it is_deleted and flip the logic
- {
- $builder = $this->db->table('tax_categories');
- if($no_deleted)
- {
- $builder->where('deleted', 0);
- }
+ /**
+ * Returns all rows from the table
+ *///TODO: I think we should work toward having all these get_all functions with the same signature. It makes it easier to use them. This signature is different from the others.
+ public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface //TODO: $no_deleted needs a new name. $not_deleted is the correct grammar, but it's a bit confusing by naming the variable a negative. Probably better to name it is_deleted and flip the logic
+ {
+ $builder = $this->db->table('tax_categories');
+ if($no_deleted)
+ {
+ $builder->where('deleted', 0);
+ }
- $builder->orderBy('tax_group_sequence', 'asc');
- $builder->orderBy('tax_category', 'asc');
+ $builder->orderBy('tax_group_sequence', 'asc');
+ $builder->orderBy('tax_category', 'asc');
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Returns multiple rows
- */
- public function get_multiple_info(array $tax_category_ids): ResultInterface
- {
- $builder = $this->db->table('tax_categories');
- $builder->whereIn('tax_category_id', $tax_category_ids);
- $builder->orderBy('tax_category', 'asc');
+ /**
+ * Returns multiple rows
+ */
+ public function get_multiple_info(array $tax_category_ids): ResultInterface
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->whereIn('tax_category_id', $tax_category_ids);
+ $builder->orderBy('tax_category', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a row
- */
- public function save_value(array &$tax_category_data, int $tax_category_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('tax_categories');
+ /**
+ * Inserts or updates a row
+ */
+ public function save_value(array &$tax_category_data, int $tax_category_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('tax_categories');
- if($tax_category_id == NEW_ENTRY || !$this->exists($tax_category_id))
- {
- if($builder->insert($tax_category_data))
- {
- $tax_category_data['tax_category_id'] = $this->db->insertID();
+ if($tax_category_id == NEW_ENTRY || !$this->exists($tax_category_id))
+ {
+ if($builder->insert($tax_category_data))
+ {
+ $tax_category_data['tax_category_id'] = $this->db->insertID();
- return true;
- }
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('tax_category_id', $tax_category_id);
+ $builder->where('tax_category_id', $tax_category_id);
- return $builder->update($tax_category_data);
- }
+ return $builder->update($tax_category_data);
+ }
- /**
- * Saves changes to the tax categories table
- */
- public function save_categories(array $array_save): bool //TODO: $array_save probably needs to be renamed here to $categories or something similar. Datatype in the variable name is a code smell.
- {
- $this->db->transStart();
+ /**
+ * Saves changes to the tax categories table
+ */
+ public function save_categories(array $array_save): bool //TODO: $array_save probably needs to be renamed here to $categories or something similar. Datatype in the variable name is a code smell.
+ {
+ $this->db->transStart();
- $not_to_delete = [];
+ $not_to_delete = [];
- foreach($array_save as $key => $value)
- {
- // save or update
- $tax_category_data = [
- 'tax_category' => $value['tax_category'],
- 'tax_group_sequence' => $value['tax_group_sequence'],
- 'deleted' => '0'
- ];
+ foreach($array_save as $key => $value)
+ {
+ // save or update
+ $tax_category_data = [
+ 'tax_category' => $value['tax_category'],
+ 'tax_group_sequence' => $value['tax_group_sequence'],
+ 'deleted' => '0'
+ ];
- $this->save_value($tax_category_data, $value['tax_category_id']);
+ $this->save_value($tax_category_data, $value['tax_category_id']);
- if($value['tax_category_id'] == NEW_ENTRY)
- {
- $not_to_delete[] = $tax_category_data['tax_category_id'];
- }
- else
- {
- $not_to_delete[] = $value['tax_category_id'];
- }
- }
+ if($value['tax_category_id'] == NEW_ENTRY)
+ {
+ $not_to_delete[] = $tax_category_data['tax_category_id'];
+ }
+ else
+ {
+ $not_to_delete[] = $value['tax_category_id'];
+ }
+ }
- // all entries not available in post will be deleted now
- $deleted_tax_categories = $this->get_all()->getResultArray();
+ // all entries not available in post will be deleted now
+ $deleted_tax_categories = $this->get_all()->getResultArray();
- foreach($deleted_tax_categories as $key => $tax_category_data)
- {
- if(!in_array($tax_category_data['tax_category_id'], $not_to_delete))
- {
- $this->delete($tax_category_data['tax_category_id']);
- }
- }
+ foreach($deleted_tax_categories as $key => $tax_category_data)
+ {
+ if(!in_array($tax_category_data['tax_category_id'], $not_to_delete))
+ {
+ $this->delete($tax_category_data['tax_category_id']);
+ }
+ }
- $this->db->transComplete();
- return $this->db->transStatus();
- }
+ $this->db->transComplete();
+ return $this->db->transStatus();
+ }
- /**
- * Soft delete a specific row
- */
- public function delete($tax_category_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('tax_categories');
- $builder->where('tax_category_id', $tax_category_id);
+ /**
+ * Soft delete a specific row
+ */
+ public function delete($tax_category_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->where('tax_category_id', $tax_category_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Deletes a list of rows
- */
- public function delete_list(array $tax_category_ids): bool
- {
- $builder = $this->db->table('tax_categories');
- $builder->whereIn('tax_category_id', $tax_category_ids);
+ /**
+ * Deletes a list of rows
+ */
+ public function delete_list(array $tax_category_ids): bool
+ {
+ $builder = $this->db->table('tax_categories');
+ $builder->whereIn('tax_category_id', $tax_category_ids);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'tax_category', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'tax_category', 'asc', true);
+ }
- /**
- * Perform a search for a set of rows
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_category', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'tax_category';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Perform a search for a set of rows
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_category', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'tax_category';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('tax_categories AS tax_categories');
+ $builder = $this->db->table('tax_categories AS tax_categories');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(tax_categories.tax_category_id) as count');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(tax_categories.tax_category_id) as count');
+ }
- $builder->like('tax_category', $search);
- $builder->where('deleted', 0);
+ $builder->like('tax_category', $search);
+ $builder->where('deleted', 0);
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @param string $search
- * @return array
- */
- public function get_tax_category_suggestions(string $search): array
- {
- $suggestions = [];
+ /**
+ * @param string $search
+ * @return array
+ */
+ public function get_tax_category_suggestions(string $search): array
+ {
+ $suggestions = [];
- $builder = $this->db->table('tax_categories');
- $builder->where('deleted', 0);
+ $builder = $this->db->table('tax_categories');
+ $builder->where('deleted', 0);
- if(!empty($search))
- {
- $builder->like('tax_category', '%'.$search.'%');
- }
+ if(!empty($search))
+ {
+ $builder->like('tax_category', '%'.$search.'%');
+ }
- $builder->orderBy('tax_category', 'asc');
+ $builder->orderBy('tax_category', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->tax_category_id, 'label' => $row->tax_category];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->tax_category_id, 'label' => $row->tax_category];
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * @return array[]
- */
- public function get_empty_row(): array
- {
- return [
- '0' => [
- 'tax_category_id' => NEW_ENTRY,
- 'tax_category' => '',
- 'tax_group_sequence' => '',
- 'deleted' => ''
- ]
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function get_empty_row(): array
+ {
+ return [
+ '0' => [
+ 'tax_category_id' => NEW_ENTRY,
+ 'tax_category' => '',
+ 'tax_group_sequence' => '',
+ 'deleted' => ''
+ ]
+ ];
+ }
}
diff --git a/app/Models/Tax_code.php b/app/Models/Tax_code.php
index bf3d48aaa..4e8fa8047 100644
--- a/app/Models/Tax_code.php
+++ b/app/Models/Tax_code.php
@@ -12,323 +12,323 @@ use stdClass;
*/
class Tax_code extends Model
{
- protected $table = 'tax_codes';
- protected $primaryKey = 'tax_code_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'tax_code',
- 'tax_code_name',
- 'city',
- 'state',
- 'deleted'
- ];
+ protected $table = 'tax_codes';
+ protected $primaryKey = 'tax_code_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'tax_code',
+ 'tax_code_name',
+ 'city',
+ 'state',
+ 'deleted'
+ ];
- /**
- * Determines if it exists in the table
- */
- public function exists(string $tax_code): bool
- {
- $builder = $this->db->table('tax_codes');
- $builder->where('tax_code', $tax_code);
+ /**
+ * Determines if it exists in the table
+ */
+ public function exists(string $tax_code): bool
+ {
+ $builder = $this->db->table('tax_codes');
+ $builder->where('tax_code', $tax_code);
- return ($builder->get()->getNumRows() == 1); //TODO: this should be === since getNumRows returns an int
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: this should be === since getNumRows returns an int
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('tax_codes');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('tax_codes');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /**
- * Gets information about the particular record
- */
- public function get_info(?int $tax_code_id): object
- {
- if($tax_code_id != null)
- {
- $builder = $this->db->table('tax_codes');
+ /**
+ * Gets information about the particular record
+ */
+ public function get_info(?int $tax_code_id): object
+ {
+ if($tax_code_id != null)
+ {
+ $builder = $this->db->table('tax_codes');
- $builder->where('tax_code_id', $tax_code_id);
- $builder->where('deleted', 0);
- $query = $builder->get();
- }
+ $builder->where('tax_code_id', $tax_code_id);
+ $builder->where('deleted', 0);
+ $query = $builder->get();
+ }
- if($tax_code_id != null && $query->getNumRows() === 1)
- {
- return $query->getRow();
- }
- else
- {
- //Get empty base parent object
- $tax_code_obj = new stdClass();
+ if($tax_code_id != null && $query->getNumRows() === 1)
+ {
+ return $query->getRow();
+ }
+ else
+ {
+ //Get empty base parent object
+ $tax_code_obj = new stdClass();
- //Get all the fields from the table
- foreach($this->db->getFieldNames('tax_codes') as $field)
- {
- $tax_code_obj->$field = null;
- }
- return $tax_code_obj;
- }
- }
+ //Get all the fields from the table
+ foreach($this->db->getFieldNames('tax_codes') as $field)
+ {
+ $tax_code_obj->$field = null;
+ }
+ return $tax_code_obj;
+ }
+ }
- /**
- * Returns all rows from the table
- */
- public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface //TODO: $no_deleted should be something like $is_deleted and flip the logic.
- {
- $builder = $this->db->table('tax_codes');
- if($no_deleted)
- {
- $builder->where('deleted', 0);
- }
+ /**
+ * Returns all rows from the table
+ */
+ public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface //TODO: $no_deleted should be something like $is_deleted and flip the logic.
+ {
+ $builder = $this->db->table('tax_codes');
+ if($no_deleted)
+ {
+ $builder->where('deleted', 0);
+ }
- $builder->orderBy('tax_code_name', 'asc');
+ $builder->orderBy('tax_code_name', 'asc');
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Returns multiple rows
- */
- public function get_multiple_info(array $tax_codes): ResultInterface
- {
- $builder = $this->db->table('tax_codes');
- $builder->whereIn('tax_code', $tax_codes);
- $builder->orderBy('tax_code_name', 'asc');
+ /**
+ * Returns multiple rows
+ */
+ public function get_multiple_info(array $tax_codes): ResultInterface
+ {
+ $builder = $this->db->table('tax_codes');
+ $builder->whereIn('tax_code', $tax_codes);
+ $builder->orderBy('tax_code_name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a row
- */
- public function save($tax_code_data): bool
- {
- $builder = $this->db->table('tax_codes');
+ /**
+ * Inserts or updates a row
+ */
+ public function save($tax_code_data): bool
+ {
+ $builder = $this->db->table('tax_codes');
- if(!$this->exists($tax_code_data['tax_code']))
- {
- if($builder->insert($tax_code_data)) //TODO: this should be refactored to return $builder->insert($tax_code_data); in the same way that $builder->update() below is the return. Look for this in the other save functions as well.
- {
- return true;
- }
- return false;
- }
+ if(!$this->exists($tax_code_data['tax_code']))
+ {
+ if($builder->insert($tax_code_data)) //TODO: this should be refactored to return $builder->insert($tax_code_data); in the same way that $builder->update() below is the return. Look for this in the other save functions as well.
+ {
+ return true;
+ }
+ return false;
+ }
- $builder->where('tax_code', $tax_code_data['tax_code']);
+ $builder->where('tax_code', $tax_code_data['tax_code']);
- return $builder->update($tax_code_data);
- }
+ return $builder->update($tax_code_data);
+ }
- /**
- * Saves changes to the tax codes table
- */
- public function save_tax_codes(array $array_save): bool //TODO: Need to rename $array_save to probably $tax_codes
- {
- $this->db->transStart();
+ /**
+ * Saves changes to the tax codes table
+ */
+ public function save_tax_codes(array $array_save): bool //TODO: Need to rename $array_save to probably $tax_codes
+ {
+ $this->db->transStart();
- $not_to_delete = [];
+ $not_to_delete = [];
- foreach($array_save as $key => $value)
- {
- // save or update
- $tax_code_data = [
- 'tax_code' => $value['tax_code'],
- 'tax_code_name' => $value['tax_code_name'],
- 'city' => $value['city'],
- 'state' => $value['state'],
- 'deleted' => '0'
- ];
- $this->save($tax_code_data);
- $not_to_delete[] = $tax_code_data['tax_code'];
- }
+ foreach($array_save as $key => $value)
+ {
+ // save or update
+ $tax_code_data = [
+ 'tax_code' => $value['tax_code'],
+ 'tax_code_name' => $value['tax_code_name'],
+ 'city' => $value['city'],
+ 'state' => $value['state'],
+ 'deleted' => '0'
+ ];
+ $this->save($tax_code_data);
+ $not_to_delete[] = $tax_code_data['tax_code'];
+ }
- // all entries not available in post will be deleted now
- $deleted_tax_codes = $this->get_all()->getResultArray();
+ // all entries not available in post will be deleted now
+ $deleted_tax_codes = $this->get_all()->getResultArray();
- foreach($deleted_tax_codes as $key => $tax_code_data)
- {
- if(!in_array($tax_code_data['tax_code'], $not_to_delete))
- {
- $this->delete($tax_code_data['tax_code']);
- }
- }
+ foreach($deleted_tax_codes as $key => $tax_code_data)
+ {
+ if(!in_array($tax_code_data['tax_code'], $not_to_delete))
+ {
+ $this->delete($tax_code_data['tax_code']);
+ }
+ }
- $this->db->transComplete();
- return $this->db->transStatus();
- }
+ $this->db->transComplete();
+ return $this->db->transStatus();
+ }
- /**
- * Deletes a specific tax code
- */
- public function delete($tax_code = null, bool $purge = false): bool
- {
- $builder = $this->db->table('tax_codes');
- $builder->where('tax_code', $tax_code);
+ /**
+ * Deletes a specific tax code
+ */
+ public function delete($tax_code = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('tax_codes');
+ $builder->where('tax_code', $tax_code);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Deletes a list of rows
- */
- public function delete_list(array $tax_codes): bool
- {
- $builder = $this->db->table('tax_codes');
- $builder->whereIn('tax_code', $tax_codes);
+ /**
+ * Deletes a list of rows
+ */
+ public function delete_list(array $tax_codes): bool
+ {
+ $builder = $this->db->table('tax_codes');
+ $builder->whereIn('tax_code', $tax_codes);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'tax_code_name', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'tax_code_name', 'asc', true);
+ }
- /**
- * Perform a search for a set of rows
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_code_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'tax_code_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Perform a search for a set of rows
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'tax_code_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'tax_code_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('tax_codes AS tax_codes');
+ $builder = $this->db->table('tax_codes AS tax_codes');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(tax_codes.tax_code) as count');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(tax_codes.tax_code) as count');
+ }
- $builder->groupStart();
- $builder->like('tax_code_name', $search);
- $builder->orLike('tax_code', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
+ $builder->groupStart();
+ $builder->like('tax_code_name', $search);
+ $builder->orLike('tax_code', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Gets the tax code to use for a given customer
- */
- public function get_sales_tax_code(string $city = '', string $state = '')
- {
- $config = config(OSPOS::class)->settings;
+ /**
+ * Gets the tax code to use for a given customer
+ */
+ public function get_sales_tax_code(string $city = '', string $state = '')
+ {
+ $config = config(OSPOS::class)->settings;
- // if tax code using both city and state cannot be found then try again using just the state
- // if the state tax code cannot be found then try again using blanks for both
- $builder = $this->db->table('tax_codes');
- $builder->where('city', $city);
- $builder->where('state', $state);
- $builder->where('deleted', 0);
+ // if tax code using both city and state cannot be found then try again using just the state
+ // if the state tax code cannot be found then try again using blanks for both
+ $builder = $this->db->table('tax_codes');
+ $builder->where('city', $city);
+ $builder->where('state', $state);
+ $builder->where('deleted', 0);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow()->tax_code_id;
- }
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow()->tax_code_id;
+ }
- $builder = $this->db->table('tax_codes');
- $builder->where('city', '');
- $builder->where('state', $state);
- $builder->where('deleted', 0);
+ $builder = $this->db->table('tax_codes');
+ $builder->where('city', '');
+ $builder->where('state', $state);
+ $builder->where('deleted', 0);
- $query = $builder->get();
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: this should be ===
- {
- return $query->getRow()->tax_code_id;
- }
- else
- {
- return $config['default_tax_code'];
- }
- }
+ if($query->getNumRows() == 1) //TODO: this should be ===
+ {
+ return $query->getRow()->tax_code_id;
+ }
+ else
+ {
+ return $config['default_tax_code'];
+ }
+ }
- /**
- * @param string $search
- * @param int $limit
- * @return array
- */
- public function get_tax_codes_search_suggestions(string $search, int $limit = 25): array
- {
- $suggestions = [];
+ /**
+ * @param string $search
+ * @param int $limit
+ * @return array
+ */
+ public function get_tax_codes_search_suggestions(string $search, int $limit = 25): array
+ {
+ $suggestions = [];
- $builder = $this->db->table('tax_codes');
+ $builder = $this->db->table('tax_codes');
- if(!empty($search))
- {
- $builder->like('tax_code', $search);
- $builder->orLike('tax_code_name', $search);
- }
+ if(!empty($search))
+ {
+ $builder->like('tax_code', $search);
+ $builder->orLike('tax_code_name', $search);
+ }
- $builder->where('deleted', 0);
- $builder->orderBy('tax_code_name', 'asc');
+ $builder->where('deleted', 0);
+ $builder->orderBy('tax_code_name', 'asc');
- foreach($builder->get()->getResult() as $row)
- {
- $suggestions[] = ['value' => $row->tax_code_id, 'label' => ($row->tax_code . ' ' . $row->tax_code_name)];
- }
+ foreach($builder->get()->getResult() as $row)
+ {
+ $suggestions[] = ['value' => $row->tax_code_id, 'label' => ($row->tax_code . ' ' . $row->tax_code_name)];
+ }
- //only return $limit suggestions
- if(count($suggestions) > $limit)
- {
- $suggestions = array_slice($suggestions, 0,$limit);
- }
+ //only return $limit suggestions
+ if(count($suggestions) > $limit)
+ {
+ $suggestions = array_slice($suggestions, 0,$limit);
+ }
- return $suggestions;
- }
+ return $suggestions;
+ }
- /**
- * @return array[]
- */
- public function get_empty_row(): array
- {
- return [
- '0' => [
- 'tax_code_id' => NEW_ENTRY,
- 'tax_code' => '',
- 'tax_code_name' => '',
- 'city' => '',
- 'state' => '',
- 'deleted' => 0
- ]
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function get_empty_row(): array
+ {
+ return [
+ '0' => [
+ 'tax_code_id' => NEW_ENTRY,
+ 'tax_code' => '',
+ 'tax_code_name' => '',
+ 'city' => '',
+ 'state' => '',
+ 'deleted' => 0
+ ]
+ ];
+ }
}
diff --git a/app/Models/Tax_jurisdiction.php b/app/Models/Tax_jurisdiction.php
index b5c94b895..053db6b9d 100644
--- a/app/Models/Tax_jurisdiction.php
+++ b/app/Models/Tax_jurisdiction.php
@@ -12,262 +12,262 @@ use stdClass;
class Tax_jurisdiction extends Model
{
- protected $table = 'tax_jurisdictions';
- protected $primaryKey = 'cashup_id';
- protected $useAutoIncrement = true;
- protected $useSoftDeletes = false;
- protected $allowedFields = [
- 'jurisdiction_name',
- 'tax_group',
- 'tax_type',
- 'reporting_authority',
- 'tax_group_sequence',
- 'cascade_sequence',
- 'deleted'
- ];
+ protected $table = 'tax_jurisdictions';
+ protected $primaryKey = 'cashup_id';
+ protected $useAutoIncrement = true;
+ protected $useSoftDeletes = false;
+ protected $allowedFields = [
+ 'jurisdiction_name',
+ 'tax_group',
+ 'tax_type',
+ 'reporting_authority',
+ 'tax_group_sequence',
+ 'cascade_sequence',
+ 'deleted'
+ ];
- /**
- * Determines if it exists in the table
- */
- public function exists(int $jurisdiction_id): bool
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->where('jurisdiction_id', $jurisdiction_id);
+ /**
+ * Determines if it exists in the table
+ */
+ public function exists(int $jurisdiction_id): bool
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->where('jurisdiction_id', $jurisdiction_id);
- return ($builder->get()->getNumRows() == 1); //TODO: ===
- }
+ return ($builder->get()->getNumRows() == 1); //TODO: ===
+ }
- /**
- * Gets total of rows
- */
- public function get_total_rows(): int
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->where('deleted', 0);
+ /**
+ * Gets total of rows
+ */
+ public function get_total_rows(): int
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->where('deleted', 0);
- return $builder->countAllResults();
- }
+ return $builder->countAllResults();
+ }
- /***
- * Gets information about the particular record
- */
- public function get_info(int $jurisdiction_id): object
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->where('jurisdiction_id', $jurisdiction_id);
- $builder->where('deleted', 0);
- $query = $builder->get();
+ /***
+ * Gets information about the particular record
+ */
+ public function get_info(int $jurisdiction_id): object
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->where('jurisdiction_id', $jurisdiction_id);
+ $builder->where('deleted', 0);
+ $query = $builder->get();
- if($query->getNumRows() == 1) //TODO: ===
- {
- return $query->getRow();
- }
- else //TODO: this else is not needed. Just put everything below it without an else.
- {
- //Get empty base parent object
- $tax_jurisdiction_obj = new stdClass();
+ if($query->getNumRows() == 1) //TODO: ===
+ {
+ return $query->getRow();
+ }
+ else //TODO: this else is not needed. Just put everything below it without an else.
+ {
+ //Get empty base parent object
+ $tax_jurisdiction_obj = new stdClass();
- //Get all the fields from the table
- foreach($this->db->getFieldNames('tax_jurisdictions') as $field)
- {
- $tax_jurisdiction_obj->$field = '';
- }
- return $tax_jurisdiction_obj;
- }
- }
+ //Get all the fields from the table
+ foreach($this->db->getFieldNames('tax_jurisdictions') as $field)
+ {
+ $tax_jurisdiction_obj->$field = '';
+ }
+ return $tax_jurisdiction_obj;
+ }
+ }
- /**
- * Returns all rows from the table
- */
- public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface
- {
- $builder = $this->db->table('tax_jurisdictions');
+ /**
+ * Returns all rows from the table
+ */
+ public function get_all(int $rows = 0, int $limit_from = 0, bool $no_deleted = true): ResultInterface
+ {
+ $builder = $this->db->table('tax_jurisdictions');
- if($no_deleted)
- {
- $builder->where('deleted', 0);
- }
+ if($no_deleted)
+ {
+ $builder->where('deleted', 0);
+ }
- $builder->orderBy('jurisdiction_name', 'asc');
+ $builder->orderBy('jurisdiction_name', 'asc');
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Returns multiple rows
- */
- public function get_multiple_info(array $jurisdiction_ids): ResultInterface
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->whereIn('jurisdiction_id', $jurisdiction_ids);
- $builder->orderBy('jurisdiction_name', 'asc');
+ /**
+ * Returns multiple rows
+ */
+ public function get_multiple_info(array $jurisdiction_ids): ResultInterface
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->whereIn('jurisdiction_id', $jurisdiction_ids);
+ $builder->orderBy('jurisdiction_name', 'asc');
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * Inserts or updates a row
- */
- public function save_value(array &$jurisdiction_data, int $jurisdiction_id = NEW_ENTRY): bool
- {
- $builder = $this->db->table('tax_jurisdictions');
- if($jurisdiction_id == NEW_ENTRY || !$this->exists($jurisdiction_id))
- {
- if($builder->insert($jurisdiction_data)) //TODO: Replace this with simply a return of the result of insert()... see update() below.
- {
- $jurisdiction_data['jurisdiction_id'] = $this->db->insertID();
- return true;
- }
+ /**
+ * Inserts or updates a row
+ */
+ public function save_value(array &$jurisdiction_data, int $jurisdiction_id = NEW_ENTRY): bool
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ if($jurisdiction_id == NEW_ENTRY || !$this->exists($jurisdiction_id))
+ {
+ if($builder->insert($jurisdiction_data)) //TODO: Replace this with simply a return of the result of insert()... see update() below.
+ {
+ $jurisdiction_data['jurisdiction_id'] = $this->db->insertID();
+ return true;
+ }
- return false;
- }
+ return false;
+ }
- $builder->where('jurisdiction_id', $jurisdiction_id);
+ $builder->where('jurisdiction_id', $jurisdiction_id);
- return $builder->update($jurisdiction_data);
- }
+ return $builder->update($jurisdiction_data);
+ }
- /**
- * Saves changes to the tax jurisdictions table
- */
- public function save_jurisdictions(array $array_save): bool
- {
- $this->db->transStart();
+ /**
+ * Saves changes to the tax jurisdictions table
+ */
+ public function save_jurisdictions(array $array_save): bool
+ {
+ $this->db->transStart();
- $not_to_delete = [];
+ $not_to_delete = [];
- foreach($array_save as $key => $value)
- {
- // save or update
- $tax_jurisdiction_data = [
- 'jurisdiction_name' => $value['jurisdiction_name'],
- 'tax_group' => $value['tax_group'],
- 'tax_type' => $value['tax_type'],
- 'reporting_authority' => $value['reporting_authority'],
- 'tax_group_sequence' => $value['tax_group_sequence'],
- 'cascade_sequence' => $value['cascade_sequence'],
- 'deleted' => '0'];
+ foreach($array_save as $key => $value)
+ {
+ // save or update
+ $tax_jurisdiction_data = [
+ 'jurisdiction_name' => $value['jurisdiction_name'],
+ 'tax_group' => $value['tax_group'],
+ 'tax_type' => $value['tax_type'],
+ 'reporting_authority' => $value['reporting_authority'],
+ 'tax_group_sequence' => $value['tax_group_sequence'],
+ 'cascade_sequence' => $value['cascade_sequence'],
+ 'deleted' => '0'];
- $this->save_value($tax_jurisdiction_data, $value['jurisdiction_id']);
+ $this->save_value($tax_jurisdiction_data, $value['jurisdiction_id']);
- if($value['jurisdiction_id'] == NEW_ENTRY)
- {
- $not_to_delete[] = $tax_jurisdiction_data['jurisdiction_id'];
- }
- else
- {
- $not_to_delete[] = $value['jurisdiction_id'];
- }
- }
+ if($value['jurisdiction_id'] == NEW_ENTRY)
+ {
+ $not_to_delete[] = $tax_jurisdiction_data['jurisdiction_id'];
+ }
+ else
+ {
+ $not_to_delete[] = $value['jurisdiction_id'];
+ }
+ }
- // all entries not available in post will be deleted now
- $deleted_tax_jurisdictions = $this->get_all()->getResultArray();
+ // all entries not available in post will be deleted now
+ $deleted_tax_jurisdictions = $this->get_all()->getResultArray();
- foreach($deleted_tax_jurisdictions as $key => $tax_jurisdiction_data)
- {
- if(!in_array($tax_jurisdiction_data['jurisdiction_id'], $not_to_delete))
- {
- $this->delete($tax_jurisdiction_data['jurisdiction_id']);
- }
- }
+ foreach($deleted_tax_jurisdictions as $key => $tax_jurisdiction_data)
+ {
+ if(!in_array($tax_jurisdiction_data['jurisdiction_id'], $not_to_delete))
+ {
+ $this->delete($tax_jurisdiction_data['jurisdiction_id']);
+ }
+ }
- $this->db->transComplete();
- return $this->db->transStatus();
- }
+ $this->db->transComplete();
+ return $this->db->transStatus();
+ }
- /**
- * Soft deletes a specific tax jurisdiction
- */
- public function delete($jurisdiction_id = null, bool $purge = false): bool
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->where('jurisdiction_id', $jurisdiction_id);
+ /**
+ * Soft deletes a specific tax jurisdiction
+ */
+ public function delete($jurisdiction_id = null, bool $purge = false): bool
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->where('jurisdiction_id', $jurisdiction_id);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Soft deletes a list of rows
- */
- public function delete_list(array $jurisdiction_ids): bool
- {
- $builder = $this->db->table('tax_jurisdictions');
- $builder->whereIn('jurisdiction_id', $jurisdiction_ids);
+ /**
+ * Soft deletes a list of rows
+ */
+ public function delete_list(array $jurisdiction_ids): bool
+ {
+ $builder = $this->db->table('tax_jurisdictions');
+ $builder->whereIn('jurisdiction_id', $jurisdiction_ids);
- return $builder->update(['deleted' => 1]);
- }
+ return $builder->update(['deleted' => 1]);
+ }
- /**
- * Gets rows
- */
- public function get_found_rows(string $search): int
- {
- return $this->search($search, 0, 0, 'jurisdiction_name', 'asc', true);
- }
+ /**
+ * Gets rows
+ */
+ public function get_found_rows(string $search): int
+ {
+ return $this->search($search, 0, 0, 'jurisdiction_name', 'asc', true);
+ }
- /**
- * Perform a search for a set of rows
- */
- public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'jurisdiction_name', ?string $order = 'asc', ?bool $count_only = false)
- {
- // Set default values
- if($rows == null) $rows = 0;
- if($limit_from == null) $limit_from = 0;
- if($sort == null) $sort = 'jurisdiction_name';
- if($order == null) $order = 'asc';
- if($count_only == null) $count_only = false;
+ /**
+ * Perform a search for a set of rows
+ */
+ public function search(string $search, ?int $rows = 0, ?int $limit_from = 0, ?string $sort = 'jurisdiction_name', ?string $order = 'asc', ?bool $count_only = false)
+ {
+ // Set default values
+ if($rows == null) $rows = 0;
+ if($limit_from == null) $limit_from = 0;
+ if($sort == null) $sort = 'jurisdiction_name';
+ if($order == null) $order = 'asc';
+ if($count_only == null) $count_only = false;
- $builder = $this->db->table('tax_jurisdictions AS tax_jurisdictions');
+ $builder = $this->db->table('tax_jurisdictions AS tax_jurisdictions');
- // get_found_rows case
- if($count_only)
- {
- $builder->select('COUNT(tax_jurisdictions.jurisdiction_id) as count');
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ $builder->select('COUNT(tax_jurisdictions.jurisdiction_id) as count');
+ }
- $builder->groupStart();
- $builder->like('jurisdiction_name', $search);
- $builder->orLike('reporting_authority', $search);
- $builder->groupEnd();
- $builder->where('deleted', 0);
+ $builder->groupStart();
+ $builder->like('jurisdiction_name', $search);
+ $builder->orLike('reporting_authority', $search);
+ $builder->groupEnd();
+ $builder->where('deleted', 0);
- // get_found_rows case
- if($count_only)
- {
- return $builder->get()->getRow()->count;
- }
+ // get_found_rows case
+ if($count_only)
+ {
+ return $builder->get()->getRow()->count;
+ }
- $builder->orderBy($sort, $order);
+ $builder->orderBy($sort, $order);
- if($rows > 0)
- {
- $builder->limit($rows, $limit_from);
- }
+ if($rows > 0)
+ {
+ $builder->limit($rows, $limit_from);
+ }
- return $builder->get();
- }
+ return $builder->get();
+ }
- /**
- * @return array[]
- */
- public function get_empty_row(): array
- {
- return [
- '0' => [
- 'jurisdiction_id' => NEW_ENTRY,
- 'jurisdiction_name' => '',
- 'tax_group' => '',
- 'tax_type' => '1',
- 'reporting_authority' => '',
- 'tax_group_sequence' => '',
- 'cascade_sequence' => '',
- 'deleted' => ''
- ]
- ];
- }
+ /**
+ * @return array[]
+ */
+ public function get_empty_row(): array
+ {
+ return [
+ '0' => [
+ 'jurisdiction_id' => NEW_ENTRY,
+ 'jurisdiction_name' => '',
+ 'tax_group' => '',
+ 'tax_type' => '1',
+ 'reporting_authority' => '',
+ 'tax_group_sequence' => '',
+ 'cascade_sequence' => '',
+ 'deleted' => ''
+ ]
+ ];
+ }
}
diff --git a/app/Models/Tokens/Token.php b/app/Models/Tokens/Token.php
index 00efe8a7d..991f7d4e8 100644
--- a/app/Models/Tokens/Token.php
+++ b/app/Models/Tokens/Token.php
@@ -9,78 +9,78 @@ use CodeIgniter\Model;
*/
abstract class Token extends Model
{
- protected string $value = '';
+ protected string $value = '';
- /**
- * @param string $value
- */
- public function __construct(string $value = '')
- {
- parent::__construct();
+ /**
+ * @param string $value
+ */
+ public function __construct(string $value = '')
+ {
+ parent::__construct();
- $this->value = $value;
- }
+ $this->value = $value;
+ }
- /**
- * @return array
- */
- public static function get_barcode_tokens(): array
- {
- return [
- new Token_barcode_price(),
- new Token_barcode_weight(),
- new Token_barcode_ean()
- ];
- }
+ /**
+ * @return array
+ */
+ public static function get_barcode_tokens(): array
+ {
+ return [
+ new Token_barcode_price(),
+ new Token_barcode_weight(),
+ new Token_barcode_ean()
+ ];
+ }
- /**
- * @return array
- */
- public static function get_tokens(): array
- {
- return [
- new Token_customer(),
- new Token_invoice_count(),
- new Token_invoice_sequence(),
- new Token_quote_sequence(),
- new Token_suspended_invoice_count(),
- new Token_quote_sequence(),
- new Token_work_order_sequence(),
- new Token_year_invoice_count(),
- new Token_year_quote_count()
- ];
- }
+ /**
+ * @return array
+ */
+ public static function get_tokens(): array
+ {
+ return [
+ new Token_customer(),
+ new Token_invoice_count(),
+ new Token_invoice_sequence(),
+ new Token_quote_sequence(),
+ new Token_suspended_invoice_count(),
+ new Token_quote_sequence(),
+ new Token_work_order_sequence(),
+ new Token_year_invoice_count(),
+ new Token_year_quote_count()
+ ];
+ }
- /**
- * @return string
- */
- abstract public function token_id(): string;
+ /**
+ * @return string
+ */
+ abstract public function token_id(): string;
- /**
- * @return mixed
- */
- abstract public function get_value(): mixed;
+ /**
+ * @return mixed
+ */
+ abstract public function get_value(): mixed;
- /**
- * @param $token_id
- * @return bool
- */
- public function matches($token_id): bool
- {
- return $this->token_id() == $token_id;
- }
+ /**
+ * @param $token_id
+ * @return bool
+ */
+ public function matches($token_id): bool
+ {
+ return $this->token_id() == $token_id;
+ }
- /**
- * @param string $text
- * @return string
- */
- public function replace_token(string $text): string //TODO: This function is never called in the code
- {
- if(strstr($text, $this->token_id()))
- {
- return str_replace($this->token_id(), $this->get_value(), $text);
- }
+ /**
+ * @param string $text
+ * @return string
+ */
+ public function replace_token(string $text): string //TODO: This function is never called in the code
+ {
+ if(strstr($text, $this->token_id()))
+ {
+ return str_replace($this->token_id(), $this->get_value(), $text);
+ }
- return $text;
- }
+ return $text;
+ }
}
diff --git a/app/Models/Tokens/Token_barcode_ean.php b/app/Models/Tokens/Token_barcode_ean.php
index 57d34f506..9eb4d48c7 100644
--- a/app/Models/Tokens/Token_barcode_ean.php
+++ b/app/Models/Tokens/Token_barcode_ean.php
@@ -7,19 +7,19 @@ namespace App\Models\Tokens;
*/
class Token_barcode_ean extends Token
{
- /**
- * @return string
- */
- public function token_id(): string
- {
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
return 'I';
}
- /**
- * @return string
- */
- public function get_value(): string
- {
+ /**
+ * @return string
+ */
+ public function get_value(): string
+ {
return '\w';
}
}
diff --git a/app/Models/Tokens/Token_barcode_price.php b/app/Models/Tokens/Token_barcode_price.php
index 81cf25b20..80874314f 100644
--- a/app/Models/Tokens/Token_barcode_price.php
+++ b/app/Models/Tokens/Token_barcode_price.php
@@ -7,19 +7,19 @@ namespace App\Models\Tokens;
*/
class Token_barcode_price extends Token
{
- /**
- * @return string
- */
- public function token_id(): string
- {
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
return 'P';
}
- /**
- * @return string
- */
- public function get_value(): string
- {
+ /**
+ * @return string
+ */
+ public function get_value(): string
+ {
return '\d';
}
}
diff --git a/app/Models/Tokens/Token_barcode_weight.php b/app/Models/Tokens/Token_barcode_weight.php
index d0f1e9463..6243b2657 100644
--- a/app/Models/Tokens/Token_barcode_weight.php
+++ b/app/Models/Tokens/Token_barcode_weight.php
@@ -7,18 +7,18 @@ namespace App\Models\Tokens;
*/
class Token_barcode_weight extends Token
{
- /**
- * @return string
- */
- public function token_id(): string
+ /**
+ * @return string
+ */
+ public function token_id(): string
{
return 'W';
}
- /**
- * @return string
- */
- public function get_value(): string
+ /**
+ * @return string
+ */
+ public function get_value(): string
{
return '\d';
}
diff --git a/app/Models/Tokens/Token_customer.php b/app/Models/Tokens/Token_customer.php
index 7b0450d3c..0fb8663eb 100644
--- a/app/Models/Tokens/Token_customer.php
+++ b/app/Models/Tokens/Token_customer.php
@@ -11,45 +11,45 @@ use App\Models\Customer;
**/
class Token_customer extends Token
{
- private array $customer_info;
- private Sale_lib $sale_lib;
+ private array $customer_info;
+ private Sale_lib $sale_lib;
- /**
- * @param string $customer_info
- */
- public function __construct(array $customer_info = [])
- {
- parent::__construct();
- $this->customer_info = $customer_info;
- $this->sale_lib = new Sale_lib();
- }
+ /**
+ * @param string $customer_info
+ */
+ public function __construct(array $customer_info = [])
+ {
+ parent::__construct();
+ $this->customer_info = $customer_info;
+ $this->sale_lib = new Sale_lib();
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'CU';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'CU';
+ }
- /**
- * @return string
- */
- public function get_value(): string
- {
- //substitute customer info
- $customer_id = $this->sale_lib->get_customer();
- if($customer_id != NEW_ITEM && empty($this->customer_info))
- {
- $customer = model(Customer::class);
- $customer_info = $customer->get_info($customer_id);
+ /**
+ * @return string
+ */
+ public function get_value(): string
+ {
+ //substitute customer info
+ $customer_id = $this->sale_lib->get_customer();
+ if($customer_id != NEW_ITEM && empty($this->customer_info))
+ {
+ $customer = model(Customer::class);
+ $customer_info = $customer->get_info($customer_id);
- if($customer_info != '')
- {
- return trim($customer_info->first_name . ' ' . $customer_info->last_name);
- }
- }
+ if($customer_info != '')
+ {
+ return trim($customer_info->first_name . ' ' . $customer_info->last_name);
+ }
+ }
- return '';
- }
+ return '';
+ }
}
diff --git a/app/Models/Tokens/Token_invoice_count.php b/app/Models/Tokens/Token_invoice_count.php
index a33330ae7..c495f68cb 100644
--- a/app/Models/Tokens/Token_invoice_count.php
+++ b/app/Models/Tokens/Token_invoice_count.php
@@ -12,28 +12,28 @@ use App\Models\Sale;
*/
class Token_invoice_count extends Token
{
- /**
- * @param string $value
- */
- public function __construct(string $value = '')
- {
- parent::__construct($value);
- }
+ /**
+ * @param string $value
+ */
+ public function __construct(string $value = '')
+ {
+ parent::__construct($value);
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'CO';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'CO';
+ }
- /**
- * @return int
- */
- public function get_value(): int
- {
- $sale = model(Sale::class);
- return empty($value) ? $sale->get_invoice_count() : $value;
- }
+ /**
+ * @return int
+ */
+ public function get_value(): int
+ {
+ $sale = model(Sale::class);
+ return empty($value) ? $sale->get_invoice_count() : $value;
+ }
}
diff --git a/app/Models/Tokens/Token_invoice_sequence.php b/app/Models/Tokens/Token_invoice_sequence.php
index cd0acdf7b..4a2054ae3 100644
--- a/app/Models/Tokens/Token_invoice_sequence.php
+++ b/app/Models/Tokens/Token_invoice_sequence.php
@@ -11,30 +11,30 @@ use ReflectionException;
class Token_invoice_sequence extends Token
{
- private Appconfig $appconfig;
+ private Appconfig $appconfig;
- /**
- * @param string $value
- */
- public function __construct(string $value = '')
- {
- parent::__construct($value);
- $this->appconfig = model(Appconfig::class);
- }
+ /**
+ * @param string $value
+ */
+ public function __construct(string $value = '')
+ {
+ parent::__construct($value);
+ $this->appconfig = model(Appconfig::class);
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'ISEQ';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'ISEQ';
+ }
- /**
- * @throws ReflectionException
- */
- public function get_value(bool $save = true): string
- {
- return $this->appconfig->acquire_next_invoice_sequence($save);
- }
+ /**
+ * @throws ReflectionException
+ */
+ public function get_value(bool $save = true): string
+ {
+ return $this->appconfig->acquire_next_invoice_sequence($save);
+ }
}
diff --git a/app/Models/Tokens/Token_quote_sequence.php b/app/Models/Tokens/Token_quote_sequence.php
index a749a0347..30c7cc519 100644
--- a/app/Models/Tokens/Token_quote_sequence.php
+++ b/app/Models/Tokens/Token_quote_sequence.php
@@ -10,28 +10,28 @@ use ReflectionException;
**/
class Token_quote_sequence extends Token
{
- private Appconfig $appconfig;
+ private Appconfig $appconfig;
- public function __construct()
- {
- parent::__construct();
- $this->appconfig = model(AppConfig::class);
+ public function __construct()
+ {
+ parent::__construct();
+ $this->appconfig = model(AppConfig::class);
- }
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'QSEQ';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'QSEQ';
+ }
- /**
- * @throws ReflectionException
- */
- public function get_value(bool $save = true): string
- {
- return $this->appconfig->acquire_next_quote_sequence($save);
- }
+ /**
+ * @throws ReflectionException
+ */
+ public function get_value(bool $save = true): string
+ {
+ return $this->appconfig->acquire_next_quote_sequence($save);
+ }
}
diff --git a/app/Models/Tokens/Token_suspended_invoice_count.php b/app/Models/Tokens/Token_suspended_invoice_count.php
index faae18e57..1c987741a 100644
--- a/app/Models/Tokens/Token_suspended_invoice_count.php
+++ b/app/Models/Tokens/Token_suspended_invoice_count.php
@@ -12,25 +12,25 @@ use App\Models\Sale;
*/
class Token_suspended_invoice_count extends Token
{
- public function __construct()
- {
- parent::__construct();
- }
+ public function __construct()
+ {
+ parent::__construct();
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'SCO';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'SCO';
+ }
- /**
- * @return int
- */
- public function get_value(): int
- {
- $sale = model(Sale::class);
- return $sale->get_suspended_invoice_count();
- }
+ /**
+ * @return int
+ */
+ public function get_value(): int
+ {
+ $sale = model(Sale::class);
+ return $sale->get_suspended_invoice_count();
+ }
}
diff --git a/app/Models/Tokens/Token_work_order_sequence.php b/app/Models/Tokens/Token_work_order_sequence.php
index 7b8aa37ed..978b4e8af 100644
--- a/app/Models/Tokens/Token_work_order_sequence.php
+++ b/app/Models/Tokens/Token_work_order_sequence.php
@@ -10,30 +10,30 @@ use ReflectionException;
**/
class Token_work_order_sequence extends Token
{
- private Appconfig $appconfig;
+ private Appconfig $appconfig;
- /**
- * @param string $value
- */
- public function __construct(string $value = '')
- {
- parent::__construct($value);
- $this->appconfig = model(AppConfig::class);
- }
+ /**
+ * @param string $value
+ */
+ public function __construct(string $value = '')
+ {
+ parent::__construct($value);
+ $this->appconfig = model(AppConfig::class);
+ }
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'WSEQ';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'WSEQ';
+ }
- /**
- * @throws ReflectionException
- */
- public function get_value(bool $save = true): string
- {
- return $this->appconfig->acquire_next_work_order_sequence($save);
- }
+ /**
+ * @throws ReflectionException
+ */
+ public function get_value(bool $save = true): string
+ {
+ return $this->appconfig->acquire_next_work_order_sequence($save);
+ }
}
diff --git a/app/Models/Tokens/Token_year_invoice_count.php b/app/Models/Tokens/Token_year_invoice_count.php
index 461956fe3..c88fdbdf3 100644
--- a/app/Models/Tokens/Token_year_invoice_count.php
+++ b/app/Models/Tokens/Token_year_invoice_count.php
@@ -12,20 +12,20 @@ use App\Models\Sale;
*/
class Token_year_invoice_count extends Token
{
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'YCO';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'YCO';
+ }
- /**
- * @return int
- */
- public function get_value(): int
- {
- $sale = model(Sale::class);
- return $sale->get_invoice_number_for_year();
- }
+ /**
+ * @return int
+ */
+ public function get_value(): int
+ {
+ $sale = model(Sale::class);
+ return $sale->get_invoice_number_for_year();
+ }
}
diff --git a/app/Models/Tokens/Token_year_quote_count.php b/app/Models/Tokens/Token_year_quote_count.php
index d1496d784..db7edd383 100644
--- a/app/Models/Tokens/Token_year_quote_count.php
+++ b/app/Models/Tokens/Token_year_quote_count.php
@@ -12,20 +12,20 @@ use App\Models\Sale;
*/
class Token_year_quote_count extends Token
{
- /**
- * @return string
- */
- public function token_id(): string
- {
- return 'QCO';
- }
+ /**
+ * @return string
+ */
+ public function token_id(): string
+ {
+ return 'QCO';
+ }
- /**
- * @return int
- */
- public function get_value(): int
- {
- $sale = model(Sale::class);
- return $sale->get_quote_number_for_year();
- }
+ /**
+ * @return int
+ */
+ public function get_value(): int
+ {
+ $sale = model(Sale::class);
+ return $sale->get_quote_number_for_year();
+ }
}
diff --git a/app/Models/index.html b/app/Models/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Models/index.html
+++ b/app/Models/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/ThirdParty/index.html b/app/ThirdParty/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/ThirdParty/index.html
+++ b/app/ThirdParty/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Views/attributes/form.php b/app/Views/attributes/form.php
index 67afc5614..e44997f88 100644
--- a/app/Views/attributes/form.php
+++ b/app/Views/attributes/form.php
@@ -16,91 +16,91 @@
= form_open("attributes/saveDefinition/$definition_id", ['id' => 'attribute_form', 'class' => 'form-horizontal'])?>
= form_close() ?>
@@ -109,169 +109,169 @@
//validation and submit handling
$(document).ready(function()
{
- var values = [];
- var definition_id = = esc($definition_id, 'js') ?>;
- var is_new = definition_id == 0;
+ var values = [];
+ var definition_id = = esc($definition_id, 'js') ?>;
+ var is_new = definition_id == 0;
- var disable_definition_types = function()
- {
- var definition_type = $("#definition_type option:selected").text();
+ var disable_definition_types = function()
+ {
+ var definition_type = $("#definition_type option:selected").text();
- if(definition_type == "DATE" || (definition_type == "GROUP" && !is_new) || definition_type == "DECIMAL")
- {
- $('#definition_type').prop("disabled",true);
- }
- else if(definition_type == "DROPDOWN" || definition_type == "CHECKBOX")
- {
- $("#definition_type option:contains('GROUP')").hide();
- $("#definition_type option:contains('DATE')").hide();
- $("#definition_type option:contains('DECIMAL')").hide();
- }
- else
- {
- $("#definition_type option:contains('GROUP')").hide();
- }
- }
- disable_definition_types();
+ if(definition_type == "DATE" || (definition_type == "GROUP" && !is_new) || definition_type == "DECIMAL")
+ {
+ $('#definition_type').prop("disabled",true);
+ }
+ else if(definition_type == "DROPDOWN" || definition_type == "CHECKBOX")
+ {
+ $("#definition_type option:contains('GROUP')").hide();
+ $("#definition_type option:contains('DATE')").hide();
+ $("#definition_type option:contains('DECIMAL')").hide();
+ }
+ else
+ {
+ $("#definition_type option:contains('GROUP')").hide();
+ }
+ }
+ disable_definition_types();
- var disable_category_dropdown = function()
- {
- if(definition_id == -1)
- {
- $('#definition_name').prop("disabled",true);
- $('#definition_type').prop("disabled",true);
- $('#definition_group').parents('.form-group').toggleClass("hidden", true);
- $('#definition_flags').parents('.form-group').toggleClass('hidden', true);
- }
- }
- disable_category_dropdown();
+ var disable_category_dropdown = function()
+ {
+ if(definition_id == -1)
+ {
+ $('#definition_name').prop("disabled",true);
+ $('#definition_type').prop("disabled",true);
+ $('#definition_group').parents('.form-group').toggleClass("hidden", true);
+ $('#definition_flags').parents('.form-group').toggleClass('hidden', true);
+ }
+ }
+ disable_category_dropdown();
- var show_hide_fields = function(event)
- {
- var is_dropdown = $('#definition_type').val() !== '1';
- var is_decimal = $('#definition_type').val() !== '2';
- var is_no_group = $('#definition_type').val() !== '0';
- var is_category_dropdown = definition_id == -1;
+ var show_hide_fields = function(event)
+ {
+ var is_dropdown = $('#definition_type').val() !== '1';
+ var is_decimal = $('#definition_type').val() !== '2';
+ var is_no_group = $('#definition_type').val() !== '0';
+ var is_category_dropdown = definition_id == -1;
- $('#definition_value, #definition_list_group').parents('.form-group').toggleClass('hidden', is_dropdown);
- $('#definition_unit').parents('.form-group').toggleClass('hidden', is_decimal);
+ $('#definition_value, #definition_list_group').parents('.form-group').toggleClass('hidden', is_dropdown);
+ $('#definition_unit').parents('.form-group').toggleClass('hidden', is_decimal);
- //Appropriately show definition flags if not category_dropdown
- if(definition_id != -1)
- {
- $('#definition_flags').parents('.form-group').toggleClass('hidden', !is_no_group);
- }
- };
+ //Appropriately show definition flags if not category_dropdown
+ if(definition_id != -1)
+ {
+ $('#definition_flags').parents('.form-group').toggleClass('hidden', !is_no_group);
+ }
+ };
- $('#definition_type').change(show_hide_fields);
- show_hide_fields();
+ $('#definition_type').change(show_hide_fields);
+ show_hide_fields();
- $('.selectpicker').each(function () {
- var $selectpicker = $(this);
- $.fn.selectpicker.call($selectpicker, $selectpicker.data());
- });
+ $('.selectpicker').each(function () {
+ var $selectpicker = $(this);
+ $.fn.selectpicker.call($selectpicker, $selectpicker.data());
+ });
- var remove_attribute_value = function()
- {
- var value = $(this).parents("li").text();
+ var remove_attribute_value = function()
+ {
+ var value = $(this).parents("li").text();
- if (is_new)
- {
- values.splice($.inArray(value, values), 1);
- }
- else
- {
- $.post('= esc("$controller_name/delete_attribute_value/") ?>', {definition_id: definition_id, attribute_value: value});
- }
- $(this).parents("li").remove();
- };
+ if (is_new)
+ {
+ values.splice($.inArray(value, values), 1);
+ }
+ else
+ {
+ $.post('= esc("$controller_name/delete_attribute_value/") ?>', {definition_id: definition_id, attribute_value: value});
+ }
+ $(this).parents("li").remove();
+ };
- var add_attribute_value = function(value)
- {
- var is_event = typeof(value) !== 'string';
+ var add_attribute_value = function(value)
+ {
+ var is_event = typeof(value) !== 'string';
if ($("#definition_value").val().match(/(\||_)/g) != null)
{
return;
}
- if (is_event)
- {
- value = $('#definition_value').val();
+ if (is_event)
+ {
+ value = $('#definition_value').val();
- if (!value)
- {
- return;
- }
+ if (!value)
+ {
+ return;
+ }
- if (is_new)
- {
- values.push(value);
- }
- else
- {
- $.post('= "attributes/saveAttributeValue/" ?>', {definition_id: definition_id, attribute_value: value});
- }
- }
+ if (is_new)
+ {
+ values.push(value);
+ }
+ else
+ {
+ $.post('= "attributes/saveAttributeValue/" ?>', {definition_id: definition_id, attribute_value: value});
+ }
+ }
- $('#definition_list_group').append("" + value + "")
- .find(':last-child a').click(remove_attribute_value);
- $('#definition_value').val('');
- };
+ $('#definition_list_group').append("" + value + "")
+ .find(':last-child a').click(remove_attribute_value);
+ $('#definition_value').val('');
+ };
- $('#add_attribute_value').click(add_attribute_value);
+ $('#add_attribute_value').click(add_attribute_value);
- $('#definition_value').keypress(function (e) {
- if (e.which == 13) {
- add_attribute_value();
- return false;
- }
- });
+ $('#definition_value').keypress(function (e) {
+ if (e.which == 13) {
+ add_attribute_value();
+ return false;
+ }
+ });
- var definition_values = = json_encode(array_values($definition_values)) ?>;
- $.each(definition_values, function(index, element) {
- add_attribute_value(element);
- });
+ var definition_values = = json_encode(array_values($definition_values)) ?>;
+ $.each(definition_values, function(index, element) {
+ add_attribute_value(element);
+ });
- $.validator.addMethod('valid_chars', function(value, element) {
+ $.validator.addMethod('valid_chars', function(value, element) {
return value.match(/(\||_)/g) == null;
- }, "= lang('Attributes.attribute_value_invalid_chars') ?>");
+ }, "= lang('Attributes.attribute_value_invalid_chars') ?>");
- $('form').bind('submit', function () {
- $(this).find(':input').prop('disabled', false);
- });
+ $('form').bind('submit', function () {
+ $(this).find(':input').prop('disabled', false);
+ });
- $('#attribute_form').validate($.extend({
- submitHandler: function(form)
- {
- $(form).ajaxSubmit({
- beforeSerialize: function($form, options) {
- is_new && $('').attr({
- id: 'definition_values',
- type: 'hidden',
- name: 'definition_values',
- value: JSON.stringify(values)
- }).appendTo($form);
- },
- success: function(response)
- {
- dialog_support.hide();
- table_support.handle_submit('= esc($controller_name) ?>', response);
- },
- dataType: 'json'
- });
- },
- rules:
- {
- definition_name: 'required',
- definition_value: 'valid_chars',
- definition_type: 'required'
- },
+ $('#attribute_form').validate($.extend({
+ submitHandler: function(form)
+ {
+ $(form).ajaxSubmit({
+ beforeSerialize: function($form, options) {
+ is_new && $('').attr({
+ id: 'definition_values',
+ type: 'hidden',
+ name: 'definition_values',
+ value: JSON.stringify(values)
+ }).appendTo($form);
+ },
+ success: function(response)
+ {
+ dialog_support.hide();
+ table_support.handle_submit('= esc($controller_name) ?>', response);
+ },
+ dataType: 'json'
+ });
+ },
+ rules:
+ {
+ definition_name: 'required',
+ definition_value: 'valid_chars',
+ definition_type: 'required'
+ },
messages:
{
definition_name: "= lang('Attributes.definition_name_required') ?>",
definition_type: "= lang('Attributes.definition_type_required') ?>"
}
- }, form_support.error));
+ }, form_support.error));
});
diff --git a/app/Views/attributes/item.php b/app/Views/attributes/item.php
index ac0516424..a4c474d33 100644
--- a/app/Views/attributes/item.php
+++ b/app/Views/attributes/item.php
@@ -7,16 +7,16 @@
*/
?>
@@ -26,78 +26,78 @@ foreach($definition_values as $definition_id => $definition_value)
?>
$definition_value)
diff --git a/app/Views/attributes/manage.php b/app/Views/attributes/manage.php
index 48cee40aa..a2e1416a8 100644
--- a/app/Views/attributes/manage.php
+++ b/app/Views/attributes/manage.php
@@ -1,5 +1,5 @@
-
+
= view('partial/footer') ?>
diff --git a/app/Views/barcodes/barcode_sheet.php b/app/Views/barcodes/barcode_sheet.php
index f31f97169..de5905c9f 100644
--- a/app/Views/barcodes/barcode_sheet.php
+++ b/app/Views/barcodes/barcode_sheet.php
@@ -12,35 +12,35 @@ $barcode_lib = new Barcode_lib();
?>
-
-
- = lang('Items.generate_barcodes') ?>
-
-
-
+
+
+ = lang('Items.generate_barcodes') ?>
+
+
+
- get_font_name($barcode_config['barcode_font']) ?>
- style="font-size:= $barcode_config['barcode_font_size'] ?>px">
- width='= $barcode_config['barcode_page_width']."%" ?>' >
-
-
';
- }
- echo '| ' . $barcode_lib->display_barcode($item, $barcode_config) . ' | ';
- $count++;
- }
- ?>
-
-
-
+ get_font_name($barcode_config['barcode_font']) ?>
+ style="font-size:= $barcode_config['barcode_font_size'] ?>px">
+ width='= $barcode_config['barcode_page_width']."%" ?>' >
+
+
';
+ }
+ echo '| ' . $barcode_lib->display_barcode($item, $barcode_config) . ' | ';
+ $count++;
+ }
+ ?>
+
+
+
diff --git a/app/Views/cashups/form.php b/app/Views/cashups/form.php
index d3dce6bfb..b46348ab8 100644
--- a/app/Views/cashups/form.php
+++ b/app/Views/cashups/form.php
@@ -11,362 +11,362 @@
= form_open('cashups/save/'.$cash_ups_info->cashup_id, ['id' => 'cashups_edit_form', 'class' => 'form-horizontal']) //TODO: String Interpolation ?>
-
= form_close() ?>
diff --git a/app/Views/cashups/manage.php b/app/Views/cashups/manage.php
index ae726be4a..56d844281 100644
--- a/app/Views/cashups/manage.php
+++ b/app/Views/cashups/manage.php
@@ -11,68 +11,68 @@
= view('partial/print_receipt', ['print_after_sale'=>false, 'selected_printer' => 'takings_printer']) ?>
-
-
+
+
= view('partial/footer') ?>
diff --git a/app/Views/configs/barcode_config.php b/app/Views/configs/barcode_config.php
index 111015649..4cf7f45ff 100644
--- a/app/Views/configs/barcode_config.php
+++ b/app/Views/configs/barcode_config.php
@@ -6,312 +6,312 @@
*/
?>
= form_open('config/saveBarcode/', ['id' => 'barcode_config_form', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_barcode',
- 'id' => 'submit_barcode',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_barcode',
+ 'id' => 'submit_barcode',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/email_config.php b/app/Views/configs/email_config.php
index 77d113dc2..ad3a5b3b7 100644
--- a/app/Views/configs/email_config.php
+++ b/app/Views/configs/email_config.php
@@ -4,170 +4,170 @@
*/
?>
= form_open('config/saveEmail/', ['id' => 'email_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_email',
- 'id' => 'submit_email',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_email',
+ 'id' => 'submit_email',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/general_config.php b/app/Views/configs/general_config.php
index 6c92eb65a..33f36ca6e 100644
--- a/app/Views/configs/general_config.php
+++ b/app/Views/configs/general_config.php
@@ -9,532 +9,532 @@
*/
?>
= form_open('config/saveGeneral/', ['id' => 'general_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_general',
- 'id' => 'submit_general',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_general',
+ 'id' => 'submit_general',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/info_config.php b/app/Views/configs/info_config.php
index 4df9de42f..ebaae51eb 100644
--- a/app/Views/configs/info_config.php
+++ b/app/Views/configs/info_config.php
@@ -6,175 +6,175 @@
*/
?>
= form_open('config/saveInfo/', ['id' => 'info_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_info',
- 'id' => 'submit_info',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_info',
+ 'id' => 'submit_info',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/integrations_config.php b/app/Views/configs/integrations_config.php
index 32880eb2e..78f84232e 100644
--- a/app/Views/configs/integrations_config.php
+++ b/app/Views/configs/integrations_config.php
@@ -5,88 +5,88 @@
*/
?>
= form_open('config/saveMailchimp/', ['id' => 'mailchimp_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
-
+
+
+ = lang('Common.fields_required_message') ?>
+
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_mailchimp',
- 'id' => 'submit_mailchimp',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_mailchimp',
+ 'id' => 'submit_mailchimp',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right'
+ ]) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/invoice_config.php b/app/Views/configs/invoice_config.php
index 9ea663bae..14aa5afe8 100644
--- a/app/Views/configs/invoice_config.php
+++ b/app/Views/configs/invoice_config.php
@@ -6,239 +6,239 @@
*/
?>
= form_open('config/saveInvoice/', ['id' => 'invoice_config_form', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_invoice',
- 'id' => 'submit_invoice',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_invoice',
+ 'id' => 'submit_invoice',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/license_config.php b/app/Views/configs/license_config.php
index 0c615d0e4..c29be125f 100644
--- a/app/Views/configs/license_config.php
+++ b/app/Views/configs/license_config.php
@@ -4,28 +4,28 @@
*/
?>
= form_open('', ['id' => 'license_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
+
= form_close() ?>
diff --git a/app/Views/configs/locale_config.php b/app/Views/configs/locale_config.php
index 963b92259..a3d478728 100644
--- a/app/Views/configs/locale_config.php
+++ b/app/Views/configs/locale_config.php
@@ -8,344 +8,344 @@
?>
= form_open('config/saveLocale/', ['id' => 'locale_config_form', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_locale',
- 'id' => 'submit_locale',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_locale',
+ 'id' => 'submit_locale',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/manage.php b/app/Views/configs/manage.php
index 45d8a7018..dd0b20c09 100644
--- a/app/Views/configs/manage.php
+++ b/app/Views/configs/manage.php
@@ -1,79 +1,79 @@
= view('partial/header') ?>
-
- = view('configs/info_config') ?>
-
-
- = view('configs/general_config') ?>
-
-
- = view('configs/tax_config') ?>
-
-
- = view('configs/locale_config') ?>
-
-
- = view('configs/barcode_config') ?>
-
-
- = view('configs/stock_config') ?>
-
-
- = view('configs/receipt_config') ?>
-
-
- = view('configs/invoice_config') ?>
-
-
- = view('configs/reward_config') ?>
-
-
- = view('configs/table_config') ?>
-
-
- = view('configs/system_config') ?>
-
+
+ = view('configs/info_config') ?>
+
+
+ = view('configs/general_config') ?>
+
+
+ = view('configs/tax_config') ?>
+
+
+ = view('configs/locale_config') ?>
+
+
+ = view('configs/barcode_config') ?>
+
+
+ = view('configs/stock_config') ?>
+
+
+ = view('configs/receipt_config') ?>
+
+
+ = view('configs/invoice_config') ?>
+
+
+ = view('configs/reward_config') ?>
+
+
+ = view('configs/table_config') ?>
+
+
+ = view('configs/system_config') ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/configs/message_config.php b/app/Views/configs/message_config.php
index 4cefe1ad2..ea5ecfd3b 100644
--- a/app/Views/configs/message_config.php
+++ b/app/Views/configs/message_config.php
@@ -4,100 +4,100 @@
*/
?>
= form_open('config/saveMessage/', ['id' => 'message_config_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_message',
- 'id' => 'submit_message',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_message',
+ 'id' => 'submit_message',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right'
+ ]) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/receipt_config.php b/app/Views/configs/receipt_config.php
index f36fd6792..006e8a0a2 100644
--- a/app/Views/configs/receipt_config.php
+++ b/app/Views/configs/receipt_config.php
@@ -4,447 +4,447 @@
*/
?>
= form_open('config/saveReceipt/', ['id' => 'receipt_config_form', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_receipt',
- 'id' => 'submit_receipt',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_receipt',
+ 'id' => 'submit_receipt',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right'
+ ]) ?>
+
+
= form_close() ?>
diff --git a/app/Views/configs/reward_config.php b/app/Views/configs/reward_config.php
index 95aef4833..e59e58599 100644
--- a/app/Views/configs/reward_config.php
+++ b/app/Views/configs/reward_config.php
@@ -10,28 +10,28 @@
= lang('Common.fields_required_message') ?>
-
+
- = view('partial/customer_rewards', ['customer_rewards' => $customer_rewards]) ?>
-
+ = view('partial/customer_rewards', ['customer_rewards' => $customer_rewards]) ?>
+
= form_submit ([
'name' => 'submit_reward',
'id' => 'submit_reward',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
+ ]) ?>
= form_close() ?>
@@ -41,128 +41,128 @@
$(document).ready(function()
{
- var enable_disable_customer_reward_enable = (function() {
- var customer_reward_enable = $("#customer_reward_enable").is(":checked");
- $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").prop("disabled", !customer_reward_enable);
- $("input[name*='reward_points_']:not(input[name=customer_reward_enable])").prop("disabled", !customer_reward_enable);
- if(customer_reward_enable)
- {
- $(".add_customer_reward, .remove_customer_reward").show();
- }
- else
- {
- $(".add_customer_reward, .remove_customer_reward").hide();
- }
- return arguments.callee;
- })();
+ var enable_disable_customer_reward_enable = (function() {
+ var customer_reward_enable = $("#customer_reward_enable").is(":checked");
+ $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").prop("disabled", !customer_reward_enable);
+ $("input[name*='reward_points_']:not(input[name=customer_reward_enable])").prop("disabled", !customer_reward_enable);
+ if(customer_reward_enable)
+ {
+ $(".add_customer_reward, .remove_customer_reward").show();
+ }
+ else
+ {
+ $(".add_customer_reward, .remove_customer_reward").hide();
+ }
+ return arguments.callee;
+ })();
- $("#customer_reward_enable").change(enable_disable_customer_reward_enable);
+ $("#customer_reward_enable").change(enable_disable_customer_reward_enable);
- var table_count = = sizeof($customer_rewards) ?>;
+ var table_count = = sizeof($customer_rewards) ?>;
- var hide_show_remove = function() {
- if ($("input[name*='customer_rewards']:enabled").length > 1)
- {
- $(".remove_customer_rewards").show();
- }
- else
- {
- $(".remove_customer_rewards").hide();
- }
- };
+ var hide_show_remove = function() {
+ if ($("input[name*='customer_rewards']:enabled").length > 1)
+ {
+ $(".remove_customer_rewards").show();
+ }
+ else
+ {
+ $(".remove_customer_rewards").hide();
+ }
+ };
- var add_customer_reward = function() {
- var id = $(this).parent().find('input').attr('id');
- id = id.replace(/.*?_(\d+)$/g, "$1");
- var previous_id = 'customer_reward_' + id;
- var previous_id_next = 'reward_points_' + id;
- var block = $(this).parent().clone(true);
- var new_block = block.insertAfter($(this).parent());
- var new_block_id = 'customer_reward_' + ++id;
- var new_block_id_next = 'reward_points_' + id;
- $(new_block).find('label').html("= lang('Config.customer_reward') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
- $(new_block).find("input[id='"+previous_id+"']").attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
- $(new_block).find("input[id='"+previous_id_next+"']").attr('id', new_block_id_next).removeAttr('disabled').attr('name', new_block_id_next).attr('class', 'form-control input-sm').val('');
- hide_show_remove();
- };
+ var add_customer_reward = function() {
+ var id = $(this).parent().find('input').attr('id');
+ id = id.replace(/.*?_(\d+)$/g, "$1");
+ var previous_id = 'customer_reward_' + id;
+ var previous_id_next = 'reward_points_' + id;
+ var block = $(this).parent().clone(true);
+ var new_block = block.insertAfter($(this).parent());
+ var new_block_id = 'customer_reward_' + ++id;
+ var new_block_id_next = 'reward_points_' + id;
+ $(new_block).find('label').html("= lang('Config.customer_reward') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
+ $(new_block).find("input[id='"+previous_id+"']").attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
+ $(new_block).find("input[id='"+previous_id_next+"']").attr('id', new_block_id_next).removeAttr('disabled').attr('name', new_block_id_next).attr('class', 'form-control input-sm').val('');
+ hide_show_remove();
+ };
- var remove_customer_reward = function() {
- $(this).parent().remove();
- hide_show_remove();
- };
+ var remove_customer_reward = function() {
+ $(this).parent().remove();
+ hide_show_remove();
+ };
- var init_add_remove_tables = function() {
- $('.add_customer_reward').click(add_customer_reward);
- $('.remove_customer_reward').click(remove_customer_reward);
- hide_show_remove();
- // set back disabled state
- enable_disable_customer_reward_enable();
- };
- init_add_remove_tables();
+ var init_add_remove_tables = function() {
+ $('.add_customer_reward').click(add_customer_reward);
+ $('.remove_customer_reward').click(remove_customer_reward);
+ hide_show_remove();
+ // set back disabled state
+ enable_disable_customer_reward_enable();
+ };
+ init_add_remove_tables();
- var duplicate_found = false;
- // run validator once for all fields
- $.validator.addMethod('customer_reward' , function(value, element) {
- var value_count = 0;
- $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").each(function() {
- value_count = $(this).val() == value ? value_count + 1 : value_count;
- });
- return value_count < 2;
+ var duplicate_found = false;
+ // run validator once for all fields
+ $.validator.addMethod('customer_reward' , function(value, element) {
+ var value_count = 0;
+ $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").each(function() {
+ value_count = $(this).val() == value ? value_count + 1 : value_count;
+ });
+ return value_count < 2;
}, "= lang('Config.customer_reward_duplicate') ?>");
$.validator.addMethod('valid_chars', function(value, element) {
- return value.indexOf('_') === -1;
+ return value.indexOf('_') === -1;
}, "= lang('Config.customer_reward_invalid_chars') ?>");
- $('#reward_config_form').validate($.extend(form_support.handler, {
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- beforeSerialize: function(arr, $form, options) {
- $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").prop("disabled", false);
- return true;
- },
- success: function(response) {
- $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
- $("#customer_rewards").load('= "config/customerRewards" ?>', init_add_remove_tables);
- },
- dataType: 'json'
- });
- },
+ $('#reward_config_form').validate($.extend(form_support.handler, {
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ beforeSerialize: function(arr, $form, options) {
+ $("input[name*='customer_reward']:not(input[name=customer_reward_enable])").prop("disabled", false);
+ return true;
+ },
+ success: function(response) {
+ $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
+ $("#customer_rewards").load('= "config/customerRewards" ?>', init_add_remove_tables);
+ },
+ dataType: 'json'
+ });
+ },
- errorLabelContainer: "#reward_error_message_box",
+ errorLabelContainer: "#reward_error_message_box",
- rules:
- {
- $table)
- {
- ?>
- = 'customer_reward_' . ++$i ?>:
- {
- required: true,
- customer_reward: true,
- valid_chars: true
- },
-
- },
+ foreach($customer_rewards as $customer_reward=>$table)
+ {
+ ?>
+ = 'customer_reward_' . ++$i ?>:
+ {
+ required: true,
+ customer_reward: true,
+ valid_chars: true
+ },
+
+ },
- messages:
- {
- $table)
- {
- ?>
- = 'customer_reward_' . ++$i ?>: "= lang('Config.customer_reward_required') ?>",
-
- }
- }));
+ foreach($customer_rewards as $customer_reward=>$table)
+ {
+ ?>
+ = 'customer_reward_' . ++$i ?>: "= lang('Config.customer_reward_required') ?>",
+
+ }
+ }));
});
diff --git a/app/Views/configs/stock_config.php b/app/Views/configs/stock_config.php
index 85ae2ae23..686f649eb 100644
--- a/app/Views/configs/stock_config.php
+++ b/app/Views/configs/stock_config.php
@@ -10,15 +10,15 @@
- = view('partial/stock_locations', ['stock_locations' => $stock_locations]) ?>
-
-
+ = view('partial/stock_locations', ['stock_locations' => $stock_locations]) ?>
+
+
= form_submit ([
'name' => 'submit_stock',
'id' => 'submit_stock',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
+ ]) ?>
= form_close() ?>
@@ -27,99 +27,99 @@
//validation and submit handling
$(document).ready(function()
{
- var location_count = = sizeof($stock_locations) ?>;
+ var location_count = = sizeof($stock_locations) ?>;
- var hide_show_remove = function() {
- if ($("input[name*='stock_location']:enabled").length > 1)
- {
- $(".remove_stock_location").show();
- }
- else
- {
- $(".remove_stock_location").hide();
- }
- };
+ var hide_show_remove = function() {
+ if ($("input[name*='stock_location']:enabled").length > 1)
+ {
+ $(".remove_stock_location").show();
+ }
+ else
+ {
+ $(".remove_stock_location").hide();
+ }
+ };
- var add_stock_location = function() {
- var block = $(this).parent().clone(true);
- var new_block = block.insertAfter($(this).parent());
- var new_block_id = 'stock_location[]';
- $(new_block).find('label').html("= lang('Config.stock_location') ?> " + ++location_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
- $(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
- hide_show_remove();
- };
+ var add_stock_location = function() {
+ var block = $(this).parent().clone(true);
+ var new_block = block.insertAfter($(this).parent());
+ var new_block_id = 'stock_location[]';
+ $(new_block).find('label').html("= lang('Config.stock_location') ?> " + ++location_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
+ $(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
+ hide_show_remove();
+ };
- var remove_stock_location = function() {
- $(this).parent().remove();
- hide_show_remove();
- };
+ var remove_stock_location = function() {
+ $(this).parent().remove();
+ hide_show_remove();
+ };
- var init_add_remove_locations = function() {
- $('.add_stock_location').click(add_stock_location);
- $('.remove_stock_location').click(remove_stock_location);
- hide_show_remove();
- };
- init_add_remove_locations();
+ var init_add_remove_locations = function() {
+ $('.add_stock_location').click(add_stock_location);
+ $('.remove_stock_location').click(remove_stock_location);
+ hide_show_remove();
+ };
+ init_add_remove_locations();
- var duplicate_found = false;
- // run validator once for all fields
- $.validator.addMethod('stock_location' , function(value, element) {
- var value_count = 0;
- $("input[name*='stock_location']").each(function() {
- value_count = $(this).val() == value ? value_count + 1 : value_count;
- });
- return value_count < 2;
+ var duplicate_found = false;
+ // run validator once for all fields
+ $.validator.addMethod('stock_location' , function(value, element) {
+ var value_count = 0;
+ $("input[name*='stock_location']").each(function() {
+ value_count = $(this).val() == value ? value_count + 1 : value_count;
+ });
+ return value_count < 2;
}, "= lang('Config.stock_location_duplicate') ?>");
$.validator.addMethod('valid_chars', function(value, element) {
- return value.indexOf('_') === -1;
+ return value.indexOf('_') === -1;
}, "= lang('Config.stock_location_invalid_chars') ?>");
-
- $('#location_config_form').validate($.extend(form_support.handler, {
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- success: function(response) {
- $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
- $("#stock_locations").load('= "config/stockLocations" ?>', init_add_remove_locations);
- },
- dataType: 'json'
- });
- },
- errorLabelContainer: "#stock_error_message_box",
+ $('#location_config_form').validate($.extend(form_support.handler, {
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ success: function(response) {
+ $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
+ $("#stock_locations").load('= "config/stockLocations" ?>', init_add_remove_locations);
+ },
+ dataType: 'json'
+ });
+ },
- rules:
- {
- $location_data)
- {
- ?>
- = 'stock_location_' . ++$i ?>:
- {
- required: true,
- stock_location: true,
- valid_chars: true
- },
-
- },
+ rules:
+ {
+ $location_data)
+ {
+ ?>
+ = 'stock_location_' . ++$i ?>:
+ {
+ required: true,
+ stock_location: true,
+ valid_chars: true
+ },
+
+ },
- foreach($stock_locations as $location => $location_data)
- {
- ?>
- = 'stock_location_' . ++$i ?>: "= lang('Config.stock_location_required') ?>",
-
- }
- }));
+ messages:
+ {
+ $location_data)
+ {
+ ?>
+ = 'stock_location_' . ++$i ?>: "= lang('Config.stock_location_required') ?>",
+
+ }
+ }));
});
diff --git a/app/Views/configs/system_config.php b/app/Views/configs/system_config.php
index 1a03d81fe..23329cf5b 100644
--- a/app/Views/configs/system_config.php
+++ b/app/Views/configs/system_config.php
@@ -1,17 +1,17 @@
-
-
-
= view('configs/system_info') ?>
-
= view('configs/email_config') ?>
-
= view('configs/message_config') ?>
-
= view('configs/integrations_config') ?>
-
= view('configs/license_config') ?>
-
+
+
+
= view('configs/system_info') ?>
+
= view('configs/email_config') ?>
+
= view('configs/message_config') ?>
+
= view('configs/integrations_config') ?>
+
= view('configs/license_config') ?>
+
diff --git a/app/Views/configs/system_info.php b/app/Views/configs/system_info.php
index 45df2bc32..13cf10c67 100644
--- a/app/Views/configs/system_info.php
+++ b/app/Views/configs/system_info.php
@@ -90,7 +90,7 @@ use Config\OSPOS;
Not Writable ✗ ';
+ echo ' - ' . substr(sprintf("%o", fileperms($logs)), -4) . ' | ' . ' Not Writable ✗ ';
}
clearstatcache();
@@ -117,7 +117,7 @@ use Config\OSPOS;
Writable ✓ ';
+ echo ' - ' . substr(sprintf("%o", fileperms($uploads)), -4) . ' | ' . ' Writable ✓ ';
}
else
{
@@ -142,11 +142,11 @@ use Config\OSPOS;
Writable ✓ ';
+ echo ' - ' . substr(sprintf("%o", fileperms($images)), -4) . ' | ' . ' Writable ✓ ';
}
else
{
- echo ' - ' . substr(sprintf("%o", fileperms($images)), -4) . ' | ' . ' Not Writable ✗ ';
+ echo ' - ' . substr(sprintf("%o", fileperms($images)), -4) . ' | ' . ' Not Writable ✗ ';
}
clearstatcache();
@@ -166,7 +166,7 @@ use Config\OSPOS;
» [importCustomers.csv:]
Readable ✓ ';
+ echo ' - ' . substr(sprintf("%o", fileperms($importCustomers)), -4) . ' | ' . ' Readable ✓ ';
} else {
echo ' - ' . substr(sprintf("%o", fileperms($importCustomers)), -4) . ' | ' . ' Not Readable ✗ ';
}
@@ -233,9 +233,9 @@ use Config\OSPOS;
});
if($('#timezone').html() !== $('#ostimezone').html()) {
- document.getElementById("timezone").innerText = Intl.DateTimeFormat().resolvedOptions().timeZone;
- document.getElementById("TimeError").innerHTML = '= lang('Config.timezone_error') ?>
= lang('Config.user_timezone') ?>
= lang('Config.os_timezone') ?>= esc($config['timezone']) ?>
';
- }
+ document.getElementById("timezone").innerText = Intl.DateTimeFormat().resolvedOptions().timeZone;
+ document.getElementById("TimeError").innerHTML = '= lang('Config.timezone_error') ?>
= lang('Config.user_timezone') ?>
= lang('Config.os_timezone') ?>= esc($config['timezone']) ?>
';
+ }
diff --git a/app/Views/configs/table_config.php b/app/Views/configs/table_config.php
index d535c79f6..9b34dc175 100644
--- a/app/Views/configs/table_config.php
+++ b/app/Views/configs/table_config.php
@@ -10,28 +10,28 @@
= lang('Common.fields_required_message') ?>
-
+
- = view('partial/dinner_tables', ['dinner_tables' => $dinner_tables]) ?>
-
+ = view('partial/dinner_tables', ['dinner_tables' => $dinner_tables]) ?>
+
= form_submit ([
'name' => 'submit_table',
'id' => 'submit_table',
'value' => lang('Common.submit'),
'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
+ ]) ?>
= form_close() ?>
@@ -41,123 +41,123 @@
$(document).ready(function()
{
- var enable_disable_dinner_table_enable = (function() {
- var dinner_table_enable = $("#dinner_table_enable").is(":checked");
- $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").prop("disabled", !dinner_table_enable);
- if(dinner_table_enable)
- {
- $(".add_dinner_table, .remove_dinner_table").show();
- }
- else
- {
- $(".add_dinner_table, .remove_dinner_table").hide();
- }
- return arguments.callee;
- })();
+ var enable_disable_dinner_table_enable = (function() {
+ var dinner_table_enable = $("#dinner_table_enable").is(":checked");
+ $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").prop("disabled", !dinner_table_enable);
+ if(dinner_table_enable)
+ {
+ $(".add_dinner_table, .remove_dinner_table").show();
+ }
+ else
+ {
+ $(".add_dinner_table, .remove_dinner_table").hide();
+ }
+ return arguments.callee;
+ })();
- $("#dinner_table_enable").change(enable_disable_dinner_table_enable);
+ $("#dinner_table_enable").change(enable_disable_dinner_table_enable);
- var table_count = = sizeof($dinner_tables) ?>;
+ var table_count = = sizeof($dinner_tables) ?>;
- var hide_show_remove = function() {
- if ($("input[name*='dinner_tables']:enabled").length > 1)
- {
- $(".remove_dinner_tables").show();
- }
- else
- {
- $(".remove_dinner_tables").hide();
- }
- };
+ var hide_show_remove = function() {
+ if ($("input[name*='dinner_tables']:enabled").length > 1)
+ {
+ $(".remove_dinner_tables").show();
+ }
+ else
+ {
+ $(".remove_dinner_tables").hide();
+ }
+ };
- var add_dinner_table = function() {
- var id = $(this).parent().find('input').attr('id');
- id = id.replace(/.*?_(\d+)$/g, "$1");
- var block = $(this).parent().clone(true);
- var new_block = block.insertAfter($(this).parent());
- var new_block_id = 'dinner_table_' + ++id;
- $(new_block).find('label').html("= lang('Config.dinner_table') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
- $(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
- hide_show_remove();
- };
+ var add_dinner_table = function() {
+ var id = $(this).parent().find('input').attr('id');
+ id = id.replace(/.*?_(\d+)$/g, "$1");
+ var block = $(this).parent().clone(true);
+ var new_block = block.insertAfter($(this).parent());
+ var new_block_id = 'dinner_table_' + ++id;
+ $(new_block).find('label').html("= lang('Config.dinner_table') ?> " + ++table_count).attr('for', new_block_id).attr('class', 'control-label col-xs-2');
+ $(new_block).find('input').attr('id', new_block_id).removeAttr('disabled').attr('name', new_block_id).attr('class', 'form-control input-sm').val('');
+ hide_show_remove();
+ };
- var remove_dinner_table = function() {
- $(this).parent().remove();
- hide_show_remove();
- };
+ var remove_dinner_table = function() {
+ $(this).parent().remove();
+ hide_show_remove();
+ };
- var init_add_remove_tables = function() {
- $('.add_dinner_table').click(add_dinner_table);
- $('.remove_dinner_table').click(remove_dinner_table);
- hide_show_remove();
- // set back disabled state
- enable_disable_dinner_table_enable();
- };
- init_add_remove_tables();
+ var init_add_remove_tables = function() {
+ $('.add_dinner_table').click(add_dinner_table);
+ $('.remove_dinner_table').click(remove_dinner_table);
+ hide_show_remove();
+ // set back disabled state
+ enable_disable_dinner_table_enable();
+ };
+ init_add_remove_tables();
- var duplicate_found = false;
- // run validator once for all fields
- $.validator.addMethod('dinner_table' , function(value, element) {
- var value_count = 0;
- $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").each(function() {
- value_count = $(this).val() == value ? value_count + 1 : value_count;
- });
- return value_count < 2;
+ var duplicate_found = false;
+ // run validator once for all fields
+ $.validator.addMethod('dinner_table' , function(value, element) {
+ var value_count = 0;
+ $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").each(function() {
+ value_count = $(this).val() == value ? value_count + 1 : value_count;
+ });
+ return value_count < 2;
}, "= lang('Config.dinner_table_duplicate') ?>");
$.validator.addMethod('valid_chars', function(value, element) {
- return value.indexOf('_') === -1;
+ return value.indexOf('_') === -1;
}, "= lang('Config.dinner_table_invalid_chars') ?>");
- $('#table_config_form').validate($.extend(form_support.handler, {
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- beforeSerialize: function(arr, $form, options) {
- $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").prop("disabled", false);
- return true;
- },
- success: function(response) {
- $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
- $("#dinner_tables").load('= "config/dinnerTables" ?>', init_add_remove_tables);
- },
- dataType: 'json'
- });
- },
+ $('#table_config_form').validate($.extend(form_support.handler, {
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ beforeSerialize: function(arr, $form, options) {
+ $("input[name*='dinner_table']:not(input[name=dinner_table_enable])").prop("disabled", false);
+ return true;
+ },
+ success: function(response) {
+ $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
+ $("#dinner_tables").load('= "config/dinnerTables" ?>', init_add_remove_tables);
+ },
+ dataType: 'json'
+ });
+ },
- errorLabelContainer: "#table_error_message_box",
+ errorLabelContainer: "#table_error_message_box",
- rules:
- {
- $table)
- {
- ?>
- = 'dinner_table_' . ++$i ?>:
- {
- required: true,
- dinner_table: true,
- valid_chars: true
- },
-
- },
+ foreach($dinner_tables as $dinner_table=>$table)
+ {
+ ?>
+ = 'dinner_table_' . ++$i ?>:
+ {
+ required: true,
+ dinner_table: true,
+ valid_chars: true
+ },
+
+ },
- messages:
- {
- $table)
- {
- ?>
- = 'dinner_table_' . ++$i ?>: "= lang('Config.dinner_table_required') ?>",
-
- }
- }));
+ foreach($dinner_tables as $dinner_table=>$table)
+ {
+ ?>
+ = 'dinner_table_' . ++$i ?>: "= lang('Config.dinner_table_required') ?>",
+
+ }
+ }));
});
diff --git a/app/Views/configs/tax_config.php b/app/Views/configs/tax_config.php
index d1d85eb51..028e96e42 100644
--- a/app/Views/configs/tax_config.php
+++ b/app/Views/configs/tax_config.php
@@ -8,132 +8,132 @@
*/
?>
= form_open('config/saveTax/', ['id' => 'tax_config_form', 'class' => 'form-horizontal']) ?>
-
-
- = lang('Common.fields_required_message') ?>
-
+
+
+ = lang('Common.fields_required_message') ?>
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- = form_submit ([
- 'name' => 'submit_tax',
- 'id' => 'submit_tax',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
-
-
+ = form_submit ([
+ 'name' => 'submit_tax',
+ 'id' => 'submit_tax',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right'
+ ]) ?>
+
+
= form_close() ?>
@@ -141,55 +141,55 @@
//validation and submit handling
$(document).ready(function()
{
- var enable_disable_use_destination_based_tax = (function() {
- var use_destination_based_tax = $("#use_destination_based_tax").is(":checked");
- $("select[name='default_tax_code']").prop("disabled", !use_destination_based_tax);
- $("select[name='default_tax_category']").prop("disabled", !use_destination_based_tax);
- $("select[name='default_tax_jurisdiction']").prop("disabled", !use_destination_based_tax);
- $("input[name='tax_included']").prop("disabled", use_destination_based_tax);
- $("input[name='default_tax_1_rate']").prop("disabled", use_destination_based_tax);
- $("input[name='default_tax_1_name']").prop("disabled", use_destination_based_tax);
- $("input[name='default_tax_2_rate']").prop("disabled", use_destination_based_tax);
- $("input[name='default_tax_2_name']").prop("disabled", use_destination_based_tax);
+ var enable_disable_use_destination_based_tax = (function() {
+ var use_destination_based_tax = $("#use_destination_based_tax").is(":checked");
+ $("select[name='default_tax_code']").prop("disabled", !use_destination_based_tax);
+ $("select[name='default_tax_category']").prop("disabled", !use_destination_based_tax);
+ $("select[name='default_tax_jurisdiction']").prop("disabled", !use_destination_based_tax);
+ $("input[name='tax_included']").prop("disabled", use_destination_based_tax);
+ $("input[name='default_tax_1_rate']").prop("disabled", use_destination_based_tax);
+ $("input[name='default_tax_1_name']").prop("disabled", use_destination_based_tax);
+ $("input[name='default_tax_2_rate']").prop("disabled", use_destination_based_tax);
+ $("input[name='default_tax_2_name']").prop("disabled", use_destination_based_tax);
- return arguments.callee;
- })();
+ return arguments.callee;
+ })();
- $("#use_destination_based_tax").change(enable_disable_use_destination_based_tax);
+ $("#use_destination_based_tax").change(enable_disable_use_destination_based_tax);
- $('#tax_config_form').validate($.extend(form_support.handler, {
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- beforeSerialize: function(arr, $form, options) {
- return true;
- },
- success: function(response) {
- $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
- },
- dataType: 'json'
- });
- },
+ $('#tax_config_form').validate($.extend(form_support.handler, {
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ beforeSerialize: function(arr, $form, options) {
+ return true;
+ },
+ success: function(response) {
+ $.notify({ message: response.message }, { type: response.success ? 'success' : 'danger'});
+ },
+ dataType: 'json'
+ });
+ },
- rules:
- {
- default_tax_1_rate:
- {
- remote: "= "$controller_name/checkNumeric" ?>"
- },
- default_tax2_rate:
- {
- remote: "= "$controller_name/checkNumeric" ?>"
- },
- },
+ rules:
+ {
+ default_tax_1_rate:
+ {
+ remote: "= "$controller_name/checkNumeric" ?>"
+ },
+ default_tax2_rate:
+ {
+ remote: "= "$controller_name/checkNumeric" ?>"
+ },
+ },
- messages:
- {
- default_tax_1_rate:
- {
- number: "= lang('Config.default_tax_rate_number') ?>"
- },
- }
- }));
+ messages:
+ {
+ default_tax_1_rate:
+ {
+ number: "= lang('Config.default_tax_rate_number') ?>"
+ },
+ }
+ }));
});
diff --git a/app/Views/customers/form.php b/app/Views/customers/form.php
index 770778608..171cd56f8 100644
--- a/app/Views/customers/form.php
+++ b/app/Views/customers/form.php
@@ -15,539 +15,539 @@
= form_open("$controller_name/save/$person_info->person_id", ['id' => 'customer_form', 'class' => 'form-horizontal']) ?>
-
+
-
-
-
-
+
+
+
+
- = view('people/form_basic_info') ?>
+ = view('people/form_basic_info') ?>
-
+
-
+
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
+
-
-
-
+
+
+
-
+
-
+
- = form_hidden('employee_id', $person_info->employee_id) ?>
-
-
+ = form_hidden('employee_id', $person_info->employee_id) ?>
+
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
-
+
-
+
-
-
-
-
+
+
+
+
-
-
-
-
+
+
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
+
+
+
+
= form_close() ?>
diff --git a/app/Views/customers/form_csv_import.php b/app/Views/customers/form_csv_import.php
index af2cc0e6b..903c8c59a 100644
--- a/app/Views/customers/form_csv_import.php
+++ b/app/Views/customers/form_csv_import.php
@@ -1,52 +1,52 @@
= form_open_multipart('customers/importCsvFile/', ['id' => 'csv_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/employees/form.php b/app/Views/employees/form.php
index 1270b5505..9916c3fcc 100644
--- a/app/Views/employees/form.php
+++ b/app/Views/employees/form.php
@@ -12,269 +12,269 @@
= form_open("$controller_name/save/$person_info->person_id", ['id' => 'employee_form', 'class' => 'form-horizontal']) ?>
-
+
-
-
-
- = view('people/form_basic_info') ?>
-
-
+
+
+
+ = view('people/form_basic_info') ?>
+
+
-
-
-
+
+
+
- person_id == "" ? ['class' => 'required'] : []; ?>
+ person_id == "" ? ['class' => 'required'] : []; ?>
-
+
-
+
-
+
+
+
+
-
-
- = lang('Employees.permission_desc') ?>
+
+
+ = lang('Employees.permission_desc') ?>
-
-
- -
- = form_checkbox("grant_$module->module_id", $module->module_id, $module->grant == 1, "class='module'") ?>
- = form_dropdown(
- "menu_group_$module->module_id", [
- 'home' => lang('Module.home'),
- 'office' => lang('Module.office'),
- 'both' => lang('Module.both')
- ],
- $module->menu_group,
- "class='module'"
- ) ?>
+
+
+ -
+ = form_checkbox("grant_$module->module_id", $module->module_id, $module->grant == 1, "class='module'") ?>
+ = form_dropdown(
+ "menu_group_$module->module_id", [
+ 'home' => lang('Module.home'),
+ 'office' => lang('Module.office'),
+ 'both' => lang('Module.both')
+ ],
+ $module->menu_group,
+ "class='module'"
+ ) ?>
- = lang("Module.$module->module_id") ?>:
- = lang("Module.$module->module_id" . '_desc') ?>
- permission_id, 2);
- if($permission->module_id == $module->module_id)
- {
- $lang_key = $module->module_id . '.' . $exploded_permission[1];
- $lang_line = lang(ucfirst($lang_key));
- $lang_line = (lang(ucfirst($lang_key)) == $lang_line) ? ucwords(str_replace("_", " ",$exploded_permission[1])) : $lang_line;
- if(!empty($lang_line))
- {
- ?>
-
- -
- = form_checkbox("grant_$permission->permission_id", $permission->permission_id, $permission->grant == 1) ?>
- = form_hidden("menu_group_$permission->permission_id", "--") ?>
- = $lang_line ?>
-
-
-
-
-
-
-
-
-
+
= lang("Module.$module->module_id") ?>:
+
= lang("Module.$module->module_id" . '_desc') ?>
+ permission_id, 2);
+ if($permission->module_id == $module->module_id)
+ {
+ $lang_key = $module->module_id . '.' . $exploded_permission[1];
+ $lang_line = lang(ucfirst($lang_key));
+ $lang_line = (lang(ucfirst($lang_key)) == $lang_line) ? ucwords(str_replace("_", " ",$exploded_permission[1])) : $lang_line;
+ if(!empty($lang_line))
+ {
+ ?>
+
+ -
+ = form_checkbox("grant_$permission->permission_id", $permission->permission_id, $permission->grant == 1) ?>
+ = form_hidden("menu_group_$permission->permission_id", "--") ?>
+ = $lang_line ?>
+
+
+
+
+
+
+
+
+
= form_close() ?>
diff --git a/app/Views/errors/cli/error_db.php b/app/Views/errors/cli/error_db.php
index c2a6d75ca..ea02c1c9f 100644
--- a/app/Views/errors/cli/error_db.php
+++ b/app/Views/errors/cli/error_db.php
@@ -4,7 +4,7 @@
* @var string $message
*/
echo "\nDatabase error: ",
- esc($heading),
- "\n\n",
- esc($message),
- "\n\n";
\ No newline at end of file
+ esc($heading),
+ "\n\n",
+ esc($message),
+ "\n\n";
diff --git a/app/Views/errors/cli/error_general.php b/app/Views/errors/cli/error_general.php
index 0efd45dcf..005e23542 100644
--- a/app/Views/errors/cli/error_general.php
+++ b/app/Views/errors/cli/error_general.php
@@ -4,7 +4,7 @@
* @var string $message
*/
echo "\nERROR: ",
- esc($heading),
- "\n\n",
- esc($message),
- "\n\n";
\ No newline at end of file
+ esc($heading),
+ "\n\n",
+ esc($message),
+ "\n\n";
diff --git a/app/Views/errors/cli/error_php.php b/app/Views/errors/cli/error_php.php
index 748456bc7..17f6e6d5d 100644
--- a/app/Views/errors/cli/error_php.php
+++ b/app/Views/errors/cli/error_php.php
@@ -16,12 +16,12 @@ Line Number: = $line ?>
Backtrace:
-
-
- File: = esc($error['file']), "\n" ?>
- Line: = $error['line'], "\n" ?>
- Function: = esc($error['function']), "\n\n" ?>
-
-
+
+
+ File: = esc($error['file']), "\n" ?>
+ Line: = $error['line'], "\n" ?>
+ Function: = esc($error['function']), "\n\n" ?>
+
+
diff --git a/app/Views/errors/cli/index.html b/app/Views/errors/cli/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Views/errors/cli/index.html
+++ b/app/Views/errors/cli/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Views/errors/html/error_db.php b/app/Views/errors/html/error_db.php
index 5086c59f2..a8cc0ec90 100644
--- a/app/Views/errors/html/error_db.php
+++ b/app/Views/errors/html/error_db.php
@@ -15,54 +15,54 @@
::-moz-selection { background-color: #E13300; color: white; }
body {
- background-color: #fff;
- margin: 40px;
- font: 13px/20px normal Helvetica, Arial, sans-serif;
- color: #4F5155;
+ background-color: #fff;
+ margin: 40px;
+ font: 13px/20px normal Helvetica, Arial, sans-serif;
+ color: #4F5155;
}
a {
- color: #003399;
- background-color: transparent;
- font-weight: normal;
+ color: #003399;
+ background-color: transparent;
+ font-weight: normal;
}
h1 {
- color: #444;
- background-color: transparent;
- border-bottom: 1px solid #D0D0D0;
- font-size: 19px;
- font-weight: normal;
- margin: 0 0 14px 0;
- padding: 14px 15px 10px 15px;
+ color: #444;
+ background-color: transparent;
+ border-bottom: 1px solid #D0D0D0;
+ font-size: 19px;
+ font-weight: normal;
+ margin: 0 0 14px 0;
+ padding: 14px 15px 10px 15px;
}
code {
- font-family: Consolas, Monaco, Courier New, Courier, monospace;
- font-size: 12px;
- background-color: #f9f9f9;
- border: 1px solid #D0D0D0;
- color: #002166;
- display: block;
- margin: 14px 0 14px 0;
- padding: 12px 10px 12px 10px;
+ font-family: Consolas, Monaco, Courier New, Courier, monospace;
+ font-size: 12px;
+ background-color: #f9f9f9;
+ border: 1px solid #D0D0D0;
+ color: #002166;
+ display: block;
+ margin: 14px 0 14px 0;
+ padding: 12px 10px 12px 10px;
}
#container {
- margin: 10px;
- border: 1px solid #D0D0D0;
- box-shadow: 0 0 8px #D0D0D0;
+ margin: 10px;
+ border: 1px solid #D0D0D0;
+ box-shadow: 0 0 8px #D0D0D0;
}
p {
- margin: 12px 15px 12px 15px;
+ margin: 12px 15px 12px 15px;
}
-
-
= esc($heading) ?>
- = esc($message) ?>
-
+
+
= esc($heading) ?>
+ = esc($message) ?>
+
diff --git a/app/Views/errors/html/error_general.php b/app/Views/errors/html/error_general.php
index 4b8ab5436..b49a7d81a 100644
--- a/app/Views/errors/html/error_general.php
+++ b/app/Views/errors/html/error_general.php
@@ -15,54 +15,54 @@
::-moz-selection { background-color: #E13300; color: white; }
body {
- background-color: #fff;
- margin: 40px;
- font: 13px/20px normal Helvetica, Arial, sans-serif;
- color: #4F5155;
+ background-color: #fff;
+ margin: 40px;
+ font: 13px/20px normal Helvetica, Arial, sans-serif;
+ color: #4F5155;
}
a {
- color: #003399;
- background-color: transparent;
- font-weight: normal;
+ color: #003399;
+ background-color: transparent;
+ font-weight: normal;
}
h1 {
- color: #444;
- background-color: transparent;
- border-bottom: 1px solid #D0D0D0;
- font-size: 19px;
- font-weight: normal;
- margin: 0 0 14px 0;
- padding: 14px 15px 10px 15px;
+ color: #444;
+ background-color: transparent;
+ border-bottom: 1px solid #D0D0D0;
+ font-size: 19px;
+ font-weight: normal;
+ margin: 0 0 14px 0;
+ padding: 14px 15px 10px 15px;
}
code {
- font-family: Consolas, Monaco, Courier New, Courier, monospace;
- font-size: 12px;
- background-color: #f9f9f9;
- border: 1px solid #D0D0D0;
- color: #002166;
- display: block;
- margin: 14px 0 14px 0;
- padding: 12px 10px 12px 10px;
+ font-family: Consolas, Monaco, Courier New, Courier, monospace;
+ font-size: 12px;
+ background-color: #f9f9f9;
+ border: 1px solid #D0D0D0;
+ color: #002166;
+ display: block;
+ margin: 14px 0 14px 0;
+ padding: 12px 10px 12px 10px;
}
#container {
- margin: 10px;
- border: 1px solid #D0D0D0;
- box-shadow: 0 0 8px #D0D0D0;
+ margin: 10px;
+ border: 1px solid #D0D0D0;
+ box-shadow: 0 0 8px #D0D0D0;
}
p {
- margin: 12px 15px 12px 15px;
+ margin: 12px 15px 12px 15px;
}
-
-
= esc($heading) ?>
- = esc($message) ?>
-
+
+
= esc($heading) ?>
+ = esc($message) ?>
+
diff --git a/app/Views/errors/html/error_php.php b/app/Views/errors/html/error_php.php
index 1562a8623..15d611730 100644
--- a/app/Views/errors/html/error_php.php
+++ b/app/Views/errors/html/error_php.php
@@ -17,20 +17,20 @@
- Backtrace:
-
+ Backtrace:
+
-
+
-
- File: = $error['file'] ?>
- Line: = $error['line'] ?>
- Function: = $error['function'] ?>
-
+
+ File: = $error['file'] ?>
+ Line: = $error['line'] ?>
+ Function: = $error['function'] ?>
+
-
+
-
+
diff --git a/app/Views/errors/html/index.html b/app/Views/errors/html/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Views/errors/html/index.html
+++ b/app/Views/errors/html/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Views/errors/index.html b/app/Views/errors/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Views/errors/index.html
+++ b/app/Views/errors/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Views/expenses/form.php b/app/Views/expenses/form.php
index 7233c5234..84ad8640d 100644
--- a/app/Views/expenses/form.php
+++ b/app/Views/expenses/form.php
@@ -13,258 +13,258 @@
= form_open("expenses/save/$expenses_info->expense_id", ['id' => 'expenses_edit_form', 'class' => 'form-horizontal']) ?>
-
-
- = form_label(lang('Expenses.info'), 'expenses_info', ['class' => 'control-label col-xs-3']) ?>
- = form_label(!empty($expenses_info->expense_id) ? lang('Expenses.expense_id') . " $expenses_info->expense_id" : '', 'expenses_info_id', ['class' => 'control-label col-xs-8', 'style' => 'text-align:left']) ?>
-
+
+
+ = form_label(lang('Expenses.info'), 'expenses_info', ['class' => 'control-label col-xs-3']) ?>
+ = form_label(!empty($expenses_info->expense_id) ? lang('Expenses.expense_id') . " $expenses_info->expense_id" : '', 'expenses_info_id', ['class' => 'control-label col-xs-8', 'style' => 'text-align:left']) ?>
+
-
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
- expense_id))
- {
- ?>
-
-
-
+ expense_id))
+ {
+ ?>
+
+
+
= form_close() ?>
diff --git a/app/Views/expenses/manage.php b/app/Views/expenses/manage.php
index efc2a6b44..cf5c0b657 100644
--- a/app/Views/expenses/manage.php
+++ b/app/Views/expenses/manage.php
@@ -11,68 +11,68 @@
= view('partial/print_receipt', ['print_after_sale' => false, 'selected_printer' => 'takings_printer']) ?>
-
-
+
+
diff --git a/app/Views/expenses_categories/form.php b/app/Views/expenses_categories/form.php
index 957c29f58..3318792c4 100644
--- a/app/Views/expenses_categories/form.php
+++ b/app/Views/expenses_categories/form.php
@@ -9,61 +9,61 @@
= form_open("expenses_categories/save/$category_info->expense_category_id", ['id' => 'expense_category_edit_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
= form_close() ?>
diff --git a/app/Views/expenses_categories/manage.php b/app/Views/expenses_categories/manage.php
index 66302a128..0aa6bfa6b 100644
--- a/app/Views/expenses_categories/manage.php
+++ b/app/Views/expenses_categories/manage.php
@@ -10,41 +10,41 @@
-
+
= view('partial/footer') ?>
diff --git a/app/Views/giftcards/form.php b/app/Views/giftcards/form.php
index 07eeb8240..e10d96ac2 100644
--- a/app/Views/giftcards/form.php
+++ b/app/Views/giftcards/form.php
@@ -14,163 +14,163 @@
= form_open("giftcards/save/$giftcard_id", ['id' => 'giftcard_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
-
+
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/giftcards/manage.php b/app/Views/giftcards/manage.php
index a1d9098c0..4af610389 100644
--- a/app/Views/giftcards/manage.php
+++ b/app/Views/giftcards/manage.php
@@ -9,33 +9,33 @@
-
+
= view('partial/footer') ?>
diff --git a/app/Views/home/form_change_password.php b/app/Views/home/form_change_password.php
index afc63befe..52f0a8758 100644
--- a/app/Views/home/form_change_password.php
+++ b/app/Views/home/form_change_password.php
@@ -8,126 +8,126 @@
= form_open("home/save/$person_info->person_id", ['id' => 'employee_form', 'class' => 'form-horizontal']) ?>
-
-
-
-
+
+
+
+
- person_id == "" ? ['class' => 'required'] : []; ?>
+ person_id == "" ? ['class' => 'required'] : []; ?>
-
+
-
+
-
-
-
-
+
+
+
+
= form_close() ?>
diff --git a/app/Views/home/home.php b/app/Views/home/home.php
index 01a320744..2cc51467d 100644
--- a/app/Views/home/home.php
+++ b/app/Views/home/home.php
@@ -6,23 +6,23 @@
= view('partial/header') ?>
= lang('Common.welcome_message') ?>
= view('partial/footer') ?>
diff --git a/app/Views/home/office.php b/app/Views/home/office.php
index 0552a7f41..04b1a2f89 100644
--- a/app/Views/home/office.php
+++ b/app/Views/home/office.php
@@ -6,23 +6,23 @@
= view('partial/header') ?>
= lang('Common.welcome_message') ?>
= view('partial/footer') ?>
diff --git a/app/Views/index.html b/app/Views/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Views/index.html
+++ b/app/Views/index.html
@@ -1,7 +1,7 @@
-
403 Forbidden
+
403 Forbidden
diff --git a/app/Views/item_kits/form.php b/app/Views/item_kits/form.php
index 2c79282f9..169e6c6e6 100644
--- a/app/Views/item_kits/form.php
+++ b/app/Views/item_kits/form.php
@@ -12,201 +12,201 @@
= form_open("item_kits/save/$item_kit_info->item_kit_id", ['id' => 'item_kit_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
-
+
-
+
-
-
-
+
-
+
-
-
+
+
= form_close() ?>
@@ -214,103 +214,103 @@
//validation and submit handling
$(document).ready(function()
{
- $('#item').autocomplete({
- source: '= "items/suggest" ?>',
- minChars: 0,
- autoFocus: false,
- delay: 10,
- appendTo: '.modal-content',
- select: function(e, ui) {
- if($('#item_kit_item_' + ui.item.value).length == 1)
- {
- $('#item_kit_item_' + ui.item.value).val(parseFloat( $('#item_kit_item_' + ui.item.value).val()) + 1);
- }
- else
- {
- $('#item_kit_items').append('
' +
- " | " +
- " | " +
- '' + ui.item.label + ' | ' +
- " | " +
- '
');
- }
- $('#item').val('');
- return false;
- }
- });
+ $('#item').autocomplete({
+ source: '= "items/suggest" ?>',
+ minChars: 0,
+ autoFocus: false,
+ delay: 10,
+ appendTo: '.modal-content',
+ select: function(e, ui) {
+ if($('#item_kit_item_' + ui.item.value).length == 1)
+ {
+ $('#item_kit_item_' + ui.item.value).val(parseFloat( $('#item_kit_item_' + ui.item.value).val()) + 1);
+ }
+ else
+ {
+ $('#item_kit_items').append('
' +
+ " | " +
+ " | " +
+ '' + ui.item.label + ' | ' +
+ " | " +
+ '
');
+ }
+ $('#item').val('');
+ return false;
+ }
+ });
- $("input[name='item_name']").change(function() {
- if( ! $("input[name='item_name']").val() ) {
- $("input[name='kit_item_id']").val('');
- }
- });
+ $("input[name='item_name']").change(function() {
+ if( ! $("input[name='item_name']").val() ) {
+ $("input[name='kit_item_id']").val('');
+ }
+ });
- var fill_value = function(event, ui) {
- event.preventDefault();
- $("input[name='kit_item_id']").val(ui.item.value);
- $("input[name='item_name']").val(ui.item.label);
- };
+ var fill_value = function(event, ui) {
+ event.preventDefault();
+ $("input[name='kit_item_id']").val(ui.item.value);
+ $("input[name='item_name']").val(ui.item.label);
+ };
- $('#item_name').autocomplete({
- source: "= 'items/suggestKits' ?>",
- minChars: 0,
- delay: 15,
- cacheLength: 1,
- appendTo: '.modal-content',
- select: fill_value,
- focus: fill_value
- });
+ $('#item_name').autocomplete({
+ source: "= 'items/suggestKits' ?>",
+ minChars: 0,
+ delay: 15,
+ cacheLength: 1,
+ appendTo: '.modal-content',
+ select: fill_value,
+ focus: fill_value
+ });
- $('#item_kit_form').validate($.extend({
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- success: function(response)
- {
- dialog_support.hide();
- table_support.handle_submit("= esc($controller_name) ?>", response);
- },
- dataType: 'json'
- });
- },
+ $('#item_kit_form').validate($.extend({
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ success: function(response)
+ {
+ dialog_support.hide();
+ table_support.handle_submit("= esc($controller_name) ?>", response);
+ },
+ dataType: 'json'
+ });
+ },
- errorLabelContainer: '#error_message_box',
+ errorLabelContainer: '#error_message_box',
- rules:
- {
- name: 'required',
- category: 'required',
- item_kit_number:
- {
- required: false,
- remote:
- {
- url: '= esc("$controller_name/checkItemNumber") ?>',
- type: 'POST',
- data:
- {
- 'item_kit_id' : "= $item_kit_info->item_kit_id ?>",
- 'item_kit_number' : function()
- {
- return $('#item_kit_number').val();
- }
- }
- }
- }
- },
+ rules:
+ {
+ name: 'required',
+ category: 'required',
+ item_kit_number:
+ {
+ required: false,
+ remote:
+ {
+ url: '= esc("$controller_name/checkItemNumber") ?>',
+ type: 'POST',
+ data:
+ {
+ 'item_kit_id' : "= $item_kit_info->item_kit_id ?>",
+ 'item_kit_number' : function()
+ {
+ return $('#item_kit_number').val();
+ }
+ }
+ }
+ }
+ },
- messages:
- {
- name: "= lang('Items.name_required') ?>",
- category: "= lang('Items.category_required') ?>",
- item_kit_number: "= lang('Item_kits.item_number_duplicate') ?>"
- }
- }, form_support.error));
+ messages:
+ {
+ name: "= lang('Items.name_required') ?>",
+ category: "= lang('Items.category_required') ?>",
+ item_kit_number: "= lang('Item_kits.item_number_duplicate') ?>"
+ }
+ }, form_support.error));
});
function delete_item_kit_row(link)
{
- $(link).parent().parent().remove();
- return false;
+ $(link).parent().parent().remove();
+ return false;
}
diff --git a/app/Views/item_kits/manage.php b/app/Views/item_kits/manage.php
index c84f4e483..2187fb0cb 100644
--- a/app/Views/item_kits/manage.php
+++ b/app/Views/item_kits/manage.php
@@ -10,47 +10,47 @@
-
+
= view('partial/footer') ?>
diff --git a/app/Views/items/form.php b/app/Views/items/form.php
index 03a9d3fd9..afbc51e39 100644
--- a/app/Views/items/form.php
+++ b/app/Views/items/form.php
@@ -29,652 +29,652 @@
= form_open("items/save/$item_info->item_id", ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
-
-
-
+
+
+
-
+
-
-
+
-
+
-
+
-
-
+
+
-
-
+
+
-
-
-
+
+
+
-
-
-
+
+
+
- $location_detail)
- {
- ?>
-
-
+ $location_detail)
+ {
+ ?>
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
-
-
-
+
+
+
+
+
-
+
-
+
= form_close() ?>
diff --git a/app/Views/items/form_bulk.php b/app/Views/items/form_bulk.php
index 15099017a..6cdfb1984 100644
--- a/app/Views/items/form_bulk.php
+++ b/app/Views/items/form_bulk.php
@@ -12,238 +12,238 @@
= form_open('items/bulkUpdate/', ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/items/form_count_details.php b/app/Views/items/form_count_details.php
index 2e1f832c4..467ac955a 100644
--- a/app/Views/items/form_count_details.php
+++ b/app/Views/items/form_count_details.php
@@ -10,154 +10,154 @@ use App\Models\Inventory;
?>
= form_open('items', ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
-
+
-
-
+
+
= form_close() ?>
-
-
- | = lang('Items.inventory_data_tracking') ?> |
-
-
- | = lang('Items.inventory_date') ?> |
- = lang('Items.inventory_employee') ?> |
- = lang('Items.inventory_in_out_quantity') ?> |
- = lang('Items.inventory_remarks') ?> |
-
-
-
-
+
+ | = lang('Items.inventory_data_tracking') ?> |
+
+
+ | = lang('Items.inventory_date') ?> |
+ = lang('Items.inventory_employee') ?> |
+ = lang('Items.inventory_in_out_quantity') ?> |
+ = lang('Items.inventory_remarks') ?> |
+
+
+
+ get_inventory_data_for_item($item_info->item_id)->getResultArray();
- $employee_name = [];
+ $inventory_array = $inventory->get_inventory_data_for_item($item_info->item_id)->getResultArray();
+ $employee_name = [];
- foreach($inventory_array as $row)
- {
- $employee_data = $employee->get_info($row['trans_user']);
- $employee_name[] = $employee_data->first_name . ' ' . $employee_data->last_name;
- }
- ?>
-
+ foreach($inventory_array as $row)
+ {
+ $employee_data = $employee->get_info($row['trans_user']);
+ $employee_name[] = $employee_data->first_name . ' ' . $employee_data->last_name;
+ }
+ ?>
+
diff --git a/app/Views/items/form_csv_import.php b/app/Views/items/form_csv_import.php
index f16be7fd9..2af6cb7e4 100644
--- a/app/Views/items/form_csv_import.php
+++ b/app/Views/items/form_csv_import.php
@@ -1,52 +1,52 @@
= form_open_multipart('items/importCsvFile/', ['id' => 'csv_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/items/form_inventory.php b/app/Views/items/form_inventory.php
index be002d007..baf02536a 100644
--- a/app/Views/items/form_inventory.php
+++ b/app/Views/items/form_inventory.php
@@ -11,137 +11,137 @@
= form_open("items/saveInventory/$item_info->item_id", ['id' => 'item_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
-
+
-
+
-
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/items/manage.php b/app/Views/items/manage.php
index d65d9840c..5a01182ac 100644
--- a/app/Views/items/manage.php
+++ b/app/Views/items/manage.php
@@ -24,19 +24,19 @@ $(document).ready(function()
);
});
- // when any filter is clicked and the dropdown window is closed
- $('#filters').on('hidden.bs.select', function(e)
- {
+ // when any filter is clicked and the dropdown window is closed
+ $('#filters').on('hidden.bs.select', function(e)
+ {
table_support.refresh();
});
- // load the preset daterange picker
- = view('partial/daterangepicker') ?>
+ // load the preset daterange picker
+ = view('partial/daterangepicker') ?>
// set the beginning of time as starting date
$('#daterangepicker').data('daterangepicker').setStartDate("= date($config['dateformat'], mktime(0,0,0,01,01,2010)) ?>");
- // update the hidden inputs with the selected dates before submitting the search data
+ // update the hidden inputs with the selected dates before submitting the search data
var start_date = "= date('Y-m-d', mktime(0,0,0,01,01,2010)) ?>";
- $("#daterangepicker").on('apply.daterangepicker', function(ev, picker) {
+ $("#daterangepicker").on('apply.daterangepicker', function(ev, picker) {
table_support.refresh();
});
@@ -45,9 +45,9 @@ $(document).ready(function()
});
+ echo view('partial/bootstrap_tables_locale');
+ $employee = model(Employee::class);
+ ?>
table_support.init({
employee_id: = $employee->get_logged_in_employee_info()->person_id ?>,
@@ -65,9 +65,9 @@ $(document).ready(function()
},
onLoadSuccess: function(response) {
$('a.rollover').imgPreview({
- imgCSS: { width: 200 },
- distanceFromCursor: { top:10, left:-210 }
- })
+ imgCSS: { width: 200 },
+ distanceFromCursor: { top:10, left:-210 }
+ })
}
});
});
@@ -90,7 +90,7 @@ $(document).ready(function()
= lang('Common.delete') ?>
= form_input (['name' => 'daterangepicker', 'class' => 'form-control input-sm', 'id' => 'daterangepicker']) ?>
= form_multiselect(
- 'filters[]',
- $filters,
- [''],
- [
- 'id' => 'filters',
- 'class' => 'selectpicker show-menu-arrow',
- 'data-none-selected-text' => lang('Common.none_selected_text'),
- 'data-selected-text-format' => 'count > 1',
- 'data-style' => 'btn-default btn-sm',
- 'data-width' => 'fit'
- ]) ?>
+ 'filters[]',
+ $filters,
+ [''],
+ [
+ 'id' => 'filters',
+ 'class' => 'selectpicker show-menu-arrow',
+ 'data-none-selected-text' => lang('Common.none_selected_text'),
+ 'data-selected-text-format' => 'count > 1',
+ 'data-style' => 'btn-default btn-sm',
+ 'data-width' => 'fit'
+ ]) ?>
1)
{
echo form_dropdown(
- 'stock_location',
- $stock_locations,
- $stock_location,
- [
- 'id' => 'stock_location',
- 'class' => 'selectpicker show-menu-arrow',
- 'data-style' => 'btn-default btn-sm',
- 'data-width' => 'fit'
- ]
- );
+ 'stock_location',
+ $stock_locations,
+ $stock_location,
+ [
+ 'id' => 'stock_location',
+ 'class' => 'selectpicker show-menu-arrow',
+ 'data-style' => 'btn-default btn-sm',
+ 'data-width' => 'fit'
+ ]
+ );
}
?>
diff --git a/app/Views/login.php b/app/Views/login.php
index dbc1d1350..94448e982 100644
--- a/app/Views/login.php
+++ b/app/Views/login.php
@@ -13,110 +13,110 @@
-
-
- = $config['company'] . ' | ' . lang('Common.software_short') . ' | ' . lang('Login.login') ?>
-
-
-
-
- /bootstrap.min.css">
-
-
-
-
+
+
+ = $config['company'] . ' | ' . lang('Common.software_short') . ' | ' . lang('Login.login') ?>
+
+
+
+
+ /bootstrap.min.css">
+
+
+
+
-
-
-
-
-
![<?= lang('Common.logo') . ' ' . $config['company'] ?>](<?= base_url('uploads/' . $config['company_logo']) ?>)
-
-
-
-
-
- = form_open('login') ?>
- = lang('Login.welcome', [lang('Common.software_short')]) ?>
-
- getErrors() as $error): ?>
-
- = $error ?>
-
-
-
-
-
- = lang('Login.migration_needed', [$latest_version]) ?>
-
-
-
-
- >
-
-
-
- >
-
-
-
-
-
-
- ';
- echo '';
- }
- ?>
-
-
-
- = form_close() ?>
-
-
-
+
+
+
+
+
![<?= lang('Common.logo') . ' ' . $config['company'] ?>](<?= base_url('uploads/' . $config['company_logo']) ?>)
+
+
+
+
+
+ = form_open('login') ?>
+ = lang('Login.welcome', [lang('Common.software_short')]) ?>
+
+ getErrors() as $error): ?>
+
+ = $error ?>
+
+
+
+
+
+ = lang('Login.migration_needed', [$latest_version]) ?>
+
+
+
+
+ >
+
+
+
+ >
+
+
+
+
+
+
+ ';
+ echo '';
+ }
+ ?>
+
+
+
+ = form_close() ?>
+
+
+
-
+
diff --git a/app/Views/messages/form_sms.php b/app/Views/messages/form_sms.php
index 9f4ac6081..8b3d383d5 100644
--- a/app/Views/messages/form_sms.php
+++ b/app/Views/messages/form_sms.php
@@ -10,81 +10,81 @@
= form_open("messages/send_form/$person_info->person_id", ['id' => 'send_sms_form', 'class' => 'form-horizontal']) ?>
-
-
-
-
-
-
+
+
+
+
+
+
= form_close() ?>
diff --git a/app/Views/messages/index.html b/app/Views/messages/index.html
index bcb7cae34..905c65ee7 100644
--- a/app/Views/messages/index.html
+++ b/app/Views/messages/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/app/Views/messages/sms.php b/app/Views/messages/sms.php
index db81ade7c..0c0605c1f 100644
--- a/app/Views/messages/sms.php
+++ b/app/Views/messages/sms.php
@@ -1,35 +1,35 @@
= view('partial/header') ?>
-
+
- = form_open("messages/send/", ['id' => 'send_sms_form', 'enctype' => 'multipart/form-data', 'method' => 'post', 'class' => 'form-horizontal']) ?>
-
-
-
+ = form_open("messages/send/", ['id' => 'send_sms_form', 'enctype' => 'multipart/form-data', 'method' => 'post', 'class' => 'form-horizontal']) ?>
+
+
+
-
+
- = form_submit ([
- 'name' => 'submit_form',
- 'id' => 'submit_form',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
- = form_close() ?>
+ = form_submit ([
+ 'name' => 'submit_form',
+ 'id' => 'submit_form',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
+ = form_close() ?>
= view('partial/footer') ?>
@@ -38,15 +38,15 @@
//validation and submit handling
$(document).ready(function()
{
- $('#send_sms_form').validate({
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- success: function(response) {
- $.notify( { message: response.message }, { type: response.success ? 'success' : 'danger'} )
- },
- dataType: 'json'
- });
- }
- });
+ $('#send_sms_form').validate({
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ success: function(response) {
+ $.notify( { message: response.message }, { type: response.success ? 'success' : 'danger'} )
+ },
+ dataType: 'json'
+ });
+ }
+ });
});
diff --git a/app/Views/partial/bootstrap_tables_locale.php b/app/Views/partial/bootstrap_tables_locale.php
index 5377f7930..41435954c 100644
--- a/app/Views/partial/bootstrap_tables_locale.php
+++ b/app/Views/partial/bootstrap_tables_locale.php
@@ -4,54 +4,54 @@
*/
?>
(function ($) {
- 'use strict';
+ 'use strict';
- $.fn.bootstrapTable.locales['= current_language_code() ?>'] = {
- formatLoadingMessage: function () {
- return "= lang('Bootstrap_tables.loading') ?>";
- },
- formatRecordsPerPage: function (pageNumber) {
- return "= lang('Bootstrap_tables.rows_per_page') ?>".replace('{0}', pageNumber);
- },
- formatShowingRows: function (pageFrom, pageTo, totalRows) {
- return "= lang('Bootstrap_tables.page_from_to') ?>".replace('{0}', pageFrom).replace('{1}', pageTo).replace('{2}', totalRows);
- },
- formatSearch: function () {
- return "= lang('Common.search') ?>";
- },
- formatNoMatches: function () {
- return "= lang(preg_match('(customers|suppliers|employees)', $controller_name)
- ? 'Common.no_persons_to_display'
- : ucfirst($controller_name) . '.no_' . $controller_name . '_to_display')
- ?>";
- },
- formatPaginationSwitch: function () {
- return "= lang('Bootstrap_tables.hide_show_pagination') ?>";
- },
- formatRefresh: function () {
- return "= lang('Bootstrap_tables.refresh') ?>";
- },
- formatToggle: function () {
- return "= lang('Bootstrap_tables.toggle') ?>";
- },
- formatColumns: function () {
- return "= lang('Bootstrap_tables.columns') ?>";
- },
- formatAllRows: function () {
- return "= lang('Bootstrap_tables.all') ?>";
- },
- formatConfirmAction: function(action) {
- if (action == "delete")
- {
- return "= lang(ucfirst($editable ?? $controller_name). '.confirm_delete') ?>";
- }
- else
- {
- return "= lang(ucfirst($editable ?? $controller_name). '.confirm_restore') ?>";
- }
+ $.fn.bootstrapTable.locales['= current_language_code() ?>'] = {
+ formatLoadingMessage: function () {
+ return "= lang('Bootstrap_tables.loading') ?>";
+ },
+ formatRecordsPerPage: function (pageNumber) {
+ return "= lang('Bootstrap_tables.rows_per_page') ?>".replace('{0}', pageNumber);
+ },
+ formatShowingRows: function (pageFrom, pageTo, totalRows) {
+ return "= lang('Bootstrap_tables.page_from_to') ?>".replace('{0}', pageFrom).replace('{1}', pageTo).replace('{2}', totalRows);
+ },
+ formatSearch: function () {
+ return "= lang('Common.search') ?>";
+ },
+ formatNoMatches: function () {
+ return "= lang(preg_match('(customers|suppliers|employees)', $controller_name)
+ ? 'Common.no_persons_to_display'
+ : ucfirst($controller_name) . '.no_' . $controller_name . '_to_display')
+ ?>";
+ },
+ formatPaginationSwitch: function () {
+ return "= lang('Bootstrap_tables.hide_show_pagination') ?>";
+ },
+ formatRefresh: function () {
+ return "= lang('Bootstrap_tables.refresh') ?>";
+ },
+ formatToggle: function () {
+ return "= lang('Bootstrap_tables.toggle') ?>";
+ },
+ formatColumns: function () {
+ return "= lang('Bootstrap_tables.columns') ?>";
+ },
+ formatAllRows: function () {
+ return "= lang('Bootstrap_tables.all') ?>";
+ },
+ formatConfirmAction: function(action) {
+ if (action == "delete")
+ {
+ return "= lang(ucfirst($editable ?? $controller_name). '.confirm_delete') ?>";
+ }
+ else
+ {
+ return "= lang(ucfirst($editable ?? $controller_name). '.confirm_restore') ?>";
+ }
}
- };
+ };
- $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales["= current_language_code() ?>"]);
+ $.extend($.fn.bootstrapTable.defaults, $.fn.bootstrapTable.locales["= current_language_code() ?>"]);
})(jQuery);
diff --git a/app/Views/partial/customer_rewards.php b/app/Views/partial/customer_rewards.php
index f06d2c4ed..228de031a 100644
--- a/app/Views/partial/customer_rewards.php
+++ b/app/Views/partial/customer_rewards.php
@@ -4,43 +4,43 @@
*/
?>
$reward_category)
- {
- $customer_reward_id = $reward_category['package_id'];
- $customer_reward_name = $reward_category['package_name'];
- $customer_points_percent = $reward_category['points_percent'];
- ++$i;
+ foreach($customer_rewards as $reward_key => $reward_category)
+ {
+ $customer_reward_id = $reward_category['package_id'];
+ $customer_reward_name = $reward_category['package_name'];
+ $customer_points_percent = $reward_category['points_percent'];
+ ++$i;
?>
-
+
diff --git a/app/Views/partial/datepicker_locale.php b/app/Views/partial/datepicker_locale.php
index 61251ec86..d844201f3 100644
--- a/app/Views/partial/datepicker_locale.php
+++ b/app/Views/partial/datepicker_locale.php
@@ -29,39 +29,39 @@ var pickerconfig = function(config) {
todayHighlight: true,
bootcssVer: 3,
language: "= current_language_code() ?>"
- }, );
+ }, );
};
$.fn.datetimepicker.dates['= $config['language'] ?>'] = {
days: [
- "= lang('Calendar.sunday') ?>",
+ "= lang('Calendar.sunday') ?>",
"= lang('Calendar.monday') ?>",
"= lang('Calendar.tuesday') ?>",
"= lang('Calendar.wednesday') ?>",
"= lang('Calendar.thursday') ?>",
"= lang('Calendar.friday') ?>",
"= lang('Calendar.saturday') ?>"
- ],
+ ],
daysShort: [
- "= lang('Calendar.sun') ?>",
+ "= lang('Calendar.sun') ?>",
"= lang('Calendar.mon') ?>",
"= lang('Calendar.tue') ?>",
"= lang('Calendar.wed') ?>",
"= lang('Calendar.thu') ?>",
"= lang('Calendar.fri') ?>",
"= lang('Calendar.sat') ?>"
- ],
+ ],
daysMin: [
- "= lang('Calendar.su') ?>",
+ "= lang('Calendar.su') ?>",
"= lang('Calendar.mo') ?>",
"= lang('Calendar.tu') ?>",
"= lang('Calendar.we') ?>",
"= lang('Calendar.th') ?>",
"= lang('Calendar.fr') ?>",
"= lang('Calendar.sa') ?>"
- ],
+ ],
months: [
- "= lang('Calendar.january') ?>",
+ "= lang('Calendar.january') ?>",
"= lang('Calendar.february') ?>",
"= lang('Calendar.march') ?>",
"= lang('Calendar.april') ?>",
@@ -73,9 +73,9 @@ $.fn.datetimepicker.dates['= $config['language'] ?>'] = {
"= lang('Calendar.october') ?>",
"= lang('Calendar.november') ?>",
"= lang('Calendar.december') ?>"
- ],
+ ],
monthsShort: [
- "= lang('Calendar.jan') ?>",
+ "= lang('Calendar.jan') ?>",
"= lang('Calendar.feb') ?>",
"= lang('Calendar.mar') ?>",
"= lang('Calendar.apr') ?>",
@@ -87,7 +87,7 @@ $.fn.datetimepicker.dates['= $config['language'] ?>'] = {
"= lang('Calendar.oct') ?>",
"= lang('Calendar.nov') ?>",
"= lang('Calendar.dec') ?>"
- ],
+ ],
today: "= lang('Datepicker.today') ?>",
- $('#daterangepicker').css("width","180");
- var start_date = "= date('Y-m-d') ?>";
- var end_date = "= date('Y-m-d') ?>";
+ $('#daterangepicker').css("width","180");
+ var start_date = "= date('Y-m-d') ?>";
+ var end_date = "= date('Y-m-d') ?>";
- $('#daterangepicker').daterangepicker({
- "ranges": {
- "= lang('Datepicker.today') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.today_last_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y")-1)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y")-1)-1) ?>"
- ],
- "= lang('Datepicker.yesterday') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-1,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.last_7') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-6,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.last_30') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-29,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.this_month') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m")+1,1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y")-1)-1) ?>"
- ],
- "= lang('Datepicker.same_month_last_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m")+1,1,date("Y")-1)-1) ?>"
- ],
- "= lang('Datepicker.last_month') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,date("m")-1,1,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.this_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")+1)-1) ?>"
- ],
- "= lang('Datepicker.last_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y")-1)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.this_financial_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y"))) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")+1)-1) ?>"
- ],
- "= lang('Datepicker.last_financial_year') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y")-1)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y"))-1) ?>"
- ],
- "= lang('Datepicker.all_time') ?>": [
- "= date($config['dateformat'], mktime(0,0,0,1,1,2010)) ?>",
- "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
- ],
- },
- "locale": {
- "format": '= dateformat_momentjs($config['dateformat']) ?>',
- "separator": " - ",
- "applyLabel": "= lang('Datepicker.apply') ?>",
- "cancelLabel": "= lang('Datepicker.cancel') ?>",
- "fromLabel": "= lang('Datepicker.from') ?>",
- "toLabel": "= lang('Datepicker.to') ?>",
- "customRangeLabel": "= lang('Datepicker.custom') ?>",
- "daysOfWeek": [
- "= lang('Calendar.su') ?>",
- "= lang('Calendar.mo') ?>",
- "= lang('Calendar.tu') ?>",
- "= lang('Calendar.we') ?>",
- "= lang('Calendar.th') ?>",
- "= lang('Calendar.fr') ?>",
- "= lang('Calendar.sa') ?>"
- ],
- "monthNames": [
- "= lang('Calendar.january') ?>",
- "= lang('Calendar.february') ?>",
- "= lang('Calendar.march') ?>",
- "= lang('Calendar.april') ?>",
- "= lang('Calendar.may') ?>",
- "= lang('Calendar.june') ?>",
- "= lang('Calendar.july') ?>",
- "= lang('Calendar.august') ?>",
- "= lang('Calendar.september') ?>",
- "= lang('Calendar.october') ?>",
- "= lang('Calendar.november') ?>",
- "= lang('Calendar.december') ?>"
- ],
- "firstDay": = lang('Datepicker.weekstart') ?>
- },
- "alwaysShowCalendars": true,
- "startDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>",
- "endDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>",
- "minDate": "= date($config['dateformat'], mktime(0,0,0,01,01,2010)) ?>",
- "maxDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
- }, function(start, end, label) {
- start_date = start.format('YYYY-MM-DD');
- end_date = end.format('YYYY-MM-DD');
- });
+ $('#daterangepicker').daterangepicker({
+ "ranges": {
+ "= lang('Datepicker.today') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.today_last_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y")-1)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y")-1)-1) ?>"
+ ],
+ "= lang('Datepicker.yesterday') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-1,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.last_7') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-6,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.last_30') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")-29,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.this_month') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m")+1,1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y")-1)-1) ?>"
+ ],
+ "= lang('Datepicker.same_month_last_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m")+1,1,date("Y")-1)-1) ?>"
+ ],
+ "= lang('Datepicker.last_month') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,date("m")-1,1,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.this_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")+1)-1) ?>"
+ ],
+ "= lang('Datepicker.last_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y")-1)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,1,1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.this_financial_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y"))) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),1,date("Y")+1)-1) ?>"
+ ],
+ "= lang('Datepicker.last_financial_year') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y")-1)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,$config['financial_year'],1,date("Y"))-1) ?>"
+ ],
+ "= lang('Datepicker.all_time') ?>": [
+ "= date($config['dateformat'], mktime(0,0,0,1,1,2010)) ?>",
+ "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
+ ],
+ },
+ "locale": {
+ "format": '= dateformat_momentjs($config['dateformat']) ?>',
+ "separator": " - ",
+ "applyLabel": "= lang('Datepicker.apply') ?>",
+ "cancelLabel": "= lang('Datepicker.cancel') ?>",
+ "fromLabel": "= lang('Datepicker.from') ?>",
+ "toLabel": "= lang('Datepicker.to') ?>",
+ "customRangeLabel": "= lang('Datepicker.custom') ?>",
+ "daysOfWeek": [
+ "= lang('Calendar.su') ?>",
+ "= lang('Calendar.mo') ?>",
+ "= lang('Calendar.tu') ?>",
+ "= lang('Calendar.we') ?>",
+ "= lang('Calendar.th') ?>",
+ "= lang('Calendar.fr') ?>",
+ "= lang('Calendar.sa') ?>"
+ ],
+ "monthNames": [
+ "= lang('Calendar.january') ?>",
+ "= lang('Calendar.february') ?>",
+ "= lang('Calendar.march') ?>",
+ "= lang('Calendar.april') ?>",
+ "= lang('Calendar.may') ?>",
+ "= lang('Calendar.june') ?>",
+ "= lang('Calendar.july') ?>",
+ "= lang('Calendar.august') ?>",
+ "= lang('Calendar.september') ?>",
+ "= lang('Calendar.october') ?>",
+ "= lang('Calendar.november') ?>",
+ "= lang('Calendar.december') ?>"
+ ],
+ "firstDay": = lang('Datepicker.weekstart') ?>
+ },
+ "alwaysShowCalendars": true,
+ "startDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>",
+ "endDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>",
+ "minDate": "= date($config['dateformat'], mktime(0,0,0,01,01,2010)) ?>",
+ "maxDate": "= date($config['dateformat'], mktime(0,0,0,date("m"),date("d")+1,date("Y"))-1) ?>"
+ }, function(start, end, label) {
+ start_date = start.format('YYYY-MM-DD');
+ end_date = end.format('YYYY-MM-DD');
+ });
- $('#daterangepicker').css("width","305");
- var start_date = "= date('Y-m-d H:i:s', mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>";
- var end_date = "= date('Y-m-d H:i:s', mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>";
- $('#daterangepicker').daterangepicker({
- "ranges": {
- "= lang('Datepicker.today') ?>": [
- "= date($config['dateformat'] . ' ' . $config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- ],
- "= lang('Datepicker.today_last_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d"),date("Y")-1)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y")-1)) ?>"
- ],
- "= lang('Datepicker.yesterday') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-1,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d")-1,date("Y"))) ?>"
- ],
- "= lang('Datepicker.last_7') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-6,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- ],
- "= lang('Datepicker.last_30') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-29,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- ],
- "= lang('Datepicker.this_month') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- ],
- "= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y")-1)) ?>"
- ],
- "= lang('Datepicker.same_month_last_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y")-1)) ?>"
- ],
- "= lang('Datepicker.last_month') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m")-1,1,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),0,date("Y"))) ?>"
- ],
- "= lang('Datepicker.this_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y"))) ?>"
- ],
- "= lang('Datepicker.last_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,date("Y")-1)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,12,31,date("Y")-1)) ?>"
- ],
- "= lang('Datepicker.this_financial_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,$config['financial_year'],1,date("Y"))) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y"))) ?>"
- ],
- "= lang('Datepicker.last_financial_year') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,$config['financial_year'],1,date("Y")-1)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,$config['financial_year'],0,date("Y"))) ?>"
- ],
- "= lang('Datepicker.all_time') ?>": [
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,2010)) ?>",
- "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- ],
- },
- "locale": {
- "format": '= dateformat_momentjs($config['dateformat'] . ' ' . $config['timeformat']) ?>',
- "separator": " - ",
- "applyLabel": "= lang('Datepicker.apply') ?>",
- "cancelLabel": "= lang('Datepicker.cancel') ?>",
- "fromLabel": "= lang('Datepicker.from') ?>",
- "toLabel": "= lang('Datepicker.to') ?>",
- "customRangeLabel": "= lang('Datepicker.custom') ?>",
- "daysOfWeek": [
- "= lang('Calendar.su') ?>",
- "= lang('Calendar.mo') ?>",
- "= lang('Calendar.tu') ?>",
- "= lang('Calendar.we') ?>",
- "= lang('Calendar.th') ?>",
- "= lang('Calendar.fr') ?>",
- "= lang('Calendar.sa') ?>"
- ],
- "monthNames": [
- "= lang('Calendar.january') ?>",
- "= lang('Calendar.february') ?>",
- "= lang('Calendar.march') ?>",
- "= lang('Calendar.april') ?>",
- "= lang('Calendar.may') ?>",
- "= lang('Calendar.june') ?>",
- "= lang('Calendar.july') ?>",
- "= lang('Calendar.august') ?>",
- "= lang('Calendar.september') ?>",
- "= lang('Calendar.october') ?>",
- "= lang('Calendar.november') ?>",
- "= lang('Calendar.december') ?>"
- ],
- "firstDay": = lang('Datepicker.weekstart') ?>
- },
- "timePicker": true,
- "timePickerSeconds": true,
- "alwaysShowCalendars": true,
- "startDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
- "endDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>",
- "minDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,01,01,2010)) ?>",
- "maxDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
- }, function(start, end, label) {
- start_date = start.format('YYYY-MM-DD HH:mm:ss');
- end_date = end.format('YYYY-MM-DD HH:mm:ss');
- });
+ $('#daterangepicker').css("width","305");
+ var start_date = "= date('Y-m-d H:i:s', mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>";
+ var end_date = "= date('Y-m-d H:i:s', mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>";
+ $('#daterangepicker').daterangepicker({
+ "ranges": {
+ "= lang('Datepicker.today') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['dateformat'], mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.today_last_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d"),date("Y")-1)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y")-1)) ?>"
+ ],
+ "= lang('Datepicker.yesterday') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-1,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d")-1,date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.last_7') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-6,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.last_30') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d")-29,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.this_month') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.same_month_to_same_day_last_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y")-1)) ?>"
+ ],
+ "= lang('Datepicker.same_month_last_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),1,date("Y")-1)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y")-1)) ?>"
+ ],
+ "= lang('Datepicker.last_month') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m")-1,1,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),0,date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.this_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.last_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,date("Y")-1)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,12,31,date("Y")-1)) ?>"
+ ],
+ "= lang('Datepicker.this_financial_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,$config['financial_year'],1,date("Y"))) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m")+1,0,date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.last_financial_year') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,$config['financial_year'],1,date("Y")-1)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,$config['financial_year'],0,date("Y"))) ?>"
+ ],
+ "= lang('Datepicker.all_time') ?>": [
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,1,1,2010)) ?>",
+ "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ ],
+ },
+ "locale": {
+ "format": '= dateformat_momentjs($config['dateformat'] . ' ' . $config['timeformat']) ?>',
+ "separator": " - ",
+ "applyLabel": "= lang('Datepicker.apply') ?>",
+ "cancelLabel": "= lang('Datepicker.cancel') ?>",
+ "fromLabel": "= lang('Datepicker.from') ?>",
+ "toLabel": "= lang('Datepicker.to') ?>",
+ "customRangeLabel": "= lang('Datepicker.custom') ?>",
+ "daysOfWeek": [
+ "= lang('Calendar.su') ?>",
+ "= lang('Calendar.mo') ?>",
+ "= lang('Calendar.tu') ?>",
+ "= lang('Calendar.we') ?>",
+ "= lang('Calendar.th') ?>",
+ "= lang('Calendar.fr') ?>",
+ "= lang('Calendar.sa') ?>"
+ ],
+ "monthNames": [
+ "= lang('Calendar.january') ?>",
+ "= lang('Calendar.february') ?>",
+ "= lang('Calendar.march') ?>",
+ "= lang('Calendar.april') ?>",
+ "= lang('Calendar.may') ?>",
+ "= lang('Calendar.june') ?>",
+ "= lang('Calendar.july') ?>",
+ "= lang('Calendar.august') ?>",
+ "= lang('Calendar.september') ?>",
+ "= lang('Calendar.october') ?>",
+ "= lang('Calendar.november') ?>",
+ "= lang('Calendar.december') ?>"
+ ],
+ "firstDay": = lang('Datepicker.weekstart') ?>
+ },
+ "timePicker": true,
+ "timePickerSeconds": true,
+ "alwaysShowCalendars": true,
+ "startDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,date("m"),date("d"),date("Y"))) ?>",
+ "endDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>",
+ "minDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(0,0,0,01,01,2010)) ?>",
+ "maxDate": "= date($config['dateformat'] . ' ' . $config['timeformat'],mktime(23,59,59,date("m"),date("d"),date("Y"))) ?>"
+ }, function(start, end, label) {
+ start_date = start.format('YYYY-MM-DD HH:mm:ss');
+ end_date = end.format('YYYY-MM-DD HH:mm:ss');
+ });
diff --git a/app/Views/partial/dinner_tables.php b/app/Views/partial/dinner_tables.php
index 6a367a66b..3dfadfd51 100644
--- a/app/Views/partial/dinner_tables.php
+++ b/app/Views/partial/dinner_tables.php
@@ -8,29 +8,29 @@ $i = 0;
foreach($dinner_tables as $table_key => $table)
{
- $dinner_table_id = $table['dinner_table_id'];
- $dinner_table_name = $table['name'];
- ++$i;
+ $dinner_table_id = $table['dinner_table_id'];
+ $dinner_table_name = $table['name'];
+ ++$i;
?>
-
diff --git a/app/Views/partial/footer.php b/app/Views/partial/footer.php
index d3d5a4697..5e2f79eea 100644
--- a/app/Views/partial/footer.php
+++ b/app/Views/partial/footer.php
@@ -4,14 +4,14 @@ use Config\OSPOS;
?>
-
+
-
-
+
+
diff --git a/app/Views/partial/header.php b/app/Views/partial/header.php
index 37c2883fd..c190d3d88 100644
--- a/app/Views/partial/header.php
+++ b/app/Views/partial/header.php
@@ -13,87 +13,87 @@ $request = Services::request();
-
-
- = esc($config['company']) . ' | ' . lang('Common.powered_by') . ' OSPOS ' . esc(config('App')->application_version) ?>
-
-
+
+
+ = esc($config['company']) . ' | ' . lang('Common.powered_by') . ' OSPOS ' . esc(config('App')->application_version) ?>
+
+
- getGet('debug') == 'true') : ?>
-
-
-
-
-
-
-
+ getGet('debug') == 'true') : ?>
+
+
+
+
+
+
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
- = view('partial/header_js') ?>
- = view('partial/lang_lines') ?>
+ = view('partial/header_js') ?>
+ = view('partial/lang_lines') ?>
-
+
-
-
-
-
-
= date($config['dateformat'] . ' ' . $config['timeformat']) ?>
-
+
+
+
+
+
= date($config['dateformat'] . ' ' . $config['timeformat']) ?>
+
-
- = anchor("home/changePassword/$user_info->person_id", "$user_info->first_name $user_info->last_name", ['class' => 'modal-dlg', 'data-btn-submit' => lang('Common.submit'), 'title' => lang('Employees.change_password')]) ?>
- |
- = anchor('home/logout', lang('Login.logout')) ?>
-
+
+ = anchor("home/changePassword/$user_info->person_id", "$user_info->first_name $user_info->last_name", ['class' => 'modal-dlg', 'data-btn-submit' => lang('Common.submit'), 'title' => lang('Employees.change_password')]) ?>
+ |
+ = anchor('home/logout', lang('Login.logout')) ?>
+
-
- = esc($config['company']) ?>
-
-
-
+
+ = esc($config['company']) ?>
+
+
+
-
-
-
+
+
diff --git a/app/Views/partial/header_js.php b/app/Views/partial/header_js.php
index 1e4f722bc..3121ab56b 100644
--- a/app/Views/partial/header_js.php
+++ b/app/Views/partial/header_js.php
@@ -4,76 +4,76 @@
*/
?>
diff --git a/app/Views/partial/print_receipt.php b/app/Views/partial/print_receipt.php
index 4011e4caa..bdeb0cbcb 100644
--- a/app/Views/partial/print_receipt.php
+++ b/app/Views/partial/print_receipt.php
@@ -8,81 +8,81 @@
diff --git a/app/Views/people/manage.php b/app/Views/people/manage.php
index f5f5f1d9c..9310bf4aa 100644
--- a/app/Views/people/manage.php
+++ b/app/Views/people/manage.php
@@ -10,62 +10,62 @@
-
-
-
-
+
+
+
+
= view('partial/footer') ?>
diff --git a/app/Views/receivings/form.php b/app/Views/receivings/form.php
index d28950859..e181fc08f 100644
--- a/app/Views/receivings/form.php
+++ b/app/Views/receivings/form.php
@@ -12,96 +12,96 @@
= form_open("receivings/save/".$receiving_info['receiving_id'], ['id' => 'receivings_edit_form', 'class' => 'form-horizontal']) ?>
-
-
- = form_label(lang('Receivings.receipt_number'), 'supplier', ['class' => 'control-label col-xs-3']) ?>
- = anchor('receivings/receipt/' . $receiving_info['receiving_id'], 'RECV ' . $receiving_info['receiving_id'], ['target' => '_blank', 'class' => 'control-label col-xs-8', "style" => "text-align:left"]) ?>
-
+
+
+ = form_label(lang('Receivings.receipt_number'), 'supplier', ['class' => 'control-label col-xs-3']) ?>
+ = anchor('receivings/receipt/' . $receiving_info['receiving_id'], 'RECV ' . $receiving_info['receiving_id'], ['target' => '_blank', 'class' => 'control-label col-xs-8', "style" => "text-align:left"]) ?>
+
-
+
-
+
-
+
-
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/receivings/receipt.php b/app/Views/receivings/receipt.php
index f631a5ed5..0b82d17fe 100644
--- a/app/Views/receivings/receipt.php
+++ b/app/Views/receivings/receipt.php
@@ -18,155 +18,155 @@
= view('partial/header') ?>
' . esc($error_message) . '
';
- exit;
- }
+ if (isset($error_message))
+ {
+ echo '
' . esc($error_message) . '
';
+ exit;
+ }
- echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'selected_printer' => 'receipt_printer']) ?>
+ echo view('partial/print_receipt', ['print_after_sale', $print_after_sale, 'selected_printer' => 'receipt_printer']) ?>
-
-
-
-
= lang('Suppliers.supplier') . esc(": $supplier") ?>
-
-
= lang('Receivings.id') . ": $receiving_id" ?>
-
-
= lang('Receivings.reference') . esc(": $reference") ?>
-
-
= lang('Employees.employee') . esc(": $employee") ?>
-
+
+
+
= lang('Suppliers.supplier') . esc(": $supplier") ?>
+
+
= lang('Receivings.id') . ": $receiving_id" ?>
+
+
= lang('Receivings.reference') . esc(": $reference") ?>
+
+
= lang('Employees.employee') . esc(": $employee") ?>
+
-
-
- | = lang('Items.item') ?> |
- = lang('Common.price') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Items.item') ?> |
+ = lang('Common.price') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.total') ?> |
+
- $item)
- {
- ?>
-
- | = esc($item['name'] . ' ' . $item['attribute_values']) ?> |
- = to_currency($item['price']) ?> |
- = to_quantity_decimals($item['quantity']) . ' ' . ($show_stock_locations ? ' [' . esc($item['stock_name']) . ']' : '') ?> x = $item['receiving_quantity'] != 0 ? to_quantity_decimals($item['receiving_quantity']) : 1 ?> |
- = to_currency($item['total']) ?> |
-
-
- | = esc($item['serialnumber']) ?> |
-
- 0 )
- {
- ?>
-
-
- | = to_currency($item['discount']) . ' ' . lang('Sales.discount') ?> |
-
- = to_decimals($item['discount']) . ' ' . lang('Sales.discount_included') ?> |
-
-
-
-
-
- | = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
-
-
- | = lang('Sales.payment') ?> |
- = esc($payment_type) ?> |
-
+ $item)
+ {
+ ?>
+
+ | = esc($item['name'] . ' ' . $item['attribute_values']) ?> |
+ = to_currency($item['price']) ?> |
+ = to_quantity_decimals($item['quantity']) . ' ' . ($show_stock_locations ? ' [' . esc($item['stock_name']) . ']' : '') ?> x = $item['receiving_quantity'] != 0 ? to_quantity_decimals($item['receiving_quantity']) : 1 ?> |
+ = to_currency($item['total']) ?> |
+
+
+ | = esc($item['serialnumber']) ?> |
+
+ 0 )
+ {
+ ?>
+
+
+ | = to_currency($item['discount']) . ' ' . lang('Sales.discount') ?> |
+
+ = to_decimals($item['discount']) . ' ' . lang('Sales.discount_included') ?> |
+
+
+
+
+
+ | = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
+
+
+ | = lang('Sales.payment') ?> |
+ = esc($payment_type) ?> |
+
-
-
- | = lang('Sales.amount_tendered') ?> |
- = to_currency($amount_tendered) ?> |
-
+
+
+ | = lang('Sales.amount_tendered') ?> |
+ = to_currency($amount_tendered) ?> |
+
-
- | = lang('Sales.change_due') ?> |
- = $amount_change ?> |
-
-
-
-
+
+ | = lang('Sales.change_due') ?> |
+ = $amount_change ?> |
+
+
+
+
-
- = nl2br(esc($config['return_policy'])) ?>
-
+
+ = nl2br(esc($config['return_policy'])) ?>
+
-
- = $barcode ?>
- = $receiving_id ?>
-
+
+ = $barcode ?>
+ = $receiving_id ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/receivings/receiving.php b/app/Views/receivings/receiving.php
index 1c1d82dad..95b4cdd01 100644
--- a/app/Views/receivings/receiving.php
+++ b/app/Views/receivings/receiving.php
@@ -22,17 +22,17 @@
' . esc($error) . '
';
+ echo '
' . esc($error) . '
';
}
if (!empty($warning))
{
- echo esc("
$warning
");
+ echo esc("
$warning
");
}
if (isset($success))
{
- echo esc("
$success
");
+ echo esc("
$success
");
}
?>
@@ -40,581 +40,581 @@ if (isset($success))
- = form_open("$controller_name/changeMode", ['id' => 'mode_form', 'class' => 'form-horizontal panel panel-default']) ?>
-
-
- -
-
-
- -
- = form_dropdown('mode', $modes, $mode, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
+ = form_open("$controller_name/changeMode", ['id' => 'mode_form', 'class' => 'form-horizontal panel panel-default']) ?>
+
+
+ -
+
+
+ -
+ = form_dropdown('mode', $modes, $mode, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
-
- -
-
-
- -
- = form_dropdown('stock_source', $stock_locations, $stock_source, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
+
+ -
+
+
+ -
+ = form_dropdown('stock_source', $stock_locations, $stock_source, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
-
- -
-
-
- -
- = form_dropdown('stock_destination', $stock_locations, $stock_destination, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
-
-
-
- = form_close() ?>
+
+ -
+
+
+ -
+ = form_dropdown('stock_destination', $stock_locations, $stock_destination, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
+
+
+
+ = form_close() ?>
- = form_open("$controller_name/add", ['id' => 'add_item_form', 'class' => 'form-horizontal panel panel-default']) ?>
-
-
- -
-
-
- -
- = form_input (['name' => 'item', 'id' => 'item', 'class' => 'form-control input-sm', 'size' => '50', 'tabindex' => '1']) ?>
-
- -
-
-
-
-
- = form_close() ?>
+ = form_open("$controller_name/add", ['id' => 'add_item_form', 'class' => 'form-horizontal panel panel-default']) ?>
+
+
+ -
+
+
+ -
+ = form_input (['name' => 'item', 'id' => 'item', 'class' => 'form-control input-sm', 'size' => '50', 'tabindex' => '1']) ?>
+
+ -
+
+
+
+
+ = form_close() ?>
-
-
-
- | = lang('Common.delete') ?> |
- = lang('Sales.item_number') ?> |
- = lang(ucfirst($controller_name) .'.item_name') ?> |
- = lang(ucfirst($controller_name) .'.cost') ?> |
- = lang(ucfirst($controller_name) .'.quantity') ?> |
- = lang(ucfirst($controller_name) .'.ship_pack') ?> |
- = lang(ucfirst($controller_name) .'.discount') ?> |
- = lang(ucfirst($controller_name) .'.total') ?> |
- = lang(ucfirst($controller_name) .'.update') ?> |
-
-
+
+
+
+ | = lang('Common.delete') ?> |
+ = lang('Sales.item_number') ?> |
+ = lang(ucfirst($controller_name) .'.item_name') ?> |
+ = lang(ucfirst($controller_name) .'.cost') ?> |
+ = lang(ucfirst($controller_name) .'.quantity') ?> |
+ = lang(ucfirst($controller_name) .'.ship_pack') ?> |
+ = lang(ucfirst($controller_name) .'.discount') ?> |
+ = lang(ucfirst($controller_name) .'.total') ?> |
+ = lang(ucfirst($controller_name) .'.update') ?> |
+
+
-
-
-
- |
- = lang('Sales.no_items_in_cart') ?>
- |
-
- $item)
- {
- ?>
- = form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
-
- | = anchor("$controller_name/deleteItem/$line", '') ?> |
- = esc($item['item_number']) ?> |
-
- = esc($item['name'] . ' '. implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']])) ?> = '[' . to_quantity_decimals($item['in_stock']) . ' in ' . $item['stock_name'] . ']' ?>
- = form_hidden('location', (string)$item['item_location']) ?>
- |
+
+
+
+ |
+ = lang('Sales.no_items_in_cart') ?>
+ |
+
+ $item)
+ {
+ ?>
+ = form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
+
+ | = anchor("$controller_name/deleteItem/$line", '') ?> |
+ = esc($item['item_number']) ?> |
+
+ = esc($item['name'] . ' '. implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']])) ?> = '[' . to_quantity_decimals($item['in_stock']) . ' in ' . $item['stock_name'] . ']' ?>
+ = form_hidden('location', (string)$item['item_location']) ?>
+ |
-
- = form_input ([
- 'name' => 'price',
- 'class' => 'form-control input-sm',
- 'value' => to_currency_no_money($item['price']),
- 'onClick' => 'this.select();'
- ]) ?> |
-
-
- = $item['price'] ?>
- = form_hidden('price', to_currency_no_money($item['price'])) ?>
- |
-
+
+ = form_input ([
+ 'name' => 'price',
+ 'class' => 'form-control input-sm',
+ 'value' => to_currency_no_money($item['price']),
+ 'onClick' => 'this.select();'
+ ]) ?> |
+
+
+ = $item['price'] ?>
+ = form_hidden('price', to_currency_no_money($item['price'])) ?>
+ |
+
- = form_input (['name' => 'quantity', 'class' => 'form-control input-sm', 'value' => to_quantity_decimals($item['quantity']),'onClick' => 'this.select();']) ?> |
- = form_dropdown(
- 'receiving_quantity',
- $item['receiving_quantity_choices'],
- $item['receiving_quantity'],
- ['class' => 'form-control input-sm']
- ) ?> |
+ = form_input (['name' => 'quantity', 'class' => 'form-control input-sm', 'value' => to_quantity_decimals($item['quantity']),'onClick' => 'this.select();']) ?> |
+ = form_dropdown(
+ 'receiving_quantity',
+ $item['receiving_quantity_choices'],
+ $item['receiving_quantity'],
+ ['class' => 'form-control input-sm']
+ ) ?> |
-
-
-
- = form_input (['name' => 'discount', 'class' => 'form-control input-sm', 'value' => $item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount']), 'onClick' => 'this.select();']) ?>
-
- = form_checkbox ([
- 'id' => 'discount_toggle',
- 'name' => 'discount_toggle',
- 'value' => 1,
- 'data-toggle' => "toggle",
- 'data-size' => 'small',
- 'data-onstyle' => 'success',
- 'data-on' => '' . $config['currency_symbol'] .'',
- 'data-off' => '%',
- 'data-line' => $line,
- 'checked' => $item['discount_type'] == 1
- ]) ?>
-
-
- |
-
- = $item['discount'] ?> |
- = form_hidden('discount', (string)$item['discount']) ?>
-
-
- = to_currency(($item['discount_type'] == PERCENT) ? $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['price'] * $item['quantity'] * $item['receiving_quantity'] * $item['discount'] / 100 : $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['discount']) ?> |
- ').submit();" title== lang(ucfirst($controller_name) .'.update') ?> > |
-
-
-
- | = lang('Sales.description_abbrv').':' ?> |
-
-
- 'description',
- 'class' => 'form-control input-sm',
- 'value' => $item['description']
- ]);
- }
- else
- {
- if ($item['description'] != '') //TODO: !==?
- {
- echo $item['description'];
- echo form_hidden('description', $item['description']);
- }
- else
- {
- echo ''.lang('Sales.no_description').'';
- echo form_hidden('description','');
- }
- }
- ?>
- |
- |
-
- = form_close() ?>
-
-
-
+
+
+
+ = form_input (['name' => 'discount', 'class' => 'form-control input-sm', 'value' => $item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount']), 'onClick' => 'this.select();']) ?>
+
+ = form_checkbox ([
+ 'id' => 'discount_toggle',
+ 'name' => 'discount_toggle',
+ 'value' => 1,
+ 'data-toggle' => "toggle",
+ 'data-size' => 'small',
+ 'data-onstyle' => 'success',
+ 'data-on' => '' . $config['currency_symbol'] .'',
+ 'data-off' => '%',
+ 'data-line' => $line,
+ 'checked' => $item['discount_type'] == 1
+ ]) ?>
+
+
+ |
+
+ = $item['discount'] ?> |
+ = form_hidden('discount', (string)$item['discount']) ?>
+
+
+ = to_currency(($item['discount_type'] == PERCENT) ? $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['price'] * $item['quantity'] * $item['receiving_quantity'] * $item['discount'] / 100 : $item['price']*$item['quantity']*$item['receiving_quantity'] - $item['discount']) ?> |
+ ').submit();" title== lang(ucfirst($controller_name) .'.update') ?> > |
+
+
+
+ | = lang('Sales.description_abbrv').':' ?> |
+
+
+ 'description',
+ 'class' => 'form-control input-sm',
+ 'value' => $item['description']
+ ]);
+ }
+ else
+ {
+ if ($item['description'] != '') //TODO: !==?
+ {
+ echo $item['description'];
+ echo form_hidden('description', $item['description']);
+ }
+ else
+ {
+ echo ''.lang('Sales.no_description').'';
+ echo form_hidden('description','');
+ }
+ }
+ ?>
+ |
+ |
+
+ = form_close() ?>
+
+
+
-
-
-
-
- | = lang(ucfirst($controller_name) .'.supplier') ?> |
- = esc($supplier) ?> |
-
-
-
- | = lang(ucfirst($controller_name) .'.supplier_email') ?> |
- = esc($supplier_email) ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.supplier_address') ?> |
- = esc($supplier_address) ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.supplier_location') ?> |
- = esc($supplier_location) ?> |
-
-
-
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.supplier') ?> |
+ = esc($supplier) ?> |
+
+
+
+ | = lang(ucfirst($controller_name) .'.supplier_email') ?> |
+ = esc($supplier_email) ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.supplier_address') ?> |
+ = esc($supplier_address) ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.supplier_location') ?> |
+ = esc($supplier_location) ?> |
+
+
+
- = anchor(
- "$controller_name/removeSupplier",
- '
 ' . lang('Common.remove').' '.lang('Suppliers.supplier'),
- [
- 'class' => 'btn btn-danger btn-sm',
- 'id' => 'remove_supplier_button',
- 'title'=>lang('Common.remove').' '.lang('Suppliers.supplier')
- ]) ?>
-
- = form_open("$controller_name/selectSupplier", ['id' => 'select_supplier_form', 'class' => 'form-horizontal']) ?>
-
+ = form_close() ?>
+
-
-
-
- | = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
- |
- |
-
-
-
+
+
+
+ | = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
+ |
+ |
+
+
+
- 0)
- {
- ?>
-
-
- = form_open("$controller_name/requisitionComplete", ['id' => 'finish_receiving_form', 'class' => 'form-horizontal']) ?>
-
+
 = lang(ucfirst($controller_name) .'.complete_receiving') ?>
+
+ = form_close() ?>
+
+
+
+
@@ -16,92 +16,92 @@
' . esc($error) . '
';
+ echo '
' . esc($error) . '
';
}
?>
= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
+
-
-
-
+
+
+
-
-
-
+
+
+
- 2)
- {
- ?>
-
-
+ 2)
+ {
+ ?>
+
+
- 'generate_report',
- 'id' => 'generate_report',
- 'content'=>lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm']
- ); ?>
+ 'generate_report',
+ 'id' => 'generate_report',
+ 'content'=>lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm']
+ ); ?>
= form_close() ?>
= view('partial/footer') ?>
@@ -109,11 +109,11 @@ if(isset($error))
diff --git a/app/Views/reports/graphical.php b/app/Views/reports/graphical.php
index 48ec6777d..da78b4c43 100644
--- a/app/Views/reports/graphical.php
+++ b/app/Views/reports/graphical.php
@@ -9,7 +9,7 @@
= view('partial/header') ?>
= esc($title) ?>
@@ -21,14 +21,14 @@
= view($chart_type) ?>
- $value)
- {
- ?>
-
= lang("Reports.$name"). ': ' . to_currency($value) ?>
-
+ $value)
+ {
+ ?>
+
= lang("Reports.$name"). ': ' . to_currency($value) ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/reports/graphs/bar.php b/app/Views/reports/graphs/bar.php
index 8a7dbf4a9..5e0d4305a 100644
--- a/app/Views/reports/graphs/bar.php
+++ b/app/Views/reports/graphs/bar.php
@@ -9,115 +9,115 @@
*/
?>
diff --git a/app/Views/reports/graphs/hbar.php b/app/Views/reports/graphs/hbar.php
index d85ef3972..5d3f916cc 100644
--- a/app/Views/reports/graphs/hbar.php
+++ b/app/Views/reports/graphs/hbar.php
@@ -9,118 +9,118 @@
*/
?>
diff --git a/app/Views/reports/graphs/line.php b/app/Views/reports/graphs/line.php
index a5f553a7d..e462c005b 100644
--- a/app/Views/reports/graphs/line.php
+++ b/app/Views/reports/graphs/line.php
@@ -9,201 +9,201 @@
*/
?>
diff --git a/app/Views/reports/graphs/pie.php b/app/Views/reports/graphs/pie.php
index 29dd45976..31bd0a7b1 100644
--- a/app/Views/reports/graphs/pie.php
+++ b/app/Views/reports/graphs/pie.php
@@ -7,84 +7,84 @@
*/
?>
diff --git a/app/Views/reports/inventory_summary_input.php b/app/Views/reports/inventory_summary_input.php
index cfe0543dc..bc172f314 100644
--- a/app/Views/reports/inventory_summary_input.php
+++ b/app/Views/reports/inventory_summary_input.php
@@ -7,7 +7,7 @@
= view('partial/header') ?>
@@ -16,33 +16,33 @@
' . esc($error) . '
';
+ echo '
' . esc($error) . '
';
}
?>
= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
+
-
+
- 'generate_report',
- 'id' => 'generate_report',
- 'content' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm'
- ]) ?>
+ 'generate_report',
+ 'id' => 'generate_report',
+ 'content' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm'
+ ]) ?>
= form_close() ?>
= view('partial/footer') ?>
@@ -50,9 +50,9 @@ if(isset($error))
diff --git a/app/Views/reports/listing.php b/app/Views/reports/listing.php
index 46d74b7d4..f0f90d5bd 100644
--- a/app/Views/reports/listing.php
+++ b/app/Views/reports/listing.php
@@ -5,111 +5,111 @@
* @var array $grants
*/
$detailed_reports = [
- 'reports_sales' => 'detailed',
- 'reports_receivings' => 'detailed',
- 'reports_customers' => 'specific',
- 'reports_discounts' => 'specific',
- 'reports_employees' => 'specific',
- 'reports_suppliers' => 'specific',
+ 'reports_sales' => 'detailed',
+ 'reports_receivings' => 'detailed',
+ 'reports_customers' => 'specific',
+ 'reports_discounts' => 'specific',
+ 'reports_employees' => 'specific',
+ 'reports_suppliers' => 'specific',
];
?>
= view('partial/header') ?>
' . esc($error) . '
';
- }
+ if (isset($error))
+ {
+ echo '' . esc($error) . '
';
+ }
?>
-
-
-
-
 = lang('Reports.graphical_reports') ?>
-
-
-
-
+
+
+
+
 = lang('Reports.graphical_reports') ?>
+
+
+
+
-
-
-
-
 = lang('Reports.summary_reports') ?>
-
-
-
-
+
+
+
+
 = lang('Reports.summary_reports') ?>
+
+
+
+
-
-
-
-
 = lang('Reports.detailed_reports') ?>
-
-
- $prefix)
- {
- if (in_array($report_name, $permission_ids, true))
- {
- $link = get_report_link($report_name, $prefix);
- ?>
-
= $link['label'] ?>
-
-
-
+
+
+
+
 = lang('Reports.detailed_reports') ?>
+
+
+ $prefix)
+ {
+ if (in_array($report_name, $permission_ids, true))
+ {
+ $link = get_report_link($report_name, $prefix);
+ ?>
+
= $link['label'] ?>
+
+
+
-
-
-
-
 = lang('Reports.inventory_reports') ?>
-
-
-
-
-
+
+
+
+
 = lang('Reports.inventory_reports') ?>
+
+
+
+
+
= view('partial/footer') ?>
diff --git a/app/Views/reports/specific_customer_input.php b/app/Views/reports/specific_customer_input.php
index 0de199ea6..10ec77445 100644
--- a/app/Views/reports/specific_customer_input.php
+++ b/app/Views/reports/specific_customer_input.php
@@ -9,7 +9,7 @@
= view('partial/header') ?>
@@ -18,46 +18,46 @@
' . esc($error) . '';
+ echo '' . esc($error) . '
';
}
?>
= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
+
-
+
-
+
-
+
- 'generate_report',
- 'id' => 'generate_report',
- 'content' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm'
- ]); ?>
+ 'generate_report',
+ 'id' => 'generate_report',
+ 'content' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm'
+ ]); ?>
= form_close() ?>
= view('partial/footer') ?>
@@ -65,12 +65,12 @@ if(isset($error))
diff --git a/app/Views/reports/specific_input.php b/app/Views/reports/specific_input.php
index f380cea9f..0662b94e2 100644
--- a/app/Views/reports/specific_input.php
+++ b/app/Views/reports/specific_input.php
@@ -9,7 +9,7 @@
= view('partial/header') ?>
@@ -18,70 +18,70 @@
' . esc($error) . '';
+ echo '' . esc($error) . '
';
}
?>
= form_open('#', ['id' => 'item_form', 'enctype' => 'multipart/form-data', 'class' => 'form-horizontal']) ?>
-
+
-
-
-
+
+
+
-
-
+
- 'generate_report',
- 'id' => 'generate_report',
- 'content'=>lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm'
- ]) ?>
+ 'generate_report',
+ 'id' => 'generate_report',
+ 'content'=>lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm'
+ ]) ?>
= form_close() ?>
= view('partial/footer') ?>
@@ -89,38 +89,38 @@ if(isset($error))
diff --git a/app/Views/reports/tabular.php b/app/Views/reports/tabular.php
index 3a9880686..a42571554 100644
--- a/app/Views/reports/tabular.php
+++ b/app/Views/reports/tabular.php
@@ -11,7 +11,7 @@
= view('partial/header') ?>
= esc($title) ?>
@@ -19,54 +19,54 @@
= esc($subtitle) ?>
- $value)
- {
- if($name == "total_quantity")
- {
- ?>
-
= lang("Reports.$name") . ": $value" ?>
-
-
= lang("Reports.$name") . ': ' . to_currency($value) ?>
-
+ $value)
+ {
+ if($name == "total_quantity")
+ {
+ ?>
+
= lang("Reports.$name") . ": $value" ?>
+
+
= lang("Reports.$name") . ': ' . to_currency($value) ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/reports/tabular_details.php b/app/Views/reports/tabular_details.php
index 50de02269..e71033c63 100644
--- a/app/Views/reports/tabular_details.php
+++ b/app/Views/reports/tabular_details.php
@@ -16,92 +16,92 @@
= esc($subtitle) ?>
- $value)
- {
- ?>
-
= lang("Reports.$name") . ': ' . to_currency($value) ?>
-
+ $value)
+ {
+ ?>
+
= lang("Reports.$name") . ': ' . to_currency($value) ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/sales/form.php b/app/Views/sales/form.php
index 65fd24eb1..87fa14b8e 100644
--- a/app/Views/sales/form.php
+++ b/app/Views/sales/form.php
@@ -21,246 +21,246 @@
= form_open('sales/save/' . $sale_info['sale_id'], ['id' => 'sales_edit_form', 'class' => 'form-horizontal']) ?>
-
-
- = form_label(lang('Sales.receipt_number'), 'receipt_number', ['class' => 'control-label col-xs-3']) ?>
- = anchor('sales/receipt/' . $sale_info['sale_id'], 'POS ' . $sale_info['sale_id'], ['target' => '_blank', 'class' => 'control-label col-xs-8', "style"=>"text-align:left"]) ?>
-
+
+
+ = form_label(lang('Sales.receipt_number'), 'receipt_number', ['class' => 'control-label col-xs-3']) ?>
+ = anchor('sales/receipt/' . $sale_info['sale_id'], 'POS ' . $sale_info['sale_id'], ['target' => '_blank', 'class' => 'control-label col-xs-8', "style"=>"text-align:left"]) ?>
+
-
+
-
-
-
+
+
+
-
-
-
+
+
+
-
-
+
+
-
-
+
+
-
+
-
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/sales/help.php b/app/Views/sales/help.php
index daebaeb9c..93ac1f043 100644
--- a/app/Views/sales/help.php
+++ b/app/Views/sales/help.php
@@ -1,97 +1,97 @@
-
-
-
-
-
-
- | = lang('Sales.key_help'); ?> |
- = lang('Sales.key_function'); ?> |
-
-
-
-
- ESC |
- = lang('Sales.key_cancel'); ?> |
-
-
- ALT + 1 |
- = lang('Sales.key_item_search'); ?> |
-
-
- ALT + 2 |
- = lang('Sales.key_customer_search'); ?> |
-
-
- ALT + 3 |
- = lang('Sales.key_suspend'); ?> |
-
-
- ALT + 4 |
- = lang('Sales.key_suspended'); ?> |
-
-
- ALT + 5 |
- = lang('Sales.key_tendered'); ?> |
-
-
- ALT + 6 |
- = lang('Sales.key_payment'); ?> |
-
-
- ALT + 7 |
- = lang('Sales.key_finish_sale'); ?> |
-
-
- ALT + 8 |
- = lang('Sales.key_finish_quote'); ?> |
-
-
- ALT + 9 |
- = lang('Sales.key_help_modal'); ?> |
-
-
-
-
+
+
+
+
+
+
+ | = lang('Sales.key_help'); ?> |
+ = lang('Sales.key_function'); ?> |
+
+
+
+
+ ESC |
+ = lang('Sales.key_cancel'); ?> |
+
+
+ ALT + 1 |
+ = lang('Sales.key_item_search'); ?> |
+
+
+ ALT + 2 |
+ = lang('Sales.key_customer_search'); ?> |
+
+
+ ALT + 3 |
+ = lang('Sales.key_suspend'); ?> |
+
+
+ ALT + 4 |
+ = lang('Sales.key_suspended'); ?> |
+
+
+ ALT + 5 |
+ = lang('Sales.key_tendered'); ?> |
+
+
+ ALT + 6 |
+ = lang('Sales.key_payment'); ?> |
+
+
+ ALT + 7 |
+ = lang('Sales.key_finish_sale'); ?> |
+
+
+ ALT + 8 |
+ = lang('Sales.key_finish_quote'); ?> |
+
+
+ ALT + 9 |
+ = lang('Sales.key_help_modal'); ?> |
+
+
+
+
-
-
-
-
- | = lang('Sales.key_help'); ?> |
- = lang('Sales.key_function'); ?> |
-
-
-
-
- F11 |
- = lang('Sales.key_full'); ?> |
-
-
- CTRL + |
- = lang('Sales.key_in'); ?> |
-
-
- CTRL - |
- = lang('Sales.key_out'); ?> |
-
-
- CTRL + 0 |
- = lang('Sales.key_restore'); ?> |
-
-
- CTRL + P |
- = lang('Sales.key_print'); ?> |
-
-
- CTRL + F |
- = lang('Sales.key_search'); ?> |
-
-
-
-
-
+
+
+
+
+ | = lang('Sales.key_help'); ?> |
+ = lang('Sales.key_function'); ?> |
+
+
+
+
+ F11 |
+ = lang('Sales.key_full'); ?> |
+
+
+ CTRL + |
+ = lang('Sales.key_in'); ?> |
+
+
+ CTRL - |
+ = lang('Sales.key_out'); ?> |
+
+
+ CTRL + 0 |
+ = lang('Sales.key_restore'); ?> |
+
+
+ CTRL + P |
+ = lang('Sales.key_print'); ?> |
+
+
+ CTRL + F |
+ = lang('Sales.key_search'); ?> |
+
+
+
+
+
diff --git a/app/Views/sales/invoice.php b/app/Views/sales/invoice.php
index d08c21f42..4f702049a 100644
--- a/app/Views/sales/invoice.php
+++ b/app/Views/sales/invoice.php
@@ -24,8 +24,8 @@
$error_message";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
@@ -33,21 +33,21 @@ if(isset($error_message))
@@ -55,244 +55,244 @@ $(document).ready(function()
= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'invoice_printer']) ?>
-
-
-
-
-
= nl2br(esc($customer_info)) ?>
-
-
+
+
+
+
+
= nl2br(esc($customer_info)) ?>
+
+
-
-
-
 ?>)
-
-
 
-
-
= $config['company'] ?>
-
-
-
+
+
+
 ?>)
+
+
 
+
+
= $config['company'] ?>
+
+
+
-
-
= nl2br(esc($company_info)) ?>
-
-
+
+
= nl2br(esc($company_info)) ?>
+
+
-
-
- | = lang('Sales.item_number') ?> |
-
- = lang('Sales.hsn') ?> |
-
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- 0)
- {
- $invoice_columns += 1;
- ?>
- = lang('Sales.customer_discount') ?> |
-
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+
+ = lang('Sales.hsn') ?> |
+
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ 0)
+ {
+ $invoice_columns += 1;
+ ?>
+ = lang('Sales.customer_discount') ?> |
+
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc($item['item_number']) ?> |
-
- = esc($item['hsn_code']) ?> |
-
- = ($item['is_serialized'] || $item['allow_alt_description']) && !empty($item['description']) ? $item['description'] : $item['name'] . ' ' . $item['attribute_values'] ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- 0): ?>
- = to_currency($item['discounted_total'] / $item['quantity']) ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
-
- |
- = $item['serialnumber'] //TODO: serialnumber does not match variable naming conventions for this project. ?> |
-
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc($item['item_number']) ?> |
+
+ = esc($item['hsn_code']) ?> |
+
+ = ($item['is_serialized'] || $item['allow_alt_description']) && !empty($item['description']) ? $item['description'] : $item['name'] . ' ' . $item['attribute_values'] ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ 0): ?>
+ = to_currency($item['discounted_total'] / $item['quantity']) ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
+
+ |
+ = $item['serialnumber'] //TODO: serialnumber does not match variable naming conventions for this project. ?> |
+
+
-
- | = ' ' ?> |
-
+
+ | = ' ' ?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not meet variable naming standards for this project.
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | |
- = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] * -1 ) ?> |
-
- $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not meet variable naming standards for this project.
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | |
+ = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] * -1 ) ?> |
+
+
-
- | |
- = lang('Sales.giftcard_balance') ?> |
- = to_currency($cur_giftcard_value) ?> |
-
-
+
+ | |
+ = lang('Sales.giftcard_balance') ?> |
+ = to_currency($cur_giftcard_value) ?> |
+
+
-
- | |
- = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
-
+ if(!empty($payments))
+ {
+ ?>
+
+ | |
+ = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
+
-
+
-
-
-
- = nl2br(esc($config['payment_message'])) ?>
- = empty($comments) ? esc($config['invoice_default_comments']) : lang('Sales.comments') . ': ' . esc($comments) ?>
-
-
= nl2br(esc($config['return_policy'])) ?>
-
-
- = $barcode ?>
- = $sale_id ?>
-
-
+
+
+
+ = nl2br(esc($config['payment_message'])) ?>
+ = empty($comments) ? esc($config['invoice_default_comments']) : lang('Sales.comments') . ': ' . esc($comments) ?>
+
+
= nl2br(esc($config['return_policy'])) ?>
+
+
+ = $barcode ?>
+ = $sale_id ?>
+
+
diff --git a/app/Views/sales/invoice_email.php b/app/Views/sales/invoice_email.php
index cd4d16301..e1db4f7b7 100644
--- a/app/Views/sales/invoice_email.php
+++ b/app/Views/sales/invoice_email.php
@@ -20,9 +20,9 @@
?>
-
-
- = lang('Sales.email_receipt') ?>
+
+
+ = lang('Sales.email_receipt') ?>
@@ -30,187 +30,187 @@
$error_message";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
-
-
-
-
-
-
-
- |
- |
-
-
-
- = esc($config['company']) ?>
- = nl2br(esc($company_info)) ?>
- |
-
-
-
- | = lang('Sales.invoice_number') ?> |
- = esc($invoice_number) ?> |
-
-
- | = lang('Common.date') ?> |
- = esc($transaction_date) ?> |
-
- 0)
- {
- ?>
-
- | = lang('Sales.amount_due') ?> |
- = to_currency($total) ?> |
-
-
-
- |
-
-
+
+
+
+
+
+
+
+ |
+ |
+
+
+
+ = esc($config['company']) ?>
+ = nl2br(esc($company_info)) ?>
+ |
+
+
+
+ | = lang('Sales.invoice_number') ?> |
+ = esc($invoice_number) ?> |
+
+
+ | = lang('Common.date') ?> |
+ = esc($transaction_date) ?> |
+
+ 0)
+ {
+ ?>
+
+ | = lang('Sales.amount_due') ?> |
+ = to_currency($total) ?> |
+
+
+
+ |
+
+
-
-
- | = lang('Sales.item_number') ?> |
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- 0)
- {
- $invoice_columns = $invoice_columns + 1;
- ?>
- = lang('Sales.customer_discount') ?> |
-
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ 0)
+ {
+ $invoice_columns = $invoice_columns + 1;
+ ?>
+ = lang('Sales.customer_discount') ?> |
+
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = $item['item_number'] ?> |
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- 0): ?>
- = to_currency($item['discounted_total'] / $item['quantity']) ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = $item['item_number'] ?> |
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ 0): ?>
+ = to_currency($item['discounted_total'] / $item['quantity']) ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
-
- | = ' ' ?> |
-
+
+ | = ' ' ?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not meet the variable naming conventions for this project
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | |
- = $splitpayment[0] ?> |
- = to_currency(-$payment['payment_amount']) ?> |
-
-
+ foreach($payments as $payment_id=>$payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not meet the variable naming conventions for this project
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | |
+ = $splitpayment[0] ?> |
+ = to_currency(-$payment['payment_amount']) ?> |
+
+
-
-
- | |
- = lang('Sales.giftcard_balance') ?> |
- = to_currency($cur_giftcard_value) ?> |
-
-
+
+
+ | |
+ = lang('Sales.giftcard_balance') ?> |
+ = to_currency($cur_giftcard_value) ?> |
+
+
-
-
- | |
- = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
-
-
+
+
+ | |
+ = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
+
+
-
-
-
- = nl2br($config['payment_message']) ?>
- = lang('Sales.comments') . ': ' . (empty($comments) ? $config['invoice_default_comments'] : $comments) ?>
-
- = nl2br($config['return_policy']) ?>
-
-
-
![<?='$sale_id'?]()
src='data:image/svg+xml;base64,= base64_encode($barcode) ?>' />
- = $sale_id ?>
-
-
+
+
+
+ = nl2br($config['payment_message']) ?>
+ = lang('Sales.comments') . ': ' . (empty($comments) ? $config['invoice_default_comments'] : $comments) ?>
+
+ = nl2br($config['return_policy']) ?>
+
+
+
![<?='$sale_id'?]()
src='data:image/svg+xml;base64,= base64_encode($barcode) ?>' />
+ = $sale_id ?>
+
+
diff --git a/app/Views/sales/manage.php b/app/Views/sales/manage.php
index 690b07cec..fe8336a80 100644
--- a/app/Views/sales/manage.php
+++ b/app/Views/sales/manage.php
@@ -12,75 +12,75 @@
= view('partial/print_receipt', ['print_after_sale'=>false, 'selected_printer' => 'takings_printer']) ?>
-
- = anchor("sales", ' ' . lang('Sales.register'), ['class' => 'btn btn-info btn-sm pull-right', 'id' => 'show_sales_button']) ?>
+
+ = anchor("sales", ' ' . lang('Sales.register'), ['class' => 'btn btn-info btn-sm pull-right', 'id' => 'show_sales_button']) ?>
diff --git a/app/Views/sales/quote.php b/app/Views/sales/quote.php
index 6bfebf95c..639b13275 100644
--- a/app/Views/sales/quote.php
+++ b/app/Views/sales/quote.php
@@ -20,237 +20,237 @@
$error_message
";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
-
+
+ send_email();
+
+ });
+
= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'invoice_printer']) ?>
-
-
-
-
-
= nl2br(esc($customer_info)) ?>
-
-
+
+
+
+
+
= nl2br(esc($customer_info)) ?>
+
+
-
-
-
) ?>)
-
-
 
-
-
= esc($config['company']) ?>
-
-
-
+
+
+
) ?>)
+
+
 
+
+
= esc($config['company']) ?>
+
+
+
-
-
= nl2br(esc($company_info)) ?>
-
-
+
+
= nl2br(esc($company_info)) ?>
+
+
-
-
- | = lang('Sales.item_number') ?> |
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- 0)
- {
- $quote_columns = $quote_columns + 1;
- ?>
- = lang('Sales.customer_discount') ?> |
-
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ 0)
+ {
+ $quote_columns = $quote_columns + 1;
+ ?>
+ = lang('Sales.customer_discount') ?> |
+
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc($item['item_number']) ?> |
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- 0): ?>
- = to_currency($item['discounted_total'] / $item['quantity']) ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc($item['item_number']) ?> |
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ 0): ?>
+ = to_currency($item['discounted_total'] / $item['quantity']) ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
-
-
- |
- = esc($item['serialnumber']) //TODO: the variable serialnumber does not meet naming conventions for this project?> |
-
-
+
+
+ |
+ = esc($item['serialnumber']) //TODO: the variable serialnumber does not meet naming conventions for this project?> |
+
+
-
- | = ' ' //TODO: align is deprecated. Also should replace the php echo for nbsp with simple html?> |
-
+
+ | = ' ' //TODO: align is deprecated. Also should replace the php echo for nbsp with simple html?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']);
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | |
- = $splitpayment[0] ?> |
- = to_currency($payment['payment_amount']) ?> |
-
-
-
-
-
-
- = empty($comments) ? '' : lang('Sales.comments') . ': ' . esc($comments) ?>
- = esc($config['quote_default_comments']) ?>
-
-
-
+ foreach($payments as $payment_id => $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']);
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | |
+ = $splitpayment[0] ?> |
+ = to_currency($payment['payment_amount']) ?> |
+
+
+
+
+
+
+ = empty($comments) ? '' : lang('Sales.comments') . ': ' . esc($comments) ?>
+ = esc($config['quote_default_comments']) ?>
+
+
+
= view('partial/footer') ?>
diff --git a/app/Views/sales/quote_email.php b/app/Views/sales/quote_email.php
index 18e700463..0dee59ace 100644
--- a/app/Views/sales/quote_email.php
+++ b/app/Views/sales/quote_email.php
@@ -16,154 +16,154 @@
-
-
- = lang('Sales.send_quote') ?>
+
+
+ = lang('Sales.send_quote') ?>
$error_message";
- exit;
- }
+ if(isset($error_message))
+ {
+ echo "$error_message
";
+ exit;
+ }
?>
-
-
-
-
-
-
-
- |
-
-
- |
-
-
- |
-
- = esc($config['company']) ?>
- = nl2br(esc($company_info)) ?>
-
- |
-
-
-
- | = lang('Sales.quote_number') ?> |
- = esc($quote_number) ?> |
-
-
- | = lang('Common.date') ?> |
- = $transaction_date ?> |
-
- 0)
- {
- ?>
-
- | = lang('Sales.amount_due') ?> |
- = to_currency($total) ?> |
-
-
-
- |
-
-
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+ |
+
+ = esc($config['company']) ?>
+ = nl2br(esc($company_info)) ?>
+
+ |
+
+
+
+ | = lang('Sales.quote_number') ?> |
+ = esc($quote_number) ?> |
+
+
+ | = lang('Common.date') ?> |
+ = $transaction_date ?> |
+
+ 0)
+ {
+ ?>
+
+ | = lang('Sales.amount_due') ?> |
+ = to_currency($total) ?> |
+
+
+
+ |
+
+
-
-
- | = lang('Sales.item_number') ?> |
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- 0)
- {
- $quote_columns = $quote_columns + 1;
- ?>
- = lang('Sales.customer_discount') ?> |
-
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ 0)
+ {
+ $quote_columns = $quote_columns + 1;
+ ?>
+ = lang('Sales.customer_discount') ?> |
+
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc($item['item_number']) ?> |
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- 0): ?>
- = to_currency($item['discounted_total'] / $item['quantity']) ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc($item['item_number']) ?> |
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ 0): ?>
+ = to_currency($item['discounted_total'] / $item['quantity']) ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
-
- | = ' ' //TODO: Replace the php echo for nbsp with just straight html? ?> |
-
+
+ | = ' ' //TODO: Replace the php echo for nbsp with just straight html? ?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
+
-
-
-
- = nl2br(esc($config['payment_message'])) ?>
- = lang('Sales.comments') . ': ' . (empty($comments) ? $config['quote_default_comments'] : esc($comments)) ?>
-
- = nl2br(esc($config['return_policy'])) ?>
-
-
- = $quote_number ?>
-
-
+
+
+
+ = nl2br(esc($config['payment_message'])) ?>
+ = lang('Sales.comments') . ': ' . (empty($comments) ? $config['quote_default_comments'] : esc($comments)) ?>
+
+ = nl2br(esc($config['return_policy'])) ?>
+
+
+ = $quote_number ?>
+
+
diff --git a/app/Views/sales/receipt.php b/app/Views/sales/receipt.php
index 766be995f..896b45e6e 100644
--- a/app/Views/sales/receipt.php
+++ b/app/Views/sales/receipt.php
@@ -13,47 +13,47 @@ use App\Models\Employee;
$error_message";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
-
+
+ send_email();
+
+ });
+
= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'receipt_printer']) ?>
= view('sales/' . $config['receipt_template']) ?>
diff --git a/app/Views/sales/receipt_default.php b/app/Views/sales/receipt_default.php
index 7b616906c..aaa6c8416 100644
--- a/app/Views/sales/receipt_default.php
+++ b/app/Views/sales/receipt_default.php
@@ -18,232 +18,232 @@
?>
-
-
-
-
= lang('Customers.customer') . esc(": $customer") ?>
-
+
+
+
= lang('Customers.customer') . esc(": $customer") ?>
+
-
= lang('Sales.id') . esc(": $sale_id") ?>
+
= lang('Sales.id') . esc(": $sale_id") ?>
-
-
= lang('Sales.invoice_number') . esc(": $invoice_number") ?>
-
+
+
= lang('Sales.invoice_number') . esc(": $invoice_number") ?>
+
-
= lang('Employees.employee') . esc(": $employee") ?>
-
+
= lang('Employees.employee') . esc(": $employee") ?>
+
-
-
- | = lang('Sales.description_abbrv') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.total') ?> |
-
- |
-
-
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
- = to_currency($item['price']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
-
- = $item['taxed_flag'] ?> |
-
-
-
-
- | = esc($item['description']) ?> |
-
+
+ | = lang('Sales.description_abbrv') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.total') ?> |
+
+ |
+
+
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
+ = to_currency($item['price']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
+
+ = $item['taxed_flag'] ?> |
+
+
+
+
+ | = esc($item['description']) ?> |
+
- = esc($item['serialnumber']) ?> |
-
-
- 0)
- {
- ?>
-
-
- | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
-
- = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
+ if($config['receipt_show_serialnumber'])
+ {
+ ?>
+ = esc($item['serialnumber']) ?> |
+
+
+ 0)
+ {
+ ?>
+
+
+ | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
+
+ = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
- 0)
- {
- ?>
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($prediscount_subtotal) ?> |
-
-
- | = lang('Sales.customer_discount') ?>: |
- = to_currency($discount * -1) ?> |
-
-
+ 0)
+ {
+ ?>
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($prediscount_subtotal) ?> |
+
+
+ | = lang('Sales.customer_discount') ?>: |
+ = to_currency($discount * -1) ?> |
+
+
-
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
- $tax)
- {
- ?>
-
- | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
-
+
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+ $tax)
+ {
+ ?>
+
+ | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
+
-
-
+
+
- 0)); ?>
-
- | = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+ 0)); ?>
+
+ | = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
-
- | |
-
+
+ | |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']); //TODO: The variable splitpayment does not follow naming conventions for this project
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] * -1 ) ?> |
-
-
+ $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']); //TODO: The variable splitpayment does not follow naming conventions for this project
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] * -1 ) ?> |
+
+
-
- | |
-
+
+ | |
+
-
-
- | = lang('Sales.giftcard_balance') ?> |
- = to_currency($cur_giftcard_value) ?> |
-
-
-
- | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
-
+
+
+ | = lang('Sales.giftcard_balance') ?> |
+ = to_currency($cur_giftcard_value) ?> |
+
+
+
+ | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
+
-
- = nl2br($config['return_policy']) ?>
-
+
+ = nl2br($config['return_policy']) ?>
+
-
- = $barcode ?>
- = $sale_id ?>
-
+
+ = $barcode ?>
+ = $sale_id ?>
+
diff --git a/app/Views/sales/receipt_email.php b/app/Views/sales/receipt_email.php
index 2a1eafd43..5d706ac26 100644
--- a/app/Views/sales/receipt_email.php
+++ b/app/Views/sales/receipt_email.php
@@ -15,207 +15,207 @@
*/
?>
-
-
+
-
-
-
= lang('Customers.customer') . esc(": $customer") ?>
-
+
+
+
= lang('Customers.customer') . esc(": $customer") ?>
+
-
= lang('Sales.id') . esc(": $sale_id") ?>
-
= lang('Employees.employee') . esc(": $employee") ?>
-
+
= lang('Sales.id') . esc(": $sale_id") ?>
+
= lang('Employees.employee') . esc(": $employee") ?>
+
-
+
-
-
- | = lang('Sales.description_abbrv') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.total') ?> |
-
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
- = to_currency($item['price']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
-
-
-
- | = esc($item['description']) ?> |
-
+
+ | = lang('Sales.description_abbrv') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.total') ?> |
+
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
+ = to_currency($item['price']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
+
+
+
+ | = esc($item['description']) ?> |
+
- = esc($item['serialnumber']) ?> |
-
-
- 0)
- {
- ?>
-
-
- | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
-
- = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
+ = esc($item['serialnumber']) ?> |
+
+
+ 0)
+ {
+ ?>
+
+
+ | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
+
+ = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+ 0)
- {
- ?>
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
-
- | = lang('Sales.discount') ?>: |
- = to_currency($discount*-1) ?> |
-
-
+ if($config['receipt_show_total_discount'] && $discount > 0)
+ {
+ ?>
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+
+ | = lang('Sales.discount') ?>: |
+ = to_currency($discount*-1) ?> |
+
+
-
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
- $tax)
- {
- ?>
-
- | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
-
+
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+ $tax)
+ {
+ ?>
+
+ | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
+
-
-
+
+
- 0)) ?>
-
- | = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+ 0)) ?>
+
+ | = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']);
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] * -1 ) ?> |
-
-
-
-
-
- | = lang('Sales.giftcard_balance') ?> |
- = to_currency($cur_giftcard_value) ?> |
-
-
-
- | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
+ $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']);
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] * -1 ) ?> |
+
+
-
- | |
-
-
+
+
+ | = lang('Sales.giftcard_balance') ?> |
+ = to_currency($cur_giftcard_value) ?> |
+
+
+
+ | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
-
-
- = nl2br(esc($config['return_policy'])) ?>
-
-
-
-
![<?='$sale_id'?]()
src='data:image/svg+xml;base64,= base64_encode($barcode) ?>' />
- = $sale_id ?>
-
-
+
+ | |
+
+
+
+
+
+ = nl2br(esc($config['return_policy'])) ?>
+
+
+
+
![<?='$sale_id'?]()
src='data:image/svg+xml;base64,= base64_encode($barcode) ?>' />
+ = $sale_id ?>
+
+
diff --git a/app/Views/sales/receipt_short.php b/app/Views/sales/receipt_short.php
index cbbeb6c12..31557dc6d 100644
--- a/app/Views/sales/receipt_short.php
+++ b/app/Views/sales/receipt_short.php
@@ -15,208 +15,208 @@
*/
?>
-
-
-
-
= lang('Customers.customer') . esc(": $customer") ?>
-
+
+
+
= lang('Customers.customer') . esc(": $customer") ?>
+
-
= lang('Sales.id') . esc(": $sale_id") ?>
+
= lang('Sales.id') . esc(": $sale_id") ?>
-
-
= lang('Sales.invoice_number') . ": $invoice_number" ?>
-
+
+
= lang('Sales.invoice_number') . ": $invoice_number" ?>
+
-
= lang('Employees.employee') . esc(": $employee") ?>
-
+
= lang('Employees.employee') . esc(": $employee") ?>
+
-
-
- | = lang('Sales.description_abbrv') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.total') ?> |
-
- $item)
- {
- ?>
-
- | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
-
-
-
- | = esc($item['description']) ?> |
-
-
- = esc($item['serialnumber']) ?> |
-
-
- 0)
- {
- ?>
-
-
- | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
-
- = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
+
+
+ | = lang('Sales.description_abbrv') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.total') ?> |
+
+ $item)
+ {
+ ?>
+
+ | = esc(ucfirst($item['name'] . ' ' . $item['attribute_values'])) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item[($config['receipt_show_total_discount'] ? 'total' : 'discounted_total')]) ?> |
+
+
+
+ | = esc($item['description']) ?> |
+
+
+ = esc($item['serialnumber']) ?> |
+
+
+ 0)
+ {
+ ?>
+
+
+ | = to_currency($item['discount']) . " " . lang('Sales.discount') ?> |
+
+ = to_decimals($item['discount']) . " " . lang('Sales.discount_included') ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
-
+
- 0)
- {
- ?>
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
-
- | = lang('Sales.discount') ?>: |
- = to_currency($discount * -1) ?> |
-
-
+ 0)
+ {
+ ?>
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+
+ | = lang('Sales.discount') ?>: |
+ = to_currency($discount * -1) ?> |
+
+
-
-
- | = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
- $tax)
- {
- ?>
-
- | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
-
+
+
+ | = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+ $tax)
+ {
+ ?>
+
+ | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?>: |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
+
-
-
+
+
- 0)); ?>
-
- | = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+ 0)); ?>
+
+ | = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']);
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] * -1 ) ?> |
-
-
+ $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']);
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] * -1 ) ?> |
+
+
-
-
- | = lang('Sales.giftcard_balance') ?> |
- = to_currency($cur_giftcard_value) ?> |
-
-
-
- | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
-
+
+
+ | = lang('Sales.giftcard_balance') ?> |
+ = to_currency($cur_giftcard_value) ?> |
+
+
+
+ | = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
+
-
- = nl2br(esc($config['return_policy'])) ?>
-
+
+ = nl2br(esc($config['return_policy'])) ?>
+
-
- = $barcode ?>
- = $sale_id ?>
-
+
+ = $barcode ?>
+ = $sale_id ?>
+
diff --git a/app/Views/sales/register.php b/app/Views/sales/register.php
index 193c3b19e..abfe00672 100644
--- a/app/Views/sales/register.php
+++ b/app/Views/sales/register.php
@@ -47,999 +47,999 @@ use App\Models\Employee;
$error";
+ echo "$error
";
}
if(!empty($warning))
{
- echo "$warning
";
+ echo "$warning
";
}
if(isset($success))
{
- echo "$success
";
+ echo "$success
";
}
?>
- = form_open("$controller_name/changeMode", ['id' => 'mode_form', 'class' => 'form-horizontal panel panel-default']) ?>
-
-
- -
-
-
- -
- = form_dropdown('mode', $modes, $mode, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
-
- -
-
-
- -
- = form_dropdown('dinner_table', $empty_tables, $selected_table, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
- 1)
- {
- ?>
- -
-
-
- -
- = form_dropdown('stock_location', $stock_locations, $stock_location, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
-
-
+ = form_open("$controller_name/changeMode", ['id' => 'mode_form', 'class' => 'form-horizontal panel panel-default']) ?>
+
+
+ -
+
+
+ -
+ = form_dropdown('mode', $modes, $mode, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
+
+ -
+
+
+ -
+ = form_dropdown('dinner_table', $empty_tables, $selected_table, ['onchange'=>"$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
+ 1)
+ {
+ ?>
+ -
+
+
+ -
+ = form_dropdown('stock_location', $stock_locations, $stock_location, ['onchange' => "$('#mode_form').submit();", 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+
+
- -
-
-
+ -
+
+
- has_grant('reports_sales', session('person_id')))
- {
- ?>
- -
- = anchor("$controller_name/manage", ' ' . lang(ucfirst($controller_name) .'.takings'),
- array('class' => 'btn btn-primary btn-sm', 'id' => 'sales_takings_button', 'title' => lang(ucfirst($controller_name) .'.takings'))) ?>
-
-
-
-
- = form_close() ?>
+ has_grant('reports_sales', session('person_id')))
+ {
+ ?>
+ -
+ = anchor("$controller_name/manage", ' ' . lang(ucfirst($controller_name) .'.takings'),
+ array('class' => 'btn btn-primary btn-sm', 'id' => 'sales_takings_button', 'title' => lang(ucfirst($controller_name) .'.takings'))) ?>
+
+
+
+
+ = form_close() ?>
-
+
- = form_open("$controller_name/add", ['id' => 'add_item_form', 'class' => 'form-horizontal panel panel-default']) ?>
-
-
- -
-
-
- -
- = form_input (['name' => 'item', 'id' => 'item', 'class' => 'form-control input-sm', 'size' => '50', 'tabindex' => ++$tabindex]) ?>
-
-
- -
-
-
-
-
- = form_close() ?>
+ = form_open("$controller_name/add", ['id' => 'add_item_form', 'class' => 'form-horizontal panel panel-default']) ?>
+
+
+ -
+
+
+ -
+ = form_input (['name' => 'item', 'id' => 'item', 'class' => 'form-control input-sm', 'size' => '50', 'tabindex' => ++$tabindex]) ?>
+
+
+ -
+
+
+
+
+ = form_close() ?>
-
-
-
- | = lang('Common.delete') ?> |
- = lang(ucfirst($controller_name) .'.item_number') ?> |
- = lang(ucfirst($controller_name) .'.item_name') ?> |
- = lang(ucfirst($controller_name) .'.price') ?> |
- = lang(ucfirst($controller_name) .'.quantity') ?> |
- = lang(ucfirst($controller_name) .'.discount') ?> |
- = lang(ucfirst($controller_name) .'.total') ?> |
- = lang(ucfirst($controller_name) .'.update') ?> |
-
-
+
+
+
+ | = lang('Common.delete') ?> |
+ = lang(ucfirst($controller_name) .'.item_number') ?> |
+ = lang(ucfirst($controller_name) .'.item_name') ?> |
+ = lang(ucfirst($controller_name) .'.price') ?> |
+ = lang(ucfirst($controller_name) .'.quantity') ?> |
+ = lang(ucfirst($controller_name) .'.discount') ?> |
+ = lang(ucfirst($controller_name) .'.total') ?> |
+ = lang(ucfirst($controller_name) .'.update') ?> |
+
+
-
-
-
- |
- = lang(ucfirst($controller_name) .'.no_items_in_cart') ?>
- |
-
- $item)
- {
- ?>
- = form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
-
- |
- ');
- echo form_hidden('location', (string)$item['item_location']);
- echo form_input (['type' => 'hidden', 'name' => 'item_id', 'value'=>$item['item_id']]);
- ?>
- |
-
- = form_input (['name' => 'item_number', 'id' => 'item_number','class' => 'form-control input-sm', 'value'=>$item['item_number'], 'tabindex'=>++$tabindex]) ?> |
-
- = form_input (['name' => 'name','id' => 'name', 'class' => 'form-control input-sm', 'value'=>$item['name'], 'tabindex'=>++$tabindex]) ?>
- |
-
- = esc($item['item_number']) ?> |
-
- = esc($item['name']) . ' '. implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']]) ?>
-
-
- |
-
+
+
+
+ |
+ = lang(ucfirst($controller_name) .'.no_items_in_cart') ?>
+ |
+
+ $item)
+ {
+ ?>
+ = form_open("$controller_name/editItem/$line", ['class' => 'form-horizontal', 'id' => "cart_$line"]) ?>
+
+ |
+ ');
+ echo form_hidden('location', (string)$item['item_location']);
+ echo form_input (['type' => 'hidden', 'name' => 'item_id', 'value'=>$item['item_id']]);
+ ?>
+ |
+
+ = form_input (['name' => 'item_number', 'id' => 'item_number','class' => 'form-control input-sm', 'value'=>$item['item_number'], 'tabindex'=>++$tabindex]) ?> |
+
+ = form_input (['name' => 'name','id' => 'name', 'class' => 'form-control input-sm', 'value'=>$item['name'], 'tabindex'=>++$tabindex]) ?>
+ |
+
+ = esc($item['item_number']) ?> |
+
+ = esc($item['name']) . ' '. implode(' ', [$item['attribute_values'], $item['attribute_dtvalues']]) ?>
+
+
+ |
+
-
- 'price', 'class' => 'form-control input-sm', 'value' => to_currency_no_money($item['price']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
- }
- else
- {
- echo to_currency($item['price']);
- echo form_hidden('price', to_currency_no_money($item['price']));
- }
- ?>
- |
+
+ 'price', 'class' => 'form-control input-sm', 'value' => to_currency_no_money($item['price']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
+ }
+ else
+ {
+ echo to_currency($item['price']);
+ echo form_hidden('price', to_currency_no_money($item['price']));
+ }
+ ?>
+ |
-
- 'quantity', 'class' => 'form-control input-sm', 'value' => to_quantity_decimals($item['quantity']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
- }
- ?>
- |
+
+ 'quantity', 'class' => 'form-control input-sm', 'value' => to_quantity_decimals($item['quantity']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
+ }
+ ?>
+ |
-
-
- = form_input (['name' => 'discount', 'class' => 'form-control input-sm', 'value' => $item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
-
- = form_checkbox (['id' => 'discount_toggle', 'name' => 'discount_toggle', 'value' => 1, 'data-toggle' => "toggle",'data-size' => 'small', 'data-onstyle' => 'success', 'data-on' => '' . $config['currency_symbol'] . '', 'data-off' => '%', 'data-line' => $line, 'checked' => $item['discount_type'] == 1]) ?>
-
-
- |
+
+
+ = form_input (['name' => 'discount', 'class' => 'form-control input-sm', 'value' => $item['discount_type'] ? to_currency_no_money($item['discount']) : to_decimals($item['discount']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
+
+ = form_checkbox (['id' => 'discount_toggle', 'name' => 'discount_toggle', 'value' => 1, 'data-toggle' => "toggle",'data-size' => 'small', 'data-onstyle' => 'success', 'data-on' => '' . $config['currency_symbol'] . '', 'data-off' => '%', 'data-line' => $line, 'checked' => $item['discount_type'] == 1]) ?>
+
+
+ |
-
- 'discounted_total', 'class' => 'form-control input-sm', 'value' => to_currency_no_money($item['discounted_total']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
- }
- else
- {
- echo to_currency($item['discounted_total']);
- }
- ?>
- |
+
+ 'discounted_total', 'class' => 'form-control input-sm', 'value' => to_currency_no_money($item['discounted_total']), 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']);
+ }
+ else
+ {
+ echo to_currency($item['discounted_total']);
+ }
+ ?>
+ |
- ').submit();" title== lang(ucfirst($controller_name) .'.update') ?> > |
-
-
-
- | = form_input (['type' => 'hidden', 'name' => 'item_id', 'value' => $item['item_id']]) ?> |
-
- = form_input (['name' => 'item_description', 'id' => 'item_description', 'class' => 'form-control input-sm', 'value' => $item['description'], 'tabindex' => ++$tabindex]) ?>
- |
- |
-
- |
-
- = lang(ucfirst($controller_name) .'.description_abbrv') ?> |
-
+ ').submit();" title== lang(ucfirst($controller_name) .'.update') ?> > |
+
+
+
+ | = form_input (['type' => 'hidden', 'name' => 'item_id', 'value' => $item['item_id']]) ?> |
+
+ = form_input (['name' => 'item_description', 'id' => 'item_description', 'class' => 'form-control input-sm', 'value' => $item['description'], 'tabindex' => ++$tabindex]) ?>
+ |
+ |
+
+ |
+
+ = lang(ucfirst($controller_name) .'.description_abbrv') ?> |
+
-
- 'description', 'class' => 'form-control input-sm', 'value' => $item['description'], 'onClick' => 'this.select();']);
- }
- else
- {
- if($item['description'] != '')
- {
- echo $item['description'];
- echo form_hidden('description', $item['description']);
- }
- else
- {
- echo lang(ucfirst($controller_name) .'.no_description');
- echo form_hidden('description','');
- }
- }
- ?>
- |
- |
-
-
- |
-
- 'serialnumber', 'class' => 'form-control input-sm', 'value' => $item['serialnumber'], 'onClick' => 'this.select();']);
- }
- else
- {
- echo form_hidden('serialnumber', '');
- }
- ?>
- |
-
-
- = form_close() ?>
-
-
-
+
+ 'description', 'class' => 'form-control input-sm', 'value' => $item['description'], 'onClick' => 'this.select();']);
+ }
+ else
+ {
+ if($item['description'] != '')
+ {
+ echo $item['description'];
+ echo form_hidden('description', $item['description']);
+ }
+ else
+ {
+ echo lang(ucfirst($controller_name) .'.no_description');
+ echo form_hidden('description','');
+ }
+ }
+ ?>
+ |
+ |
+
+
+ |
+
+ 'serialnumber', 'class' => 'form-control input-sm', 'value' => $item['serialnumber'], 'onClick' => 'this.select();']);
+ }
+ else
+ {
+ echo form_hidden('serialnumber', '');
+ }
+ ?>
+ |
+
+
+ = form_close() ?>
+
+
+
-
- = form_open("$controller_name/selectCustomer", ['id' => 'select_customer_form', 'class' => 'form-horizontal']) ?>
-
-
-
- | = lang(ucfirst($controller_name) .'.customer') ?> |
- = anchor("customers/view/$customer_id", $customer, ['class' => 'modal-dlg', 'data-btn-submit' => lang('Common.submit'), 'title' => lang('Customers.update')]) ?> |
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_email') ?> |
- = esc($customer_email) ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_address') ?> |
- = esc($customer_address) ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_location') ?> |
- = esc($customer_location) ?> |
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_discount') ?> |
- = ($customer_discount_type == FIXED) ? to_currency($customer_discount) : $customer_discount . '%' ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.rewards_package') ?> |
- = esc($customer_rewards['package_name']) ?> |
-
-
- | = lang('Customers.available_points') ?> |
- = esc($customer_rewards['points']) ?> |
-
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_total') ?> |
- = to_currency($customer_total) ?> |
-
-
-
- | = lang(ucfirst($controller_name) .'.customer_mailchimp_status') ?> |
- = esc($mailchimp_info['status']) ?> |
-
-
-
+
+ = form_open("$controller_name/selectCustomer", ['id' => 'select_customer_form', 'class' => 'form-horizontal']) ?>
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer') ?> |
+ = anchor("customers/view/$customer_id", $customer, ['class' => 'modal-dlg', 'data-btn-submit' => lang('Common.submit'), 'title' => lang('Customers.update')]) ?> |
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_email') ?> |
+ = esc($customer_email) ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_address') ?> |
+ = esc($customer_address) ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_location') ?> |
+ = esc($customer_location) ?> |
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_discount') ?> |
+ = ($customer_discount_type == FIXED) ? to_currency($customer_discount) : $customer_discount . '%' ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.rewards_package') ?> |
+ = esc($customer_rewards['package_name']) ?> |
+
+
+ | = lang('Customers.available_points') ?> |
+ = esc($customer_rewards['points']) ?> |
+
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_total') ?> |
+ = to_currency($customer_total) ?> |
+
+
+
+ | = lang(ucfirst($controller_name) .'.customer_mailchimp_status') ?> |
+ = esc($mailchimp_info['status']) ?> |
+
+
+
- = anchor(
- "$controller_name/removeCustomer",
- '
 ' . lang('Common.remove') . ' ' . lang('Customers.customer'),
- ['class' => 'btn btn-danger btn-sm', 'id' => 'remove_customer_button', 'title' => lang('Common.remove') . ' ' . lang('Customers.customer')]
- )
- ?>
-
-
+
+ = form_close() ?>
-
-
- | = lang(ucfirst($controller_name) .'.quantity_of_items', [$item_count]) ?> |
- = $total_units ?> |
-
-
- | = lang(ucfirst($controller_name) .'.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+
+ | = lang(ucfirst($controller_name) .'.quantity_of_items', [$item_count]) ?> |
+ = $total_units ?> |
+
+
+ | = lang(ucfirst($controller_name) .'.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | = lang(ucfirst($controller_name) .'.total') ?> |
- = to_currency($total) ?> |
-
-
+
+ | = lang(ucfirst($controller_name) .'.total') ?> |
+ = to_currency($total) ?> |
+
+
- 0)
- {
- ?>
-
-
- | = lang(ucfirst($controller_name) .'.payments_total') ?> |
- = to_currency($payments_total) ?> |
-
-
- | = lang(ucfirst($controller_name) .'.amount_due') ?> |
- = to_currency($amount_due) ?> |
-
-
+ 0)
+ {
+ ?>
+
+
+ | = lang(ucfirst($controller_name) .'.payments_total') ?> |
+ = to_currency($payments_total) ?> |
+
+
+ | = lang(ucfirst($controller_name) .'.amount_due') ?> |
+ = to_currency($amount_due) ?> |
+
+
-
-
- = form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
-
-
- | = lang(ucfirst($controller_name) .'.payment') ?> |
-
- = form_dropdown('payment_type', $payment_options, $selected_payment_type, ['id' => 'payment_types', 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit', 'disabled' => 'disabled']) ?>
- |
-
-
- | = lang(ucfirst($controller_name) .'.amount_tendered') ?> |
-
- = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm disabled', 'disabled' => 'disabled', 'value' => '0', 'size' => '5', 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
- |
-
-
- = form_close() ?>
+
+
+ = form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
+
+
+ | = lang(ucfirst($controller_name) .'.payment') ?> |
+
+ = form_dropdown('payment_type', $payment_options, $selected_payment_type, ['id' => 'payment_types', 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit', 'disabled' => 'disabled']) ?>
+ |
+
+
+ | = lang(ucfirst($controller_name) .'.amount_tendered') ?> |
+
+ = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm disabled', 'disabled' => 'disabled', 'value' => '0', 'size' => '5', 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
+ |
+
+
+ = form_close() ?>
- 0)
- {
- foreach($payments as $payment_id => $payment)
- {
- if($payment['payment_type'] == lang(ucfirst($controller_name) .'.due'))
- {
- $due_payment = true;
- }
- }
- }
+ if(count($payments) > 0)
+ {
+ foreach($payments as $payment_id => $payment)
+ {
+ if($payment['payment_type'] == lang(ucfirst($controller_name) .'.due'))
+ {
+ $due_payment = true;
+ }
+ }
+ }
- if(!$due_payment || ($due_payment && isset($customer))) //TODO: $due_payment is not needed because the first clause insures that it will always be true if it gets to this point. Can be shortened to if(!$due_payment || isset($customer))
- {
- ?>
-
 = lang(ucfirst($controller_name) .'.complete_sale') ?>
-
-
- = form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
-
-
- | = lang(ucfirst($controller_name) .'.payment') ?> |
-
- = form_dropdown('payment_type', $payment_options, $selected_payment_type, ['id' => 'payment_types', 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
- |
-
-
- | = lang(ucfirst($controller_name) .'.amount_tendered') ?> |
-
- = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm non-giftcard-input', 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
- = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm giftcard-input', 'disabled' => true, 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex]) ?>
- |
-
-
- = form_close() ?>
+ if(!$due_payment || ($due_payment && isset($customer))) //TODO: $due_payment is not needed because the first clause insures that it will always be true if it gets to this point. Can be shortened to if(!$due_payment || isset($customer))
+ {
+ ?>
+
 = lang(ucfirst($controller_name) .'.complete_sale') ?>
+
+
+ = form_open("$controller_name/addPayment", ['id' => 'add_payment_form', 'class' => 'form-horizontal']) ?>
+
+
+ | = lang(ucfirst($controller_name) .'.payment') ?> |
+
+ = form_dropdown('payment_type', $payment_options, $selected_payment_type, ['id' => 'payment_types', 'class' => 'selectpicker show-menu-arrow', 'data-style' => 'btn-default btn-sm', 'data-width' => 'fit']) ?>
+ |
+
+
+ | = lang(ucfirst($controller_name) .'.amount_tendered') ?> |
+
+ = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm non-giftcard-input', 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex, 'onClick' => 'this.select();']) ?>
+ = form_input (['name' => 'amount_tendered', 'id' => 'amount_tendered', 'class' => 'form-control input-sm giftcard-input', 'disabled' => true, 'value' => to_currency_no_money($amount_due), 'size' => '5', 'tabindex' => ++$tabindex]) ?>
+ |
+
+
+ = form_close() ?>
-
 = lang(ucfirst($controller_name) .'.add_payment') ?>
-
+
 = lang(ucfirst($controller_name) .'.add_payment') ?>
+
- 0)
- {
- ?>
-
-
-
- | = lang('Common.delete') ?> |
- = lang(ucfirst($controller_name) .'.payment_type') ?> |
- = lang(ucfirst($controller_name) .'.payment_amount') ?> |
-
-
+ 0)
+ {
+ ?>
+
+
+
+ | = lang('Common.delete') ?> |
+ = lang(ucfirst($controller_name) .'.payment_type') ?> |
+ = lang(ucfirst($controller_name) .'.payment_amount') ?> |
+
+
-
- $payment)
- {
- ?>
-
- | = anchor("$controller_name/deletePayment/$payment_id", '') ?> |
- = esc($payment['payment_type']) ?> |
- = to_currency($payment['payment_amount']) ?> |
-
-
-
-
-
-
+
+ $payment)
+ {
+ ?>
+
+ | = anchor("$controller_name/deletePayment/$payment_id", '') ?> |
+ = esc($payment['payment_type']) ?> |
+ = to_currency($payment['payment_amount']) ?> |
+
+
+
+
+
+
- = form_open("$controller_name/cancel", ['id' => 'buttons_form']) ?>
-
+ = form_close() ?>
-
-
-
-
-
+
+
+ #
+ = form_input (['name' => 'sales_invoice_number', 'id' => 'sales_invoice_number', 'class' => 'form-control input-sm', 'value' => $invoice_number]) ?>
+
+
+
+
+
+
+
+
+
diff --git a/app/Views/sales/suspended.php b/app/Views/sales/suspended.php
index 84459f529..97950a62f 100644
--- a/app/Views/sales/suspended.php
+++ b/app/Views/sales/suspended.php
@@ -11,89 +11,89 @@ use App\Models\Customer;
diff --git a/app/Views/sales/tax_invoice.php b/app/Views/sales/tax_invoice.php
index e8b9516b4..20b0152b2 100644
--- a/app/Views/sales/tax_invoice.php
+++ b/app/Views/sales/tax_invoice.php
@@ -24,8 +24,8 @@
$error_message
";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
@@ -33,21 +33,21 @@ if(isset($error_message))
@@ -55,247 +55,247 @@ $(document).ready(function()
= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'invoice_printer']) ?>
-
-
-
-
-
= nl2br(esc($customer_info)) ?>
-
-
+
+
+
+
+
= nl2br(esc($customer_info)) ?>
+
+
-
-
-
, 'url') ?>)
-
-
 
-
-
= esc($config['company']) ?>
-
-
-
+
+
+
, 'url') ?>)
+
+
 
+
+
= esc($config['company']) ?>
+
+
+
-
-
= nl2br(esc($company_info)) ?>
-
-
+
+
= nl2br(esc($company_info)) ?>
+
+
-
-
- | = lang('Sales.item_number') ?> |
-
- = lang('Sales.hsn') ?> |
-
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- 0)
- {
- $invoice_columns += 1; //TODO: $invoice_columns++; ?
- ?>
- = lang('Sales.customer_discount') ?> |
-
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+
+ = lang('Sales.hsn') ?> |
+
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ 0)
+ {
+ $invoice_columns += 1; //TODO: $invoice_columns++; ?
+ ?>
+ = lang('Sales.customer_discount') ?> |
+
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES) //TODO: === ?
- {
- ?>
-
- | = $item['item_number'] ?> |
-
- = esc($item['hsn_code']) ?> |
-
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- 0): ?>
- = to_currency($item['discounted_total'] / $item['quantity']) ?> |
-
- = to_currency($item['discounted_total']) ?> |
-
-
-
- | = esc($item['hsn_code']) ?> |
-
- = esc($item['description']) ?>
- |
- = esc($item['serialnumber']) //TODO: serialnumber does not meet naming conventions for this project ?> |
-
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES) //TODO: === ?
+ {
+ ?>
+
+ | = $item['item_number'] ?> |
+
+ = esc($item['hsn_code']) ?> |
+
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ 0): ?>
+ = to_currency($item['discounted_total'] / $item['quantity']) ?> |
+
+ = to_currency($item['discounted_total']) ?> |
+
+
+
+ | = esc($item['hsn_code']) ?> |
+
+ = esc($item['description']) ?>
+ |
+ = esc($item['serialnumber']) //TODO: serialnumber does not meet naming conventions for this project ?> |
+
+
-
- | = ' ' ?> |
-
+
+ | = ' ' ?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']);
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | |
- = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] * -1 ) ?> |
-
- $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']);
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | |
+ = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] * -1 ) ?> |
+
+
-
- | |
- = lang('Sales.giftcard_balance') ?>/td>
- | = to_currency($cur_giftcard_value) ?> |
-
-
+
+ | |
+ = lang('Sales.giftcard_balance') ?>/td>
+ | = to_currency($cur_giftcard_value) ?> |
+
+
-
- | = lang('Sales.authorized_signature') ?>: |
- = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
- = to_currency($amount_change) ?> |
-
-
-
+ if(!empty($payments))
+ {
+ ?>
+
+ | = lang('Sales.authorized_signature') ?>: |
+ = lang($amount_change >= 0 ? ($only_sale_check ? 'Sales.check_balance' : 'Sales.change_due') : 'Sales.amount_due') ?> |
+ = to_currency($amount_change) ?> |
+
+
+
-
-
-
- = nl2br($config['payment_message']) ?>
- = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
- = esc($config['invoice_default_comments']) ?>
-
-
= nl2br(esc($config['return_policy'])) ?>
-
-
-
 ?>)
- = $sale_id ?>
-
-
+
+
+
+ = nl2br($config['payment_message']) ?>
+ = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
+ = esc($config['invoice_default_comments']) ?>
+
+
= nl2br(esc($config['return_policy'])) ?>
+
+
+
 ?>)
+ = $sale_id ?>
+
+
diff --git a/app/Views/sales/work_order.php b/app/Views/sales/work_order.php
index 78da9a7e4..021a8cf41 100644
--- a/app/Views/sales/work_order.php
+++ b/app/Views/sales/work_order.php
@@ -22,226 +22,226 @@
$error_message";
- exit;
+ echo "$error_message
";
+ exit;
}
?>
-
+
+ send_email();
+
+ });
+
= view('partial/print_receipt', ['print_after_sale' => $print_after_sale, 'selected_printer' => 'invoice_printer']) ?>
-
-
-
-
-
= esc(nl2br($customer_info)) ?>
-
-
+
+
+
+
+
= esc(nl2br($customer_info)) ?>
+
+
-
-
-
 ?>)
-
-
 
-
-
= esc($config['company']) ?>
-
-
-
+
+
+
 ?>)
+
+
 
+
+
= esc($config['company']) ?>
+
+
+
-
-
= esc(nl2br($company_info)) ?>
-
-
+
+
= esc(nl2br($company_info)) ?>
+
+
-
-
- | = lang('Sales.item_number') ?> |
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- = lang('Sales.total') ?> |
-
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc($item['item_number']) ?> |
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- |
-
+
+
+ | = lang('Sales.item_number') ?> |
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ = lang('Sales.total') ?> |
+
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc($item['item_number']) ?> |
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ |
+
-
-
- |
- = esc($item['description']) ?> |
- = esc($item['serialnumber']) ?> |
-
-
-
- | = ' ' //TODO: Why is PHP needed for an HTML ` `? ?> |
-
-
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($subtotal) ?> |
-
- $tax)
- {
- ?>
-
- | |
- = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
- = to_currency_tax($tax['sale_tax_amount']) ?> |
-
-
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
-
- $payment)
- {
- $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
- $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not match naming conventions for the project
- $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
- ?>
-
- | |
- = $splitpayment[0] ?> |
- = to_currency( $payment['payment_amount'] ) ?> |
-
-
-
-
-
-
- = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
-
-
-
+
+
+ |
+ = esc($item['description']) ?> |
+ = esc($item['serialnumber']) ?> |
+
+
+
+ | = ' ' //TODO: Why is PHP needed for an HTML ` `? ?> |
+
+
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($subtotal) ?> |
+
+ $tax)
+ {
+ ?>
+
+ | |
+ = (float)$tax['tax_rate'] . '% ' . $tax['tax_group'] ?> |
+ = to_currency_tax($tax['sale_tax_amount']) ?> |
+
+
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
+
+ $payment)
+ {
+ $only_sale_check |= $payment['payment_type'] == lang('Sales.check');
+ $splitpayment = explode(':', $payment['payment_type']); //TODO: $splitpayment does not match naming conventions for the project
+ $show_giftcard_remainder |= $splitpayment[0] == lang('Sales.giftcard');
+ ?>
+
+ | |
+ = $splitpayment[0] ?> |
+ = to_currency( $payment['payment_amount'] ) ?> |
+
+
+
+
+
+
+ = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
+
+
+
= view('partial/footer') ?>
diff --git a/app/Views/sales/work_order_email.php b/app/Views/sales/work_order_email.php
index 5216eae09..4d670b8bc 100644
--- a/app/Views/sales/work_order_email.php
+++ b/app/Views/sales/work_order_email.php
@@ -15,134 +15,134 @@
-
-
+
+
$error_message";
- exit;
- }
+ if(isset($error_message))
+ {
+ echo "$error_message
";
+ exit;
+ }
?>
-
-
-
-
-
-
-
- |
-
-
- |
-
-
-
- = esc($config['company']) ?>
- = esc($company_info) ?>
- |
-
-
-
- | = lang('Sales.work_order_number') ?> |
- = esc($work_order_number) ?> |
-
-
- | = lang('Common.date') ?> |
- = esc($transaction_date) ?> |
-
- 0)
- {
- ?>
-
- | = lang('Sales.amount_due') ?> |
- = to_currency($total) ?> |
-
-
-
- |
-
-
+
+
+
+
+
+
+
+ |
+
+
+ |
+
+
+
+ = esc($config['company']) ?>
+ = esc($company_info) ?>
+ |
+
+
+
+ | = lang('Sales.work_order_number') ?> |
+ = esc($work_order_number) ?> |
+
+
+ | = lang('Common.date') ?> |
+ = esc($transaction_date) ?> |
+
+ 0)
+ {
+ ?>
+
+ | = lang('Sales.amount_due') ?> |
+ = to_currency($total) ?> |
+
+
+
+ |
+
+
-
-
- | = lang('Sales.item_number') ?> |
- = lang('Sales.item_name') ?> |
- = lang('Sales.quantity') ?> |
- = lang('Sales.price') ?> |
- = lang('Sales.discount') ?> |
- = lang('Sales.total') ?> |
-
+
+
+ | = lang('Sales.item_number') ?> |
+ = lang('Sales.item_name') ?> |
+ = lang('Sales.quantity') ?> |
+ = lang('Sales.price') ?> |
+ = lang('Sales.discount') ?> |
+ = lang('Sales.total') ?> |
+
- $item)
- {
- if($item['print_option'] == PRINT_YES)
- {
- ?>
-
- | = esc($item['item_number']) ?> |
- = esc($item['name']) ?> |
- = to_quantity_decimals($item['quantity']) ?> |
- = to_currency($item['price']) ?> |
- = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
- = to_currency($item['discounted_total']) ?> |
-
-
+ $item)
+ {
+ if($item['print_option'] == PRINT_YES)
+ {
+ ?>
+
+ | = esc($item['item_number']) ?> |
+ = esc($item['name']) ?> |
+ = to_quantity_decimals($item['quantity']) ?> |
+ = to_currency($item['price']) ?> |
+ = ($item['discount_type'] == FIXED) ? to_currency($item['discount']) : to_decimals($item['discount']) . '%' ?> |
+ = to_currency($item['discounted_total']) ?> |
+
+
-
- | = ' ' ?> |
-
+
+ | = ' ' ?> |
+
-
- | |
- = lang('Sales.sub_total') ?> |
- = to_currency($tax_exclusive_subtotal) ?> |
-
+
+ | |
+ = lang('Sales.sub_total') ?> |
+ = to_currency($tax_exclusive_subtotal) ?> |
+
- $value)
- {
- ?>
-
- | |
- = esc($name) ?> |
- = to_currency_tax($value) ?> |
-
-
+ $value)
+ {
+ ?>
+
+ | |
+ = esc($name) ?> |
+ = to_currency_tax($value) ?> |
+
+
-
- | |
- = lang('Sales.total') ?> |
- = to_currency($total) ?> |
-
-
+
+ | |
+ = lang('Sales.total') ?> |
+ = to_currency($total) ?> |
+
+
-
-
-
- = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
-
-
-
+
+
+
+ = empty($comments) ? '' : lang('Sales.comments') . esc(": $comments") ?>
+
+
+
diff --git a/app/Views/suppliers/form.php b/app/Views/suppliers/form.php
index 9cca0347a..72c1b2f20 100644
--- a/app/Views/suppliers/form.php
+++ b/app/Views/suppliers/form.php
@@ -10,103 +10,103 @@
= form_open("$controller_name/save/$person_info->person_id", ['id' => 'supplier_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
- = view('people/form_basic_info') ?>
+ = view('people/form_basic_info') ?>
-
+
-
-
+
+
= form_close() ?>
diff --git a/app/Views/taxes/manage.php b/app/Views/taxes/manage.php
index c1ee98c08..a069490ed 100644
--- a/app/Views/taxes/manage.php
+++ b/app/Views/taxes/manage.php
@@ -6,37 +6,37 @@
= view('partial/header') ?>
-
- = view('taxes/tax_codes') ?>
-
-
- = view('taxes/tax_jurisdictions') ?>
-
-
- = view('taxes/tax_categories') ?>
-
-
- = view('taxes/tax_rates') ?>
-
+
+ = view('taxes/tax_codes') ?>
+
+
+ = view('taxes/tax_jurisdictions') ?>
+
+
+ = view('taxes/tax_categories') ?>
+
+
+ = view('taxes/tax_rates') ?>
+
= view('partial/footer') ?>
diff --git a/app/Views/taxes/tax_categories.php b/app/Views/taxes/tax_categories.php
index 6a602b080..b81b54261 100644
--- a/app/Views/taxes/tax_categories.php
+++ b/app/Views/taxes/tax_categories.php
@@ -5,130 +5,130 @@
?>
= form_open('taxes/save_tax_categories/', ['id' => 'tax_categories_form', 'class' => 'form-horizontal']) ?>
-
- = lang('Common.fields_required_message') ?>
-
+
+ = lang('Common.fields_required_message') ?>
+
-
- = view('partial/tax_categories') ?>
-
+
+ = view('partial/tax_categories') ?>
+
- = form_submit([
- 'name' => 'submit_tax_categories',
- 'id' => 'submit_tax_categories',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right'
- ]) ?>
-
+ = form_submit([
+ 'name' => 'submit_tax_categories',
+ 'id' => 'submit_tax_categories',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right'
+ ]) ?>
+
= form_close() ?>
diff --git a/app/Views/taxes/tax_codes.php b/app/Views/taxes/tax_codes.php
index ed0a3ebf2..efeb3db05 100644
--- a/app/Views/taxes/tax_codes.php
+++ b/app/Views/taxes/tax_codes.php
@@ -5,129 +5,129 @@
?>
= form_open('taxes/save_tax_codes/', ['id' => 'tax_codes_form', 'class' => 'form-horizontal']) ?>
-
- = lang('Common.fields_required_message') ?>
-
+
+ = lang('Common.fields_required_message') ?>
+
-
- = view('partial/tax_codes', ['tax_codes' => $tax_codes]) ?>
-
+
+ = view('partial/tax_codes', ['tax_codes' => $tax_codes]) ?>
+
- = form_submit ([
- 'name' => 'submit_tax_codes',
- 'id' => 'submit_tax_codes',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
+ = form_submit ([
+ 'name' => 'submit_tax_codes',
+ 'id' => 'submit_tax_codes',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
= form_close() ?>
diff --git a/app/Views/taxes/tax_jurisdictions.php b/app/Views/taxes/tax_jurisdictions.php
index 9e3236477..1ccc7a746 100644
--- a/app/Views/taxes/tax_jurisdictions.php
+++ b/app/Views/taxes/tax_jurisdictions.php
@@ -6,131 +6,131 @@
?>
= form_open('taxes/save_tax_jurisdictions/', ['id' => 'tax_jurisdictions_form', 'class' => 'form-horizontal']) ?>
-
- = lang('Common.fields_required_message') ?>
-
+
+ = lang('Common.fields_required_message') ?>
+
-
- = view('partial/tax_jurisdictions') ?>
-
+
+ = view('partial/tax_jurisdictions') ?>
+
- = form_submit ([
- 'name' => 'submit_tax_jurisdictions',
- 'id' => 'submit_tax_jurisdictions',
- 'value' => lang('Common.submit'),
- 'class' => 'btn btn-primary btn-sm pull-right']) ?>
-
+ = form_submit ([
+ 'name' => 'submit_tax_jurisdictions',
+ 'id' => 'submit_tax_jurisdictions',
+ 'value' => lang('Common.submit'),
+ 'class' => 'btn btn-primary btn-sm pull-right']) ?>
+
= form_close() ?>
diff --git a/app/Views/taxes/tax_rates.php b/app/Views/taxes/tax_rates.php
index b3c2bbbce..2219c9c78 100644
--- a/app/Views/taxes/tax_rates.php
+++ b/app/Views/taxes/tax_rates.php
@@ -8,31 +8,31 @@
-
+
diff --git a/app/Views/taxes/tax_rates_form.php b/app/Views/taxes/tax_rates_form.php
index fc02bef4a..def214e82 100644
--- a/app/Views/taxes/tax_rates_form.php
+++ b/app/Views/taxes/tax_rates_form.php
@@ -15,50 +15,50 @@
= form_open("taxes/save/$tax_rate_id", ['id' => 'tax_code_form', 'class' => 'form-horizontal']) ?>
-
-
+
+
-
+
-
+
-
-
-
+
+
= form_close() ?>
diff --git a/app/Views/viewData.php b/app/Views/viewData.php
index 4c696aace..4ed457a6c 100644
--- a/app/Views/viewData.php
+++ b/app/Views/viewData.php
@@ -1 +1 @@
-load->vars() does not exist in CI4
+load->vars() does not exist in CI4
diff --git a/composer.json b/composer.json
index f8605ec44..a771ccb82 100644
--- a/composer.json
+++ b/composer.json
@@ -1,78 +1,78 @@
{
- "name": "opensourcepos/opensourcepos",
- "description": "Open Source Point of Sale is a web based POS system written in the PHP language. It uses MySQL as backend and has a simple user interface",
- "license": "MIT",
- "authors": [
- {
- "name": "jekkos"
- },
- {
- "name": "FrancescoUK"
- },
- {
- "name": "objecttothis"
- },
- {
- "name": "steveireland"
- }
- ],
- "type": "project",
- "keywords": [
- "point-of-sale",
- "POS"
- ],
- "homepage": "https://opensourcepos.org",
- "support": {
- "issues": "https://github.com/opensourcepos/opensourcepos/issues",
- "forum": "https://github.com/opensourcepos/opensourcepos/discussions",
- "wiki": "https://github.com/opensourcepos/opensourcepos/wiki",
- "source": "https://github.com/opensourcepos/opensourcepos",
- "docs": "https://github.com/opensourcepos/opensourcepos/wiki#documentation",
- "matrix": "https://matrix.to/#/#opensourcepos_Lobby:gitter.im"
- },
- "require": {
- "php": "^8.1",
- "codeigniter4/framework": "4.5.5",
- "dompdf/dompdf": "^2.0.3",
- "ezyang/htmlpurifier": "^4.17",
- "laminas/laminas-escaper": "^2.13",
- "paragonie/random_compat": "^2.0.21",
- "picqer/php-barcode-generator": "^2.4.0",
- "tamtamchik/namecase": "^3.0.0"
- },
- "require-dev": {
- "codeigniter/coding-standard": "^1.7",
- "codeigniter4/devkit": "^1.2.3",
- "fakerphp/faker": "^1.23.0",
- "friendsofphp/php-cs-fixer": "^3.47.1",
- "kint-php/kint": "^5.0.4",
- "mikey179/vfsstream": "^1.6",
- "nexusphp/cs-config": "^3.6",
- "phpunit/phpunit": "^10.5.16 || ^11.2",
- "predis/predis": "^1.1 || ^2.0",
- "roave/security-advisories": "dev-latest"
- },
- "replace": {
- "psr/log": "*"
- },
- "autoload": {
- "psr-4": {
- "App\\": "app/",
- "CodeIgniter\\": "vendor/codeigniter4/framework/system/"
- },
- "exclude-from-classmap": [
- "**/Database/Migrations/**"
- ]
- },
- "config": {
- "allow-plugins": {
- "phpstan/extension-installer": true
- },
- "optimize-autoloader": true,
- "preferred-install": "dist",
- "sort-packages": true
- },
- "scripts": {
- "test": "phpunit"
- }
+ "name": "opensourcepos/opensourcepos",
+ "description": "Open Source Point of Sale is a web based POS system written in the PHP language. It uses MySQL as backend and has a simple user interface",
+ "license": "MIT",
+ "authors": [
+ {
+ "name": "jekkos"
+ },
+ {
+ "name": "FrancescoUK"
+ },
+ {
+ "name": "objecttothis"
+ },
+ {
+ "name": "steveireland"
+ }
+ ],
+ "type": "project",
+ "keywords": [
+ "point-of-sale",
+ "POS"
+ ],
+ "homepage": "https://opensourcepos.org",
+ "support": {
+ "issues": "https://github.com/opensourcepos/opensourcepos/issues",
+ "forum": "https://github.com/opensourcepos/opensourcepos/discussions",
+ "wiki": "https://github.com/opensourcepos/opensourcepos/wiki",
+ "source": "https://github.com/opensourcepos/opensourcepos",
+ "docs": "https://github.com/opensourcepos/opensourcepos/wiki#documentation",
+ "matrix": "https://matrix.to/#/#opensourcepos_Lobby:gitter.im"
+ },
+ "require": {
+ "php": "^8.1",
+ "codeigniter4/framework": "4.5.5",
+ "dompdf/dompdf": "^2.0.3",
+ "ezyang/htmlpurifier": "^4.17",
+ "laminas/laminas-escaper": "^2.13",
+ "paragonie/random_compat": "^2.0.21",
+ "picqer/php-barcode-generator": "^2.4.0",
+ "tamtamchik/namecase": "^3.0.0"
+ },
+ "require-dev": {
+ "codeigniter/coding-standard": "^1.7",
+ "codeigniter4/devkit": "^1.2.3",
+ "fakerphp/faker": "^1.23.0",
+ "friendsofphp/php-cs-fixer": "^3.47.1",
+ "kint-php/kint": "^5.0.4",
+ "mikey179/vfsstream": "^1.6",
+ "nexusphp/cs-config": "^3.6",
+ "phpunit/phpunit": "^10.5.16 || ^11.2",
+ "predis/predis": "^1.1 || ^2.0",
+ "roave/security-advisories": "dev-latest"
+ },
+ "replace": {
+ "psr/log": "*"
+ },
+ "autoload": {
+ "psr-4": {
+ "App\\": "app/",
+ "CodeIgniter\\": "vendor/codeigniter4/framework/system/"
+ },
+ "exclude-from-classmap": [
+ "**/Database/Migrations/**"
+ ]
+ },
+ "config": {
+ "allow-plugins": {
+ "phpstan/extension-installer": true
+ },
+ "optimize-autoloader": true,
+ "preferred-install": "dist",
+ "sort-packages": true
+ },
+ "scripts": {
+ "test": "phpunit"
+ }
}
diff --git a/docker/data/nginx/nginx.tmpl b/docker/data/nginx/nginx.tmpl
index 4ffec7436..43df13309 100644
--- a/docker/data/nginx/nginx.tmpl
+++ b/docker/data/nginx/nginx.tmpl
@@ -6,64 +6,64 @@ events {
http {
- error_log /etc/nginx/error_log.log warn;
+ error_log /etc/nginx/error_log.log warn;
- server {
- listen 80;
- server_name ${WEB_DOMAIN};
- server_tokens off;
+ server {
+ listen 80;
+ server_name ${WEB_DOMAIN};
+ server_tokens off;
- location /.well-known/acme-challenge/ {
- root /var/www/certbot;
- }
+ location /.well-known/acme-challenge/ {
+ root /var/www/certbot;
+ }
- location / {
- return 301 https://${ESC}host${ESC}request_uri;
- }
- }
+ location / {
+ return 301 https://${ESC}host${ESC}request_uri;
+ }
+ }
- server {
- listen 443 ssl;
- server_name ${WEB_DOMAIN};
- server_tokens off;
-
- client_max_body_size 10M;
+ server {
+ listen 443 ssl;
+ server_name ${WEB_DOMAIN};
+ server_tokens off;
- ssl_certificate /etc/letsencrypt/live/${WEB_DOMAIN}/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/${WEB_DOMAIN}/privkey.pem;
- include /etc/letsencrypt/options-ssl-nginx.conf;
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+ client_max_body_size 10M;
- location / {
- proxy_pass http://ospos:80;
- proxy_redirect off;
- proxy_set_header Host ${ESC}host;
- proxy_set_header X-Real-IP ${ESC}remote_addr;
- proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Host ${ESC}server_name;
- proxy_set_header X-Forwarded-Proto ${ESC}scheme;
- }
- }
+ ssl_certificate /etc/letsencrypt/live/${WEB_DOMAIN}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/${WEB_DOMAIN}/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
- server {
- listen 8000 ssl;
- server_name ${WEB_DOMAIN};
- server_tokens off;
+ location / {
+ proxy_pass http://ospos:80;
+ proxy_redirect off;
+ proxy_set_header Host ${ESC}host;
+ proxy_set_header X-Real-IP ${ESC}remote_addr;
+ proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host ${ESC}server_name;
+ proxy_set_header X-Forwarded-Proto ${ESC}scheme;
+ }
+ }
- ssl_certificate /etc/letsencrypt/live/${WEB_DOMAIN}/fullchain.pem;
- ssl_certificate_key /etc/letsencrypt/live/${WEB_DOMAIN}/privkey.pem;
- include /etc/letsencrypt/options-ssl-nginx.conf;
- ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+ server {
+ listen 8000 ssl;
+ server_name ${WEB_DOMAIN};
+ server_tokens off;
- location / {
- proxy_pass http://phpmyadmin:80;
- proxy_redirect off;
- proxy_set_header Host ${ESC}host;
- proxy_set_header X-Real-IP ${ESC}remote_addr;
- proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
- proxy_set_header X-Forwarded-Host ${ESC}server_name;
- proxy_set_header X-Forwarded-Proto ${ESC}scheme;
- }
- }
+ ssl_certificate /etc/letsencrypt/live/${WEB_DOMAIN}/fullchain.pem;
+ ssl_certificate_key /etc/letsencrypt/live/${WEB_DOMAIN}/privkey.pem;
+ include /etc/letsencrypt/options-ssl-nginx.conf;
+ ssl_dhparam /etc/letsencrypt/ssl-dhparams.pem;
+
+ location / {
+ proxy_pass http://phpmyadmin:80;
+ proxy_redirect off;
+ proxy_set_header Host ${ESC}host;
+ proxy_set_header X-Real-IP ${ESC}remote_addr;
+ proxy_set_header X-Forwarded-For ${ESC}proxy_add_x_forwarded_for;
+ proxy_set_header X-Forwarded-Host ${ESC}server_name;
+ proxy_set_header X-Forwarded-Proto ${ESC}scheme;
+ }
+ }
}
diff --git a/gulpfile.js b/gulpfile.js
index d0b855edd..3579ca809 100644
--- a/gulpfile.js
+++ b/gulpfile.js
@@ -25,10 +25,10 @@ var prod1js;
// Clear and remove the resources folder
gulp.task('clean', function () {
- return pipeline(
- gulp.src('./public/resources', {read: false, allowEmpty: true}),
- clean()
- );
+ return pipeline(
+ gulp.src('./public/resources', {read: false, allowEmpty: true}),
+ clean()
+ );
});
gulp.task('compress', function() {
@@ -39,41 +39,41 @@ gulp.task('compress', function() {
// Copy the bootswatch styles into their own folder so OSPOS can select one from the collection
gulp.task('copy-bootswatch', function() {
- pipeline(gulp.src('./node_modules/bootswatch/cerulean/*.min.css'),gulp.dest('public/resources/bootswatch/cerulean'));
- pipeline(gulp.src('./node_modules/bootswatch/cosmo/*.min.css'),gulp.dest('public/resources/bootswatch/cosmo'));
- pipeline(gulp.src('./node_modules/bootswatch/cyborg/*.min.css'),gulp.dest('public/resources/bootswatch/cyborg'));
- pipeline(gulp.src('./node_modules/bootswatch/darkly/*.min.css'),gulp.dest('public/resources/bootswatch/darkly'));
- pipeline(gulp.src('./node_modules/bootswatch/flatly/*.min.css'),gulp.dest('public/resources/bootswatch/flatly'));
- pipeline(gulp.src('./node_modules/bootswatch/journal/*.min.css'),gulp.dest('public/resources/bootswatch/journal'));
- pipeline(gulp.src('./node_modules/bootswatch/lumen/*.min.css'),gulp.dest('public/resources/bootswatch/lumen'));
- pipeline(gulp.src('./node_modules/bootswatch/paper/*.min.css'),gulp.dest('public/resources/bootswatch/paper'));
- pipeline(gulp.src('./node_modules/bootswatch/readable/*.min.css'),gulp.dest('public/resources/bootswatch/readable'));
- pipeline(gulp.src('./node_modules/bootswatch/sandstone/*.min.css'),gulp.dest('public/resources/bootswatch/sandstone'));
- pipeline(gulp.src('./node_modules/bootswatch/simplex/*.min.css'),gulp.dest('public/resources/bootswatch/simplex'));
- pipeline(gulp.src('./node_modules/bootswatch/slate/*.min.css'),gulp.dest('public/resources/bootswatch/slate'));
- pipeline(gulp.src('./node_modules/bootswatch/spacelab/*.min.css'),gulp.dest('public/resources/bootswatch/spacelab'));
- pipeline(gulp.src('./node_modules/bootswatch/superhero/*.min.css'),gulp.dest('public/resources/bootswatch/superhero'));
- pipeline(gulp.src('./node_modules/bootswatch/united/*.min.css'),gulp.dest('public/resources/bootswatch/united'));
- pipeline(gulp.src('./node_modules/bootswatch/yeti/*.min.css'),gulp.dest('public/resources/bootswatch/yeti'));
- return pipeline(gulp.src('./node_modules/bootswatch/fonts/*.*', {encoding:false}),gulp.dest('public/resources/bootswatch/fonts'));
+ pipeline(gulp.src('./node_modules/bootswatch/cerulean/*.min.css'),gulp.dest('public/resources/bootswatch/cerulean'));
+ pipeline(gulp.src('./node_modules/bootswatch/cosmo/*.min.css'),gulp.dest('public/resources/bootswatch/cosmo'));
+ pipeline(gulp.src('./node_modules/bootswatch/cyborg/*.min.css'),gulp.dest('public/resources/bootswatch/cyborg'));
+ pipeline(gulp.src('./node_modules/bootswatch/darkly/*.min.css'),gulp.dest('public/resources/bootswatch/darkly'));
+ pipeline(gulp.src('./node_modules/bootswatch/flatly/*.min.css'),gulp.dest('public/resources/bootswatch/flatly'));
+ pipeline(gulp.src('./node_modules/bootswatch/journal/*.min.css'),gulp.dest('public/resources/bootswatch/journal'));
+ pipeline(gulp.src('./node_modules/bootswatch/lumen/*.min.css'),gulp.dest('public/resources/bootswatch/lumen'));
+ pipeline(gulp.src('./node_modules/bootswatch/paper/*.min.css'),gulp.dest('public/resources/bootswatch/paper'));
+ pipeline(gulp.src('./node_modules/bootswatch/readable/*.min.css'),gulp.dest('public/resources/bootswatch/readable'));
+ pipeline(gulp.src('./node_modules/bootswatch/sandstone/*.min.css'),gulp.dest('public/resources/bootswatch/sandstone'));
+ pipeline(gulp.src('./node_modules/bootswatch/simplex/*.min.css'),gulp.dest('public/resources/bootswatch/simplex'));
+ pipeline(gulp.src('./node_modules/bootswatch/slate/*.min.css'),gulp.dest('public/resources/bootswatch/slate'));
+ pipeline(gulp.src('./node_modules/bootswatch/spacelab/*.min.css'),gulp.dest('public/resources/bootswatch/spacelab'));
+ pipeline(gulp.src('./node_modules/bootswatch/superhero/*.min.css'),gulp.dest('public/resources/bootswatch/superhero'));
+ pipeline(gulp.src('./node_modules/bootswatch/united/*.min.css'),gulp.dest('public/resources/bootswatch/united'));
+ pipeline(gulp.src('./node_modules/bootswatch/yeti/*.min.css'),gulp.dest('public/resources/bootswatch/yeti'));
+ return pipeline(gulp.src('./node_modules/bootswatch/fonts/*.*', {encoding:false}),gulp.dest('public/resources/bootswatch/fonts'));
});
// Copy the bootswatch styles into their own folder so OSPOS can select one from the collection
gulp.task('copy-bootswatch5', function() {
- pipeline(gulp.src('./node_modules/bootswatch5/dist/cerulean/*.min.css'),gulp.dest('public/resources/bootswatch5/cerulean'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/cosmo/*.min.css'),gulp.dest('public/resources/bootswatch5/cosmo'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/cyborg/*.min.css'),gulp.dest('public/resources/bootswatch5/cyborg'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/darkly/*.min.css'),gulp.dest('public/resources/bootswatch5/darkly'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/flatly/*.min.css'),gulp.dest('public/resources/bootswatch5/flatly'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/journal/*.min.css'),gulp.dest('public/resources/bootswatch5/journal'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/lumen/*.min.css'),gulp.dest('public/resources/bootswatch5/lumen'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/sandstone/*.min.css'),gulp.dest('public/resources/bootswatch5/sandstone'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/simplex/*.min.css'),gulp.dest('public/resources/bootswatch5/simplex'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/slate/*.min.css'),gulp.dest('public/resources/bootswatch5/slate'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/spacelab/*.min.css'),gulp.dest('public/resources/bootswatch5/spacelab'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/superhero/*.min.css'),gulp.dest('public/resources/bootswatch5/superhero'));
- pipeline(gulp.src('./node_modules/bootswatch5/dist/united/*.min.css'),gulp.dest('public/resources/bootswatch5/united'));
- return pipeline(gulp.src('./node_modules/bootswatch5/dist/yeti/*.min.css'),gulp.dest('public/resources/bootswatch5/yeti'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/cerulean/*.min.css'),gulp.dest('public/resources/bootswatch5/cerulean'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/cosmo/*.min.css'),gulp.dest('public/resources/bootswatch5/cosmo'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/cyborg/*.min.css'),gulp.dest('public/resources/bootswatch5/cyborg'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/darkly/*.min.css'),gulp.dest('public/resources/bootswatch5/darkly'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/flatly/*.min.css'),gulp.dest('public/resources/bootswatch5/flatly'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/journal/*.min.css'),gulp.dest('public/resources/bootswatch5/journal'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/lumen/*.min.css'),gulp.dest('public/resources/bootswatch5/lumen'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/sandstone/*.min.css'),gulp.dest('public/resources/bootswatch5/sandstone'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/simplex/*.min.css'),gulp.dest('public/resources/bootswatch5/simplex'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/slate/*.min.css'),gulp.dest('public/resources/bootswatch5/slate'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/spacelab/*.min.css'),gulp.dest('public/resources/bootswatch5/spacelab'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/superhero/*.min.css'),gulp.dest('public/resources/bootswatch5/superhero'));
+ pipeline(gulp.src('./node_modules/bootswatch5/dist/united/*.min.css'),gulp.dest('public/resources/bootswatch5/united'));
+ return pipeline(gulp.src('./node_modules/bootswatch5/dist/yeti/*.min.css'),gulp.dest('public/resources/bootswatch5/yeti'));
});
// /public/resources/ospos - contains the minimized files to be packed into opensourcepos.min.[css/js]
@@ -86,194 +86,194 @@ gulp.task('copy-bootswatch5', function() {
gulp.task('debug-js', function() {
- var debugjs = gulp.src(['./node_modules/jquery/dist/jquery.js',
- './node_modules/jquery-form/src/jquery.form.js',
- './node_modules/jquery-validation/dist/jquery.validate.js',
- './node_modules/jquery-ui-dist/jquery-ui.js',
- './node_modules/bootstrap/dist/js/bootstrap.js',
- './node_modules/bootstrap3-dialog/dist/js/bootstrap-dialog.js',
- './node_modules/jasny-bootstrap/dist/js/jasny-bootstrap.js',
- './node_modules/bootstrap-datetime-picker/js/bootstrap-datetimepicker.js',
- './node_modules/bootstrap-select/dist/js/bootstrap-select.js',
- './node_modules/bootstrap-table/dist/bootstrap-table.js',
- './node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.js',
- './node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.js',
- './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.js',
- './node_modules/moment/min/moment.min.js',
- './node_modules/bootstrap-daterangepicker/daterangepicker.js',
- './node_modules/es6-promise/dist/es6-promise.js',
- './node_modules/file-saver/dist/FileSaver.js',
- './node_modules/html2canvas/dist/html2canvas.js',
- './node_modules/jspdf/dist/jspdf.umd.js',
- './node_modules/jspdf-autotable/dist/jspdf.plugin.autotable.js',
- './node_modules/tableexport.jquery.plugin/tableExport.min.js',
- './node_modules/chartist/dist/chartist.js',
- './node_modules/chartist-plugin-pointlabels/dist/chartist-plugin-pointlabels.js',
- './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.js',
- './node_modules/chartist-plugin-axistitle/dist/chartist-plugin-axistitle.js',
- './node_modules/chartist-plugin-barlabels/dist/chartist-plugin-barlabels.js',
- './node_modules/bootstrap-notify/bootstrap-notify.js',
- './node_modules/js-cookie/src/js.cookie.js',
- './node_modules/bootstrap-tagsinput-2021/dist/bootstrap-tagsinput.js',
- './node_modules/bootstrap-toggle/js/bootstrap-toggle.js',
- './node_modules/clipboard/dist/clipboard.js',
- './public/js/imgpreview.full.jquery.js',
- './public/js/manage_tables.js',
- './public/js/nominatim.autocomplete.js']).pipe(rev()).pipe(gulp.dest('public/resources/js'));
- return gulp.src('./app/Views/partial/header.php').pipe(inject(debugjs,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
+ var debugjs = gulp.src(['./node_modules/jquery/dist/jquery.js',
+ './node_modules/jquery-form/src/jquery.form.js',
+ './node_modules/jquery-validation/dist/jquery.validate.js',
+ './node_modules/jquery-ui-dist/jquery-ui.js',
+ './node_modules/bootstrap/dist/js/bootstrap.js',
+ './node_modules/bootstrap3-dialog/dist/js/bootstrap-dialog.js',
+ './node_modules/jasny-bootstrap/dist/js/jasny-bootstrap.js',
+ './node_modules/bootstrap-datetime-picker/js/bootstrap-datetimepicker.js',
+ './node_modules/bootstrap-select/dist/js/bootstrap-select.js',
+ './node_modules/bootstrap-table/dist/bootstrap-table.js',
+ './node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.js',
+ './node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.js',
+ './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.js',
+ './node_modules/moment/min/moment.min.js',
+ './node_modules/bootstrap-daterangepicker/daterangepicker.js',
+ './node_modules/es6-promise/dist/es6-promise.js',
+ './node_modules/file-saver/dist/FileSaver.js',
+ './node_modules/html2canvas/dist/html2canvas.js',
+ './node_modules/jspdf/dist/jspdf.umd.js',
+ './node_modules/jspdf-autotable/dist/jspdf.plugin.autotable.js',
+ './node_modules/tableexport.jquery.plugin/tableExport.min.js',
+ './node_modules/chartist/dist/chartist.js',
+ './node_modules/chartist-plugin-pointlabels/dist/chartist-plugin-pointlabels.js',
+ './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.js',
+ './node_modules/chartist-plugin-axistitle/dist/chartist-plugin-axistitle.js',
+ './node_modules/chartist-plugin-barlabels/dist/chartist-plugin-barlabels.js',
+ './node_modules/bootstrap-notify/bootstrap-notify.js',
+ './node_modules/js-cookie/src/js.cookie.js',
+ './node_modules/bootstrap-tagsinput-2021/dist/bootstrap-tagsinput.js',
+ './node_modules/bootstrap-toggle/js/bootstrap-toggle.js',
+ './node_modules/clipboard/dist/clipboard.js',
+ './public/js/imgpreview.full.jquery.js',
+ './public/js/manage_tables.js',
+ './public/js/nominatim.autocomplete.js']).pipe(rev()).pipe(gulp.dest('public/resources/js'));
+ return gulp.src('./app/Views/partial/header.php').pipe(inject(debugjs,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
});
gulp.task('prod-js', function() {
- var prod0js = gulp.src('./node_modules/jquery/dist/jquery.min.js').pipe(rev()).pipe(gulp.dest('public/resources'));
+ var prod0js = gulp.src('./node_modules/jquery/dist/jquery.min.js').pipe(rev()).pipe(gulp.dest('public/resources'));
- var opensourcepos1js = gulp.src(['./node_modules/bootstrap/dist/js/bootstrap.min.js',
- './node_modules/bootstrap-table/dist/bootstrap-table.min.js',
- './node_modules/moment/min/moment.min.js',
- './node_modules/jquery-ui-dist/jquery-ui.min.js',
- './node_modules/bootstrap3-dialog/dist/js/bootstrap-dialog.min.js',
- './node_modules/jasny-bootstrap/dist/js/jasny-bootstrap.min.js',
- './node_modules/bootstrap-select/dist/js/bootstrap-select.min.js',
- './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.min.js',
- './node_modules/bootstrap-tagsinput-2021/dist/bootstrap-tagsinput.min.js',
- './node_modules/bootstrap-toggle/js/bootstrap-toggle.min.js',
- './node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.min.js',
- './node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.min.js',
- './node_modules/bootstrap-notify/bootstrap-notify.min.js',
- './node_modules/clipboard/dist/clipboard.min.js',
- './node_modules/jquery-form/dist/jquery.form.min.js',
- './node_modules/jquery-validation/dist/jquery.validate.min.js',
- './node_modules/bootstrap-datetime-picker/js/bootstrap-datetimepicker.min.js',
- './node_modules/es6-promise/dist/es6-promise.min.js',
- './node_modules/file-saver/dist/FileSaver.min.js',
- './node_modules/file-saver/dist/FileSaver.js',
- './node_modules/html2canvas/dist/html2canvas.min.js',
- './node_modules/chartist/dist/chartist.min.js',
- './node_modules/jspdf/dist/jspdf.umd.min.js',
- './node_modules/chartist/dist/chartist.min.js',
- './node_modules/chartist-plugin-pointlabels/dist/chartist-plugin-pointlabels.min.js',
- './node_modules/chartist-plugin-axistitle/dist/chartist-plugin-axistitle.min.js',
- './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.min.js',
- './node_modules/chartist-plugin-barlabels/dist/chartist-plugin-barlabels.min.js',
- './node_modules/tableexport.jquery.plugin/tableExport.min.js'], { allowEmpty: true });
+ var opensourcepos1js = gulp.src(['./node_modules/bootstrap/dist/js/bootstrap.min.js',
+ './node_modules/bootstrap-table/dist/bootstrap-table.min.js',
+ './node_modules/moment/min/moment.min.js',
+ './node_modules/jquery-ui-dist/jquery-ui.min.js',
+ './node_modules/bootstrap3-dialog/dist/js/bootstrap-dialog.min.js',
+ './node_modules/jasny-bootstrap/dist/js/jasny-bootstrap.min.js',
+ './node_modules/bootstrap-select/dist/js/bootstrap-select.min.js',
+ './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.min.js',
+ './node_modules/bootstrap-tagsinput-2021/dist/bootstrap-tagsinput.min.js',
+ './node_modules/bootstrap-toggle/js/bootstrap-toggle.min.js',
+ './node_modules/bootstrap-table/dist/extensions/export/bootstrap-table-export.min.js',
+ './node_modules/bootstrap-table/dist/extensions/mobile/bootstrap-table-mobile.min.js',
+ './node_modules/bootstrap-notify/bootstrap-notify.min.js',
+ './node_modules/clipboard/dist/clipboard.min.js',
+ './node_modules/jquery-form/dist/jquery.form.min.js',
+ './node_modules/jquery-validation/dist/jquery.validate.min.js',
+ './node_modules/bootstrap-datetime-picker/js/bootstrap-datetimepicker.min.js',
+ './node_modules/es6-promise/dist/es6-promise.min.js',
+ './node_modules/file-saver/dist/FileSaver.min.js',
+ './node_modules/file-saver/dist/FileSaver.js',
+ './node_modules/html2canvas/dist/html2canvas.min.js',
+ './node_modules/chartist/dist/chartist.min.js',
+ './node_modules/jspdf/dist/jspdf.umd.min.js',
+ './node_modules/chartist/dist/chartist.min.js',
+ './node_modules/chartist-plugin-pointlabels/dist/chartist-plugin-pointlabels.min.js',
+ './node_modules/chartist-plugin-axistitle/dist/chartist-plugin-axistitle.min.js',
+ './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.min.js',
+ './node_modules/chartist-plugin-barlabels/dist/chartist-plugin-barlabels.min.js',
+ './node_modules/tableexport.jquery.plugin/tableExport.min.js'], { allowEmpty: true });
- var opensourcepos2js = gulp.src(['./node_modules/bootstrap-daterangepicker/daterangepicker.js',
- './node_modules/js-cookie/src/js.cookie.js',
- './public/js/imgpreview.full.jquery.js',
- './public/js/manage_tables.js',
- './public/js/nominatim.autocomplete.js']).pipe(uglify());
+ var opensourcepos2js = gulp.src(['./node_modules/bootstrap-daterangepicker/daterangepicker.js',
+ './node_modules/js-cookie/src/js.cookie.js',
+ './public/js/imgpreview.full.jquery.js',
+ './public/js/manage_tables.js',
+ './public/js/nominatim.autocomplete.js']).pipe(uglify());
- var prod1js = series(opensourcepos1js, opensourcepos2js).pipe(concat('opensourcepos.min.js'))
- .pipe(rev())
- .pipe(gulp.dest('./public/resources/'));
+ var prod1js = series(opensourcepos1js, opensourcepos2js).pipe(concat('opensourcepos.min.js'))
+ .pipe(rev())
+ .pipe(gulp.dest('./public/resources/'));
- return gulp.src('./app/Views/partial/header.php').pipe(inject(
- series(prod0js, prod1js), {addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
+ return gulp.src('./app/Views/partial/header.php').pipe(inject(
+ series(prod0js, prod1js), {addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
});
gulp.task('debug-css', function() {
- var debugcss = gulp.src(['./node_modules/jquery-ui-dist/jquery-ui.css',
- './node_modules/bootstrap3-dialog/dist/css/bootstrap-dialog.css',
- './node_modules/jasny-bootstrap/dist/css/jasny-bootstrap.css',
- './node_modules/bootstrap-datetime-picker/css/bootstrap-datetimepicker.css',
- './node_modules/bootstrap-select/dist/css/bootstrap-select.css',
- './node_modules/bootstrap-table/dist/bootstrap-table.css',
- './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.css',
- './node_modules/bootstrap-daterangepicker/daterangepicker.css',
- './node_modules/chartist/dist/chartist.css',
- './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css',
- './node_modules/bootstrap-tagsinput-2021/src/bootstrap-tagsinput.css',
- './node_modules/bootstrap-toggle/css/bootstrap-toggle.css',
- './public/css/bootstrap.autocomplete.css',
- './public/css/invoice.css',
- './public/css/ospos_print.css',
- './public/css/ospos.css',
- './public/css/popupbox.css',
- './public/css/receipt.css',
- './public/css/register.css',
- './public/css/reports.css'
- ]).pipe(rev()).pipe(gulp.dest('public/resources/css'));
- return gulp.src('./app/Views/partial/header.php').pipe(inject(debugcss,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
+ var debugcss = gulp.src(['./node_modules/jquery-ui-dist/jquery-ui.css',
+ './node_modules/bootstrap3-dialog/dist/css/bootstrap-dialog.css',
+ './node_modules/jasny-bootstrap/dist/css/jasny-bootstrap.css',
+ './node_modules/bootstrap-datetime-picker/css/bootstrap-datetimepicker.css',
+ './node_modules/bootstrap-select/dist/css/bootstrap-select.css',
+ './node_modules/bootstrap-table/dist/bootstrap-table.css',
+ './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.css',
+ './node_modules/bootstrap-daterangepicker/daterangepicker.css',
+ './node_modules/chartist/dist/chartist.css',
+ './node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css',
+ './node_modules/bootstrap-tagsinput-2021/src/bootstrap-tagsinput.css',
+ './node_modules/bootstrap-toggle/css/bootstrap-toggle.css',
+ './public/css/bootstrap.autocomplete.css',
+ './public/css/invoice.css',
+ './public/css/ospos_print.css',
+ './public/css/ospos.css',
+ './public/css/popupbox.css',
+ './public/css/receipt.css',
+ './public/css/register.css',
+ './public/css/reports.css'
+ ]).pipe(rev()).pipe(gulp.dest('public/resources/css'));
+ return gulp.src('./app/Views/partial/header.php').pipe(inject(debugcss,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
});
gulp.task('prod-css', function() {
- var opensourcepos1css = gulp.src(['./node_modules/jquery-ui-dist/jquery-ui.min.css',
- './node_modules/bootstrap3-dialog/dist/css/bootstrap-dialog.min.css',
- './node_modules/jasny-bootstrap/dist/css/jasny-bootstrap.min.css',
- './node_modules/bootstrap-datetime-picker/css/bootstrap-datetimepicker.min.css']);
+ var opensourcepos1css = gulp.src(['./node_modules/jquery-ui-dist/jquery-ui.min.css',
+ './node_modules/bootstrap3-dialog/dist/css/bootstrap-dialog.min.css',
+ './node_modules/jasny-bootstrap/dist/css/jasny-bootstrap.min.css',
+ './node_modules/bootstrap-datetime-picker/css/bootstrap-datetimepicker.min.css']);
- var opensourcepos2css = gulp.src(['./node_modules/bootstrap-daterangepicker/daterangepicker.css',
- './node_modules/bootstrap-tagsinput-2021/src/bootstrap-tagsinput.css']).pipe(cleanCSS({compatibility: 'ie8'}));
+ var opensourcepos2css = gulp.src(['./node_modules/bootstrap-daterangepicker/daterangepicker.css',
+ './node_modules/bootstrap-tagsinput-2021/src/bootstrap-tagsinput.css']).pipe(cleanCSS({compatibility: 'ie8'}));
- var opensourcepos3css = gulp.src(['./node_modules/bootstrap-select/dist/css/bootstrap-select.min.css',
- './node_modules/bootstrap-table/dist/bootstrap-table.min.css',
- './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.min.css',
- './node_modules/bootstrap-toggle/css/bootstrap-toggle.min.css',
- './node_modules/chartist/dist/chartist.min.css']);
+ var opensourcepos3css = gulp.src(['./node_modules/bootstrap-select/dist/css/bootstrap-select.min.css',
+ './node_modules/bootstrap-table/dist/bootstrap-table.min.css',
+ './node_modules/bootstrap-table/dist/extensions/sticky-header/bootstrap-table-sticky-header.min.css',
+ './node_modules/bootstrap-toggle/css/bootstrap-toggle.min.css',
+ './node_modules/chartist/dist/chartist.min.css']);
- var opensourcepos4css = gulp.src('./node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css').pipe(cleanCSS({compatibility: 'ie8'}));
+ var opensourcepos4css = gulp.src('./node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css').pipe(cleanCSS({compatibility: 'ie8'}));
- var opensourcepos5css = gulp.src(['./node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css',
- './public/css/bootstrap.autocomplete.css',
- './public/css/invoice.css',
- './public/css/ospos.css',
- './public/css/ospos_print.css',
- './public/css/popupbox.css',
- './public/css/receipt.css',
- './public/css/register.css',
- './public/css/reports.css'
- ]).pipe(cleanCSS({compatibility: 'ie8'}));
+ var opensourcepos5css = gulp.src(['./node_modules/chartist-plugin-tooltips/dist/chartist-plugin-tooltip.css',
+ './public/css/bootstrap.autocomplete.css',
+ './public/css/invoice.css',
+ './public/css/ospos.css',
+ './public/css/ospos_print.css',
+ './public/css/popupbox.css',
+ './public/css/receipt.css',
+ './public/css/register.css',
+ './public/css/reports.css'
+ ]).pipe(cleanCSS({compatibility: 'ie8'}));
- var prodcss = series(opensourcepos1css, opensourcepos2css, opensourcepos3css, opensourcepos4css, opensourcepos5css)
- .pipe(concat('opensourcepos.min.css')).pipe(rev()).pipe(gulp.dest('public/resources'));
+ var prodcss = series(opensourcepos1css, opensourcepos2css, opensourcepos3css, opensourcepos4css, opensourcepos5css)
+ .pipe(concat('opensourcepos.min.css')).pipe(rev()).pipe(gulp.dest('public/resources'));
- return gulp.src('./app/Views/partial/header.php').pipe(inject(prodcss,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
+ return gulp.src('./app/Views/partial/header.php').pipe(inject(prodcss,{addRootSlash: false, ignorePath: '/public/', starttag: ''})).pipe(gulp.dest('./app/Views/partial'));
});
gulp.task('copy-fonts', function() {
- return pipeline(gulp.src('./node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.*', {encoding: false}),rev(),gulp.dest('public/resources'));
+ return pipeline(gulp.src('./node_modules/bootstrap/dist/fonts/glyphicons-halflings-regular.*', {encoding: false}),rev(),gulp.dest('public/resources'));
});
gulp.task('inject-login', function() {
- return pipeline(gulp.src('./app/Views/login.php'),
- inject(gulp.src('./public/css/login.min.css', {read: false}), {addRootSlash: false, ignorePath: '/public/', starttag: ''}),
- gulp.dest('./app/Views')
- );
+ return pipeline(gulp.src('./app/Views/login.php'),
+ inject(gulp.src('./public/css/login.min.css', {read: false}), {addRootSlash: false, ignorePath: '/public/', starttag: ''}),
+ gulp.dest('./app/Views')
+ );
});
gulp.task('update-licenses', function() {
- run('composer licenses --format=json --no-dev > public/license/composer.LICENSES').exec();
- return pipeline(gulp.src('LICENSE'),gulp.dest('public/license'));
+ run('composer licenses --format=json --no-dev > public/license/composer.LICENSES').exec();
+ return pipeline(gulp.src('LICENSE'),gulp.dest('public/license'));
});
gulp.task('build-database', function() {
- return gulp.src(['./app/Database/tables.sql','./app/Database/constraints.sql'])
- .pipe(header('-- >> This file is autogenerated from tables.sql and constraints.sql. Do not modify directly << --'))
- .pipe(concat('database.sql'))
- .pipe(gulp.dest('./app/Database'));
+ return gulp.src(['./app/Database/tables.sql','./app/Database/constraints.sql'])
+ .pipe(header('-- >> This file is autogenerated from tables.sql and constraints.sql. Do not modify directly << --'))
+ .pipe(concat('database.sql'))
+ .pipe(gulp.dest('./app/Database'));
});
// Run all required tasks
gulp.task('default',
- gulp.series('clean',
- 'copy-bootswatch',
- 'copy-bootswatch5',
- 'debug-js',
- 'prod-js',
- 'debug-css',
- 'prod-css',
- 'copy-fonts',
- 'inject-login',
- 'update-licenses',
- 'build-database'
- ));
+ gulp.series('clean',
+ 'copy-bootswatch',
+ 'copy-bootswatch5',
+ 'debug-js',
+ 'prod-js',
+ 'debug-css',
+ 'prod-css',
+ 'copy-fonts',
+ 'inject-login',
+ 'update-licenses',
+ 'build-database'
+ ));
diff --git a/package-lock.json b/package-lock.json
index fb9e26244..cd9efcb70 100644
--- a/package-lock.json
+++ b/package-lock.json
@@ -1,5243 +1,5243 @@
{
- "name": "@opensourcepos/opensourcepos",
- "version": "3.4.0",
- "lockfileVersion": 3,
- "requires": true,
- "packages": {
- "": {
- "name": "@opensourcepos/opensourcepos",
- "version": "3.4.0",
- "license": "MIT",
- "dependencies": {
- "bootstrap": "^3.4.1",
- "bootstrap-daterangepicker": "^2.1.27",
- "bootstrap-datetime-picker": "2.4.4",
- "bootstrap-notify": "^3.1.3",
- "bootstrap-select": "^1.13.18",
- "bootstrap-table": "^1.23.5",
- "bootstrap-tagsinput-2021": "^0.8.6",
- "bootstrap-toggle": "^2.2.2",
- "bootstrap3-dialog": "github:nakupanda/bootstrap3-dialog#master",
- "bootstrap5": "npm:bootstrap@^5.3.3",
- "bootswatch": "^3.4.1",
- "bootswatch5": "npm:bootswatch@^5.3.3",
- "chartist": "^0.11.4",
- "chartist-plugin-axistitle": "^0.0.7",
- "chartist-plugin-barlabels": "^0.0.5",
- "chartist-plugin-pointlabels": "^0.0.6",
- "chartist-plugin-tooltips": "^0.0.17",
- "clipboard": "^2.0.11",
- "coffeescript": "^2.7.0",
- "es6-promise": "^4.2.8",
- "file-saver": "^2.0.5",
- "html2canvas": "^1.4.1",
- "jasny-bootstrap": "^3.1.3",
- "jquery": "^3.7.1",
- "jquery-form": "^4.3.0",
- "jquery-ui-dist": "^1.12.1",
- "jquery-validation": "^1.19.5",
- "js-cookie": "^2.2.1",
- "jspdf": "^2.5.1",
- "jspdf-autotable": "^3.8.2",
- "npm-check-updates": "^17.1.14",
- "tableexport.jquery.plugin": "^1.30.0"
- },
- "devDependencies": {
- "gulp": "^5.0.0",
- "gulp-clean": "^0.4.0",
- "gulp-clean-css": "^4.3.0",
- "gulp-concat": "^2.6.1",
- "gulp-debug": "^5.0.1",
- "gulp-gzip": "^1.4.2",
- "gulp-header": "^2.0.9",
- "gulp-inject": "^5.0.5",
- "gulp-rename": "^2.0.0",
- "gulp-rev": "^10.0.0",
- "gulp-run": "^1.7.1",
- "gulp-tar": "^4.0.0",
- "gulp-uglify": "^3.0.2",
- "gulp-zip": "^6.1.0",
- "readable-stream": "^4.4.2",
- "stream-series": "^0.1.1"
- }
- },
- "node_modules/@babel/runtime": {
- "version": "7.24.4",
- "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
- "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
- "dependencies": {
- "regenerator-runtime": "^0.14.0"
- },
- "engines": {
- "node": ">=6.9.0"
- }
- },
- "node_modules/@gulpjs/messages": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz",
- "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/@gulpjs/to-absolute-glob": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz",
- "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==",
- "dev": true,
- "dependencies": {
- "is-negated-glob": "^1.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/@popperjs/core": {
- "version": "2.11.8",
- "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
- "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
- "peer": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/popperjs"
- }
- },
- "node_modules/@sec-ant/readable-stream": {
- "version": "0.4.1",
- "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
- "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/@swc/helpers": {
- "version": "0.3.17",
- "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
- "integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==",
- "dependencies": {
- "tslib": "^2.4.0"
- }
- },
- "node_modules/@types/expect": {
- "version": "1.20.4",
- "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz",
- "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==",
- "dev": true
- },
- "node_modules/@types/node": {
- "version": "20.12.7",
- "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
- "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
- "dev": true,
- "dependencies": {
- "undici-types": "~5.26.4"
- }
- },
- "node_modules/@types/raf": {
- "version": "3.4.3",
- "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
- "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
- "optional": true
- },
- "node_modules/@types/vinyl": {
- "version": "2.0.12",
- "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.12.tgz",
- "integrity": "sha512-Sr2fYMBUVGYq8kj3UthXFAu5UN6ZW+rYr4NACjZQJvHvj+c8lYv0CahmZ2P/r7iUkN44gGUBwqxZkrKXYPb7cw==",
- "dev": true,
- "dependencies": {
- "@types/expect": "^1.20.4",
- "@types/node": "*"
- }
- },
- "node_modules/abort-controller": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
- "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
- "dev": true,
- "dependencies": {
- "event-target-shim": "^5.0.0"
- },
- "engines": {
- "node": ">=6.5"
- }
- },
- "node_modules/adler-32": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
- "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/ansi-colors": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
- "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
- "dev": true,
- "dependencies": {
- "ansi-wrap": "^0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-cyan": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
- "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==",
- "dev": true,
- "dependencies": {
- "ansi-wrap": "0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-gray": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
- "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==",
- "dev": true,
- "dependencies": {
- "ansi-wrap": "0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-red": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
- "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==",
- "dev": true,
- "dependencies": {
- "ansi-wrap": "0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-regex": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
- "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-styles": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
- "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ansi-wrap": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
- "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/any-promise": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
- "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
- "dev": true
- },
- "node_modules/anymatch": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
- "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
- "dev": true,
- "dependencies": {
- "normalize-path": "^3.0.0",
- "picomatch": "^2.0.4"
- },
- "engines": {
- "node": ">= 8"
- }
- },
- "node_modules/archiver": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.2.tgz",
- "integrity": "sha512-UQ/2nW7NMl1G+1UnrLypQw1VdT9XZg/ECcKPq7l+STzStrSivFIXIp34D8M5zeNGW5NoOupdYCHv6VySCPNNlw==",
- "dev": true,
- "dependencies": {
- "archiver-utils": "^4.0.1",
- "async": "^3.2.4",
- "buffer-crc32": "^0.2.1",
- "readable-stream": "^3.6.0",
- "readdir-glob": "^1.1.2",
- "tar-stream": "^3.0.0",
- "zip-stream": "^5.0.1"
- },
- "engines": {
- "node": ">= 12.0.0"
- }
- },
- "node_modules/archiver-utils": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz",
- "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==",
- "dev": true,
- "dependencies": {
- "glob": "^8.0.0",
- "graceful-fs": "^4.2.0",
- "lazystream": "^1.0.0",
- "lodash": "^4.17.15",
- "normalize-path": "^3.0.0",
- "readable-stream": "^3.6.0"
- },
- "engines": {
- "node": ">= 12.0.0"
- }
- },
- "node_modules/archiver-utils/node_modules/glob": {
- "version": "8.1.0",
- "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
- "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^5.0.1",
- "once": "^1.3.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/archiver-utils/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/archiver-utils/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/archiver/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/arr-diff": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
- "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/arr-flatten": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
- "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/arr-union": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
- "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/array-buffer-byte-length": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
- "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
- "dependencies": {
- "call-bind": "^1.0.5",
- "is-array-buffer": "^3.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/array-differ": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
- "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/array-each": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
- "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/array-slice": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
- "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/array-uniq": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
- "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/arrify": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
- "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/assign-symbols": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
- "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/async": {
- "version": "3.2.5",
- "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
- "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==",
- "dev": true
- },
- "node_modules/async-done": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz",
- "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==",
- "dev": true,
- "dependencies": {
- "end-of-stream": "^1.4.4",
- "once": "^1.4.0",
- "stream-exhaust": "^1.0.2"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/async-settle": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz",
- "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==",
- "dev": true,
- "dependencies": {
- "async-done": "^2.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/atob": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
- "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
- "bin": {
- "atob": "bin/atob.js"
- },
- "engines": {
- "node": ">= 4.5.0"
- }
- },
- "node_modules/available-typed-arrays": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
- "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
- "dependencies": {
- "possible-typed-array-names": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/b4a": {
- "version": "1.6.6",
- "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
- "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==",
- "dev": true
- },
- "node_modules/bach": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz",
- "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==",
- "dev": true,
- "dependencies": {
- "async-done": "^2.0.0",
- "async-settle": "^2.0.0",
- "now-and-later": "^3.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/balanced-match": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
- "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
- "dev": true
- },
- "node_modules/bare-events": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
- "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
- "dev": true,
- "optional": true
- },
- "node_modules/base64-arraybuffer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
- "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
- "engines": {
- "node": ">= 0.6.0"
- }
- },
- "node_modules/base64-js": {
- "version": "1.5.1",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
- "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/beeper": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
- "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/binary-extensions": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
- "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
- "dev": true,
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/bl": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
- "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
- "dev": true,
- "dependencies": {
- "buffer": "^6.0.3",
- "inherits": "^2.0.4",
- "readable-stream": "^3.4.0"
- }
- },
- "node_modules/bl/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/bootstrap": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
- "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==",
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/bootstrap-daterangepicker": {
- "version": "2.1.30",
- "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-2.1.30.tgz",
- "integrity": "sha512-lZAmyQxwsthEbsIBKl2KVcUca+b/O8uAJxxY8AvlsCYF9dQlIY7WjskuqMJ3b/1YdXUgxHN/R6HFdVVNFSgeVQ==",
- "dependencies": {
- "jquery": ">=1.10",
- "moment": "^2.9.0"
- }
- },
- "node_modules/bootstrap-datetime-picker": {
- "version": "2.4.4",
- "resolved": "https://registry.npmjs.org/bootstrap-datetime-picker/-/bootstrap-datetime-picker-2.4.4.tgz",
- "integrity": "sha512-TTknlrqoJ7DcJJpkmvg+TneUiWNG65gfjHYbTM5MpJ60DGWmcQJWN7+6eU78WvqxE6Dz/yKmeyLDEzzWVgw43A=="
- },
- "node_modules/bootstrap-notify": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/bootstrap-notify/-/bootstrap-notify-3.1.3.tgz",
- "integrity": "sha512-cnTactFVG8aHri03+RmuZ5sl9VcA+jTTM/mTdEOQN+R1V9u4YBu8Ca+Pf6NGeVfieGv0Z6CxK8FzlWg59omzyg=="
- },
- "node_modules/bootstrap-select": {
- "version": "1.13.18",
- "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.13.18.tgz",
- "integrity": "sha512-V1IzK4rxBq5FrJtkzSH6RmFLFBsjx50byFbfAf8jYyXROWs7ZpprGjdHeoyq2HSsHyjJhMMwjsQhRoYAfxCGow==",
- "peerDependencies": {
- "bootstrap": ">=3.0.0",
- "jquery": "1.9.1 - 3"
- }
- },
- "node_modules/bootstrap-table": {
- "version": "1.23.5",
- "resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.5.tgz",
- "integrity": "sha512-9WByoSpJvA73gi2YYIlX6IWR74oZtBmSixul/Th8FTBtBd/kZRpbKESGTjhA3BA3AYTnfyY8Iy1KeRWPlV2GWQ==",
- "license": "MIT",
- "peerDependencies": {
- "jquery": "3"
- }
- },
- "node_modules/bootstrap-tagsinput-2021": {
- "version": "0.8.6",
- "resolved": "https://registry.npmjs.org/bootstrap-tagsinput-2021/-/bootstrap-tagsinput-2021-0.8.6.tgz",
- "integrity": "sha512-/ZbR3Hl6BtpbuVuoXPxiyoh4a4fKyoyKn4pFXyL4fGEEQ3uwPS4/urrJ5O9ew2WkfBkJUdHnCLtNuVeUlz6HoA=="
- },
- "node_modules/bootstrap-toggle": {
- "version": "2.2.2",
- "resolved": "https://registry.npmjs.org/bootstrap-toggle/-/bootstrap-toggle-2.2.2.tgz",
- "integrity": "sha512-AkYD/i3NGCEksIb/PmmUrrxpa0DYi7Si30e9Ldhou2t1HTd9npoXUsxJJjFPvlV7iLUptlysWTcYD7i3DKV6qg=="
- },
- "node_modules/bootstrap3-dialog": {
- "version": "1.35.4",
- "resolved": "git+ssh://git@github.com/nakupanda/bootstrap3-dialog.git#a491a98c97921114883ad44e5715fe28396dbaea"
- },
- "node_modules/bootstrap5": {
- "name": "bootstrap",
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
- "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/twbs"
- },
- {
- "type": "opencollective",
- "url": "https://opencollective.com/bootstrap"
- }
- ],
- "peerDependencies": {
- "@popperjs/core": "^2.11.8"
- }
- },
- "node_modules/bootswatch": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-3.4.1.tgz",
- "integrity": "sha512-0hL4A8OUiqABgPipGrojf/hyhr5RS257xCNARlbK34HaMfhV5fXvwEooN4/ri9+jgX47J4Wg24ZPmfZ2xD2cKw==",
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/bootswatch5": {
- "name": "bootswatch",
- "version": "5.3.3",
- "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.3.3.tgz",
- "integrity": "sha512-cJLhobnZsVCelU7zdH/L7wpcXAyUoTX4/5l2dWQ0JXgaVK80BdTQNU/ImWwoyIGBeyms4iQDAdNtOfPQZf0Atg=="
- },
- "node_modules/brace-expansion": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
- "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0"
- }
- },
- "node_modules/braces": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
- "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
- "dev": true,
- "dependencies": {
- "fill-range": "^7.1.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/brotli": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
- "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
- "dependencies": {
- "base64-js": "^1.1.2"
- }
- },
- "node_modules/btoa": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
- "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
- "bin": {
- "btoa": "bin/btoa.js"
- },
- "engines": {
- "node": ">= 0.4.0"
- }
- },
- "node_modules/buffer": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
- "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ],
- "dependencies": {
- "base64-js": "^1.3.1",
- "ieee754": "^1.2.1"
- }
- },
- "node_modules/buffer-crc32": {
- "version": "0.2.13",
- "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
- "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
- "dev": true,
- "engines": {
- "node": "*"
- }
- },
- "node_modules/bytes": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
- "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
- "dev": true,
- "engines": {
- "node": ">= 0.8"
- }
- },
- "node_modules/call-bind": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
- "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
- "dependencies": {
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "set-function-length": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/canvg": {
- "version": "3.0.10",
- "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
- "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
- "optional": true,
- "dependencies": {
- "@babel/runtime": "^7.12.5",
- "@types/raf": "^3.4.0",
- "core-js": "^3.8.3",
- "raf": "^3.4.1",
- "regenerator-runtime": "^0.13.7",
- "rgbcolor": "^1.0.1",
- "stackblur-canvas": "^2.0.0",
- "svg-pathdata": "^6.0.3"
- },
- "engines": {
- "node": ">=10.0.0"
- }
- },
- "node_modules/canvg/node_modules/regenerator-runtime": {
- "version": "0.13.11",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
- "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
- "optional": true
- },
- "node_modules/cfb": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
- "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
- "dependencies": {
- "adler-32": "~1.3.0",
- "crc-32": "~1.2.0"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/chalk": {
- "version": "5.3.0",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
- "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
- "dev": true,
- "engines": {
- "node": "^12.17.0 || ^14.13 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/chartist": {
- "version": "0.11.4",
- "resolved": "https://registry.npmjs.org/chartist/-/chartist-0.11.4.tgz",
- "integrity": "sha512-H4AimxaUD738/u9Mq8t27J4lh6STsLi4BQHt65nOtpLk3xyrBPaLiLMrHw7/WV9CmsjGA02WihjuL5qpSagLYw==",
- "engines": {
- "node": ">=4.6.0"
- }
- },
- "node_modules/chartist-plugin-axistitle": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/chartist-plugin-axistitle/-/chartist-plugin-axistitle-0.0.7.tgz",
- "integrity": "sha512-qFG7R/qiZZyCn/gx9WJpMcnyhE0LIpGBxDnPpYtzY5cG53fHBkvJDsAEHEFFfO1l/RHI0G8oN9fpoUD/BMeiFA==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/chartist-plugin-barlabels": {
- "version": "0.0.5",
- "resolved": "https://registry.npmjs.org/chartist-plugin-barlabels/-/chartist-plugin-barlabels-0.0.5.tgz",
- "integrity": "sha512-QJpFB37jCD0pyDqb0/FSnaXXqUhnzabN1gULkBqK0VOoC/KerihR5EomNdOPnjZoEm8T9gRSNbxGGObZKJFKiw==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/chartist-plugin-pointlabels": {
- "version": "0.0.6",
- "resolved": "https://registry.npmjs.org/chartist-plugin-pointlabels/-/chartist-plugin-pointlabels-0.0.6.tgz",
- "integrity": "sha512-DUemVUBWAN0qAHBUMXKKLrDCsUL1qWWwN+EfxN8gpftgXSheMiYeq83uHoHyp4X+W5Pz/aUWBf3N/HJwj+eRFw==",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/chartist-plugin-tooltips": {
- "version": "0.0.17",
- "resolved": "https://registry.npmjs.org/chartist-plugin-tooltips/-/chartist-plugin-tooltips-0.0.17.tgz",
- "integrity": "sha512-frXv269MyRHfuhyZILdTTsNG4PP3+Ab0NkysdnMk73aN4w76oWarsGguuciYzZawKrctp8RZzU/W44A4+Y4vOg==",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/chokidar": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
- "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
- "dev": true,
- "dependencies": {
- "anymatch": "~3.1.2",
- "braces": "~3.0.2",
- "glob-parent": "~5.1.2",
- "is-binary-path": "~2.1.0",
- "is-glob": "~4.0.1",
- "normalize-path": "~3.0.0",
- "readdirp": "~3.6.0"
- },
- "engines": {
- "node": ">= 8.10.0"
- },
- "funding": {
- "url": "https://paulmillr.com/funding/"
- },
- "optionalDependencies": {
- "fsevents": "~2.3.2"
- }
- },
- "node_modules/clean-css": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
- "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
- "dev": true,
- "dependencies": {
- "source-map": "~0.6.0"
- },
- "engines": {
- "node": ">= 4.0"
- }
- },
- "node_modules/clipboard": {
- "version": "2.0.11",
- "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
- "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
- "dependencies": {
- "good-listener": "^1.2.2",
- "select": "^1.1.2",
- "tiny-emitter": "^2.0.0"
- }
- },
- "node_modules/cliui": {
- "version": "7.0.4",
- "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
- "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
- "dev": true,
- "dependencies": {
- "string-width": "^4.2.0",
- "strip-ansi": "^6.0.0",
- "wrap-ansi": "^7.0.0"
- }
- },
- "node_modules/cliui/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/cliui/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/cliui/node_modules/wrap-ansi": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
- "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.0.0",
- "string-width": "^4.1.0",
- "strip-ansi": "^6.0.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
- }
- },
- "node_modules/clone": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
- "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/clone-buffer": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
- "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==",
- "dev": true,
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/clone-stats": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
- "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
- "dev": true
- },
- "node_modules/cloneable-readable": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
- "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.1",
- "process-nextick-args": "^2.0.0",
- "readable-stream": "^2.3.5"
- }
- },
- "node_modules/cloneable-readable/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dev": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/cloneable-readable/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/cloneable-readable/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/codepage": {
- "version": "1.15.0",
- "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
- "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/coffeescript": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz",
- "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==",
- "bin": {
- "cake": "bin/cake",
- "coffee": "bin/coffee"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/color-convert": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
- "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
- "dev": true,
- "dependencies": {
- "color-name": "~1.1.4"
- },
- "engines": {
- "node": ">=7.0.0"
- }
- },
- "node_modules/color-name": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
- "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
- "dev": true
- },
- "node_modules/color-support": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
- "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
- "dev": true,
- "bin": {
- "color-support": "bin.js"
- }
- },
- "node_modules/compress-commons": {
- "version": "5.0.3",
- "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.3.tgz",
- "integrity": "sha512-/UIcLWvwAQyVibgpQDPtfNM3SvqN7G9elAPAV7GM0L53EbNWwWiCsWtK8Fwed/APEbptPHXs5PuW+y8Bq8lFTA==",
- "dev": true,
- "dependencies": {
- "crc-32": "^1.2.0",
- "crc32-stream": "^5.0.0",
- "normalize-path": "^3.0.0",
- "readable-stream": "^3.6.0"
- },
- "engines": {
- "node": ">= 12.0.0"
- }
- },
- "node_modules/compress-commons/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/concat-map": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
- "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
- "dev": true
- },
- "node_modules/concat-with-sourcemaps": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
- "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
- "dev": true,
- "dependencies": {
- "source-map": "^0.6.1"
- }
- },
- "node_modules/convert-source-map": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
- "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
- "dev": true
- },
- "node_modules/copy-props": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz",
- "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==",
- "dev": true,
- "dependencies": {
- "each-props": "^3.0.0",
- "is-plain-object": "^5.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/core-js": {
- "version": "3.37.0",
- "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz",
- "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==",
- "hasInstallScript": true,
- "optional": true,
- "funding": {
- "type": "opencollective",
- "url": "https://opencollective.com/core-js"
- }
- },
- "node_modules/core-util-is": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
- "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
- "dev": true
- },
- "node_modules/crc-32": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
- "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
- "bin": {
- "crc32": "bin/crc32.njs"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/crc32-stream": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.1.tgz",
- "integrity": "sha512-lO1dFui+CEUh/ztYIpgpKItKW9Bb4NWakCRJrnqAbFIYD+OZAwb2VfD5T5eXMw2FNcsDHkQcNl/Wh3iVXYwU6g==",
- "dev": true,
- "dependencies": {
- "crc-32": "^1.2.0",
- "readable-stream": "^3.4.0"
- },
- "engines": {
- "node": ">= 12.0.0"
- }
- },
- "node_modules/crc32-stream/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/crypto-js": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
- "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
- },
- "node_modules/css-line-break": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
- "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
- "dependencies": {
- "utrie": "^1.0.2"
- }
- },
- "node_modules/dateformat": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
- "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/deep-equal": {
- "version": "2.2.3",
- "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
- "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
- "dependencies": {
- "array-buffer-byte-length": "^1.0.0",
- "call-bind": "^1.0.5",
- "es-get-iterator": "^1.1.3",
- "get-intrinsic": "^1.2.2",
- "is-arguments": "^1.1.1",
- "is-array-buffer": "^3.0.2",
- "is-date-object": "^1.0.5",
- "is-regex": "^1.1.4",
- "is-shared-array-buffer": "^1.0.2",
- "isarray": "^2.0.5",
- "object-is": "^1.1.5",
- "object-keys": "^1.1.1",
- "object.assign": "^4.1.4",
- "regexp.prototype.flags": "^1.5.1",
- "side-channel": "^1.0.4",
- "which-boxed-primitive": "^1.0.2",
- "which-collection": "^1.0.1",
- "which-typed-array": "^1.1.13"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/deep-equal/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
- },
- "node_modules/define-data-property": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
- "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
- "dependencies": {
- "es-define-property": "^1.0.0",
- "es-errors": "^1.3.0",
- "gopd": "^1.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/define-properties": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
- "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
- "dependencies": {
- "define-data-property": "^1.0.1",
- "has-property-descriptors": "^1.0.0",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/delegate": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
- "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
- },
- "node_modules/detect-file": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
- "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/dfa": {
- "version": "1.2.0",
- "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
- "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
- },
- "node_modules/dompurify": {
- "version": "2.5.6",
- "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz",
- "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==",
- "optional": true
- },
- "node_modules/duplexer2": {
- "version": "0.0.2",
- "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
- "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==",
- "dev": true,
- "license": "BSD",
- "dependencies": {
- "readable-stream": "~1.1.9"
- }
- },
- "node_modules/duplexer2/node_modules/isarray": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
- "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/duplexer2/node_modules/readable-stream": {
- "version": "1.1.14",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
- "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.1",
- "isarray": "0.0.1",
- "string_decoder": "~0.10.x"
- }
- },
- "node_modules/duplexer2/node_modules/string_decoder": {
- "version": "0.10.31",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
- "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/each-props": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz",
- "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^5.0.0",
- "object.defaults": "^1.1.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/easy-transform-stream": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/easy-transform-stream/-/easy-transform-stream-1.0.1.tgz",
- "integrity": "sha512-ktkaa6XR7COAR3oj02CF3IOgz2m1hCaY3SfzvKT4Svt2MhHw9XCt+ncJNWfe2TGz31iqzNGZ8spdKQflj+Rlog==",
- "dev": true,
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/emoji-regex": {
- "version": "8.0.0",
- "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
- "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
- "dev": true
- },
- "node_modules/end-of-stream": {
- "version": "1.4.4",
- "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
- "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
- "dev": true,
- "dependencies": {
- "once": "^1.4.0"
- }
- },
- "node_modules/es-define-property": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
- "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
- "dependencies": {
- "get-intrinsic": "^1.2.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-errors": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
- "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/es-get-iterator": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
- "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.1.3",
- "has-symbols": "^1.0.3",
- "is-arguments": "^1.1.1",
- "is-map": "^2.0.2",
- "is-set": "^2.0.2",
- "is-string": "^1.0.7",
- "isarray": "^2.0.5",
- "stop-iteration-iterator": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/es-get-iterator/node_modules/isarray": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
- "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
- },
- "node_modules/es6-promise": {
- "version": "4.2.8",
- "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
- "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
- },
- "node_modules/escalade": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
- "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/escape-string-regexp": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
- "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/event-target-shim": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
- "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/events": {
- "version": "3.3.0",
- "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
- "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
- "dev": true,
- "engines": {
- "node": ">=0.8.x"
- }
- },
- "node_modules/expand-tilde": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
- "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
- "dev": true,
- "dependencies": {
- "homedir-polyfill": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/extend": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
- "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
- "dev": true
- },
- "node_modules/extend-shallow": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
- "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
- "dev": true,
- "dependencies": {
- "assign-symbols": "^1.0.0",
- "is-extendable": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/fancy-log": {
- "version": "1.3.3",
- "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
- "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
- "dev": true,
- "dependencies": {
- "ansi-gray": "^0.1.1",
- "color-support": "^1.1.3",
- "parse-node-version": "^1.0.0",
- "time-stamp": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/fast-fifo": {
- "version": "1.3.2",
- "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
- "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
- "dev": true
- },
- "node_modules/fast-levenshtein": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz",
- "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==",
- "dev": true,
- "dependencies": {
- "fastest-levenshtein": "^1.0.7"
- }
- },
- "node_modules/fastest-levenshtein": {
- "version": "1.0.16",
- "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
- "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
- "dev": true,
- "engines": {
- "node": ">= 4.9.1"
- }
- },
- "node_modules/fastq": {
- "version": "1.17.1",
- "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
- "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
- "dev": true,
- "dependencies": {
- "reusify": "^1.0.4"
- }
- },
- "node_modules/fflate": {
- "version": "0.4.8",
- "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
- "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
- },
- "node_modules/file-saver": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
- "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
- },
- "node_modules/fill-range": {
- "version": "7.1.1",
- "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
- "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
- "dev": true,
- "dependencies": {
- "to-regex-range": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/findup-sync": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz",
- "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==",
- "dev": true,
- "dependencies": {
- "detect-file": "^1.0.0",
- "is-glob": "^4.0.3",
- "micromatch": "^4.0.4",
- "resolve-dir": "^1.0.1"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/fined": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz",
- "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==",
- "dev": true,
- "dependencies": {
- "expand-tilde": "^2.0.2",
- "is-plain-object": "^5.0.0",
- "object.defaults": "^1.1.0",
- "object.pick": "^1.3.0",
- "parse-filepath": "^1.0.2"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/first-chunk-stream": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-5.0.0.tgz",
- "integrity": "sha512-WdHo4ejd2cG2Dl+sLkW79SctU7mUQDfr4s1i26ffOZRs5mgv+BRttIM9gwcq0rDbemo0KlpVPaa3LBVLqPXzcQ==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/flagged-respawn": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz",
- "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/fontkit": {
- "version": "1.9.0",
- "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.9.0.tgz",
- "integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==",
- "dependencies": {
- "@swc/helpers": "^0.3.13",
- "brotli": "^1.3.2",
- "clone": "^2.1.2",
- "deep-equal": "^2.0.5",
- "dfa": "^1.2.0",
- "restructure": "^2.0.1",
- "tiny-inflate": "^1.0.3",
- "unicode-properties": "^1.3.1",
- "unicode-trie": "^2.0.0"
- }
- },
- "node_modules/for-each": {
- "version": "0.3.3",
- "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
- "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
- "dependencies": {
- "is-callable": "^1.1.3"
- }
- },
- "node_modules/for-in": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
- "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/for-own": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
- "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==",
- "dev": true,
- "dependencies": {
- "for-in": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/frac": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
- "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/fs-mkdirp-stream": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz",
- "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==",
- "dev": true,
- "dependencies": {
- "graceful-fs": "^4.2.8",
- "streamx": "^2.12.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/fs.realpath": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
- "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
- "dev": true
- },
- "node_modules/fsevents": {
- "version": "2.3.3",
- "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
- "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
- "dev": true,
- "hasInstallScript": true,
- "optional": true,
- "os": [
- "darwin"
- ],
- "engines": {
- "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
- }
- },
- "node_modules/function-bind": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
- "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/functions-have-names": {
- "version": "1.2.3",
- "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
- "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-caller-file": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
- "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
- "dev": true,
- "engines": {
- "node": "6.* || 8.* || >= 10.*"
- }
- },
- "node_modules/get-intrinsic": {
- "version": "1.2.4",
- "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
- "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
- "dependencies": {
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "has-proto": "^1.0.1",
- "has-symbols": "^1.0.3",
- "hasown": "^2.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/get-own-enumerable-keys": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz",
- "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==",
- "dev": true,
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/get-stream": {
- "version": "9.0.1",
- "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
- "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@sec-ant/readable-stream": "^0.4.1",
- "is-stream": "^4.0.1"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/glob-parent": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
- "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/glob-stream": {
- "version": "8.0.2",
- "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz",
- "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==",
- "dev": true,
- "dependencies": {
- "@gulpjs/to-absolute-glob": "^4.0.0",
- "anymatch": "^3.1.3",
- "fastq": "^1.13.0",
- "glob-parent": "^6.0.2",
- "is-glob": "^4.0.3",
- "is-negated-glob": "^1.0.0",
- "normalize-path": "^3.0.0",
- "streamx": "^2.12.5"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/glob-stream/node_modules/glob-parent": {
- "version": "6.0.2",
- "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
- "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
- "dev": true,
- "dependencies": {
- "is-glob": "^4.0.3"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/glob-watcher": {
- "version": "6.0.0",
- "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz",
- "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==",
- "dev": true,
- "dependencies": {
- "async-done": "^2.0.0",
- "chokidar": "^3.5.3"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/global-modules": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
- "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
- "dev": true,
- "dependencies": {
- "global-prefix": "^1.0.1",
- "is-windows": "^1.0.1",
- "resolve-dir": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/global-prefix": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
- "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
- "dev": true,
- "dependencies": {
- "expand-tilde": "^2.0.2",
- "homedir-polyfill": "^1.0.1",
- "ini": "^1.3.4",
- "is-windows": "^1.0.1",
- "which": "^1.2.14"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/global-prefix/node_modules/ini": {
- "version": "1.3.8",
- "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
- "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
- "dev": true
- },
- "node_modules/global-prefix/node_modules/which": {
- "version": "1.3.1",
- "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
- "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
- "dev": true,
- "dependencies": {
- "isexe": "^2.0.0"
- },
- "bin": {
- "which": "bin/which"
- }
- },
- "node_modules/glogg": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
- "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
- "dev": true,
- "dependencies": {
- "sparkles": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/good-listener": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
- "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
- "dependencies": {
- "delegate": "^3.1.2"
- }
- },
- "node_modules/gopd": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
- "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
- "dependencies": {
- "get-intrinsic": "^1.1.3"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/graceful-fs": {
- "version": "4.2.11",
- "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
- "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
- "dev": true
- },
- "node_modules/group-array": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/group-array/-/group-array-1.0.0.tgz",
- "integrity": "sha512-PJresALe5TUzSIcdWKLdAKcdUDxv8du2EGueShgAL2xknbcTo5Bk1xbNaNhxpWxxAx/SV7N+5S0UyK7XV0+QhA==",
- "dev": true,
- "dependencies": {
- "arr-flatten": "^1.1.0",
- "for-own": "^1.0.0",
- "get-value": "^3.0.1",
- "kind-of": "^6.0.2",
- "split-string": "^6.1.0",
- "union-value": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/group-array/node_modules/get-value": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz",
- "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/group-array/node_modules/kind-of": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
- "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/group-array/node_modules/split-string": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/split-string/-/split-string-6.1.0.tgz",
- "integrity": "sha512-9UBdnmnvx2NLLd4bMs7CEKK+wSzbujVv3ONyorkP1o8M3pVJQtXDO1cN19xD1JJs6ltOrtPrkUND0HzLSinUcA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/gulp": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz",
- "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==",
- "dev": true,
- "dependencies": {
- "glob-watcher": "^6.0.0",
- "gulp-cli": "^3.0.0",
- "undertaker": "^2.0.0",
- "vinyl-fs": "^4.0.0"
- },
- "bin": {
- "gulp": "bin/gulp.js"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulp-clean": {
- "version": "0.4.0",
- "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz",
- "integrity": "sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==",
- "dev": true,
- "dependencies": {
- "fancy-log": "^1.3.2",
- "plugin-error": "^0.1.2",
- "rimraf": "^2.6.2",
- "through2": "^2.0.3",
- "vinyl": "^2.1.0"
- },
- "engines": {
- "node": ">=0.9"
- }
- },
- "node_modules/gulp-clean-css": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz",
- "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==",
- "dev": true,
- "dependencies": {
- "clean-css": "4.2.3",
- "plugin-error": "1.0.1",
- "through2": "3.0.1",
- "vinyl-sourcemaps-apply": "0.2.1"
- }
- },
- "node_modules/gulp-clean-css/node_modules/arr-union": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
- "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/gulp-clean-css/node_modules/plugin-error": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
- "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^1.0.1",
- "arr-diff": "^4.0.0",
- "arr-union": "^3.1.0",
- "extend-shallow": "^3.0.2"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/gulp-clean-css/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/gulp-clean-css/node_modules/through2": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
- "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
- "dev": true,
- "dependencies": {
- "readable-stream": "2 || 3"
- }
- },
- "node_modules/gulp-cli": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz",
- "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==",
- "dev": true,
- "dependencies": {
- "@gulpjs/messages": "^1.1.0",
- "chalk": "^4.1.2",
- "copy-props": "^4.0.0",
- "gulplog": "^2.2.0",
- "interpret": "^3.1.1",
- "liftoff": "^5.0.0",
- "mute-stdout": "^2.0.0",
- "replace-homedir": "^2.0.0",
- "semver-greatest-satisfied-range": "^2.0.0",
- "string-width": "^4.2.3",
- "v8flags": "^4.0.0",
- "yargs": "^16.2.0"
- },
- "bin": {
- "gulp": "bin/gulp.js"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulp-cli/node_modules/ansi-styles": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
- "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
- "dev": true,
- "dependencies": {
- "color-convert": "^2.0.1"
- },
- "engines": {
- "node": ">=8"
- },
- "funding": {
- "url": "https://github.com/chalk/ansi-styles?sponsor=1"
- }
- },
- "node_modules/gulp-cli/node_modules/chalk": {
- "version": "4.1.2",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
- "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
- "dev": true,
- "dependencies": {
- "ansi-styles": "^4.1.0",
- "supports-color": "^7.1.0"
- },
- "engines": {
- "node": ">=10"
- },
- "funding": {
- "url": "https://github.com/chalk/chalk?sponsor=1"
- }
- },
- "node_modules/gulp-cli/node_modules/glogg": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz",
- "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==",
- "dev": true,
- "dependencies": {
- "sparkles": "^2.1.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/gulp-cli/node_modules/gulplog": {
- "version": "2.2.0",
- "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz",
- "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==",
- "dev": true,
- "dependencies": {
- "glogg": "^2.2.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/gulp-cli/node_modules/sparkles": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz",
- "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/gulp-concat": {
- "version": "2.6.1",
- "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
- "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==",
- "dev": true,
- "dependencies": {
- "concat-with-sourcemaps": "^1.0.0",
- "through2": "^2.0.0",
- "vinyl": "^2.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/gulp-debug": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/gulp-debug/-/gulp-debug-5.0.1.tgz",
- "integrity": "sha512-2MZFfzg95/6JlfKchX+ZY+6Awn2KoEvg4GeJh+uVi/lwD3W4LEeLDo3SfQEFBF9X5jhQYgUazKD/xyxd2dG9cw==",
- "dev": true,
- "dependencies": {
- "chalk": "^5.3.0",
- "gulp-plugin-extras": "^0.3.0",
- "plur": "^5.1.0",
- "stringify-object": "^5.0.0",
- "tildify": "^3.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- },
- "peerDependencies": {
- "gulp": ">=4"
- },
- "peerDependenciesMeta": {
- "gulp": {
- "optional": true
- }
- }
- },
- "node_modules/gulp-gzip": {
- "version": "1.4.2",
- "resolved": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz",
- "integrity": "sha512-ZIxfkUwk2XmZPTT9pPHrHUQlZMyp9nPhg2sfoeN27mBGpi7OaHnOD+WCN41NXjfJQ69lV1nQ9LLm1hYxx4h3UQ==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^1.0.1",
- "bytes": "^3.0.0",
- "fancy-log": "^1.3.2",
- "plugin-error": "^1.0.0",
- "stream-to-array": "^2.3.0",
- "through2": "^2.0.3"
- },
- "engines": {
- "node": ">= 0.10.0"
- }
- },
- "node_modules/gulp-gzip/node_modules/arr-union": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
- "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/gulp-gzip/node_modules/plugin-error": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
- "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^1.0.1",
- "arr-diff": "^4.0.0",
- "arr-union": "^3.1.0",
- "extend-shallow": "^3.0.2"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/gulp-header": {
- "version": "2.0.9",
- "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz",
- "integrity": "sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==",
- "dev": true,
- "dependencies": {
- "concat-with-sourcemaps": "^1.1.0",
- "lodash.template": "^4.5.0",
- "map-stream": "0.0.7",
- "through2": "^2.0.0"
- }
- },
- "node_modules/gulp-inject": {
- "version": "5.0.5",
- "resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-5.0.5.tgz",
- "integrity": "sha512-5bGMjqleXUHPu4CI1pnVzHtwyMy+Zt8EMo1RFwNsOpidPxwjFwyLgmsRZWGMMI8UenJMJRjURqwznfFmqb5wgw==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^4.1.1",
- "arrify": "^2.0.1",
- "escape-string-regexp": "^2.0.0",
- "fancy-log": "^1.3.3",
- "group-array": "^1.0.0",
- "plugin-error": "^1.0.1",
- "stream-to-array": "^2.3.0",
- "through2": "^3.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/gulp-inject/node_modules/ansi-colors": {
- "version": "4.1.3",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
- "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
- "dev": true,
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/gulp-inject/node_modules/arr-union": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
- "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/gulp-inject/node_modules/plugin-error": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
- "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^1.0.1",
- "arr-diff": "^4.0.0",
- "arr-union": "^3.1.0",
- "extend-shallow": "^3.0.2"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/gulp-inject/node_modules/plugin-error/node_modules/ansi-colors": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
- "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
- "dev": true,
- "dependencies": {
- "ansi-wrap": "^0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/gulp-inject/node_modules/readable-stream": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
- "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.3",
- "string_decoder": "^1.1.1",
- "util-deprecate": "^1.0.1"
- },
- "engines": {
- "node": ">= 6"
- }
- },
- "node_modules/gulp-inject/node_modules/through2": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
- "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
- "dev": true,
- "dependencies": {
- "inherits": "^2.0.4",
- "readable-stream": "2 || 3"
- }
- },
- "node_modules/gulp-plugin-extras": {
- "version": "0.3.0",
- "resolved": "https://registry.npmjs.org/gulp-plugin-extras/-/gulp-plugin-extras-0.3.0.tgz",
- "integrity": "sha512-I/kOBSpo61QsGQZcqozZYEnDseKvpudUafVVWDLYgBFAUJ37kW5R8Sjw9cMYzpGyPUfEYOeoY4p+dkfLqgyJUQ==",
- "dev": true,
- "dependencies": {
- "@types/vinyl": "^2.0.9",
- "chalk": "^5.3.0",
- "easy-transform-stream": "^1.0.1"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/gulp-rename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz",
- "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==",
- "dev": true,
- "engines": {
- "node": ">=4"
- }
- },
- "node_modules/gulp-rev": {
- "version": "10.0.0",
- "resolved": "https://registry.npmjs.org/gulp-rev/-/gulp-rev-10.0.0.tgz",
- "integrity": "sha512-5mP6oOGp1DUzBQuiy9IrtyAWHWUOz2n1qLUHfo7LU0p111t7sTkUhKW01b70B2MsDWgScTdz6sGLg76KCbqclw==",
- "dev": true,
- "dependencies": {
- "easy-transform-stream": "^1.0.0",
- "modify-filename": "^2.0.0",
- "plugin-error": "^2.0.1",
- "rev-hash": "^4.0.0",
- "rev-path": "^3.0.0",
- "sort-keys": "^5.0.0",
- "vinyl": "^3.0.0",
- "vinyl-file": "^5.0.0"
- },
- "engines": {
- "node": ">=16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- },
- "peerDependencies": {
- "gulp": ">=4"
- },
- "peerDependenciesMeta": {
- "gulp": {
- "optional": true
- }
- }
- },
- "node_modules/gulp-rev/node_modules/plugin-error": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz",
- "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==",
- "dev": true,
- "dependencies": {
- "ansi-colors": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulp-rev/node_modules/replace-ext": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
- "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/gulp-rev/node_modules/vinyl": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
- "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.2",
- "clone-stats": "^1.0.0",
- "remove-trailing-separator": "^1.1.0",
- "replace-ext": "^2.0.0",
- "teex": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulp-run": {
- "version": "1.7.1",
- "resolved": "https://registry.npmjs.org/gulp-run/-/gulp-run-1.7.1.tgz",
- "integrity": "sha512-4OcXhBE5xpRWmbcKzE0EQWEqpLRAkX3ju6k85qkYLfmnCVGK6nPmu/sbVgDiGg6mjuzsF2b9nHFbImZBZPH3zg==",
- "dev": true,
- "license": "ISC",
- "dependencies": {
- "gulp-util": "^3.0.0",
- "lodash.defaults": "^4.0.1",
- "lodash.template": "^4.0.2",
- "vinyl": "^0.4.6"
- }
- },
- "node_modules/gulp-run/node_modules/clone": {
- "version": "0.2.0",
- "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
- "integrity": "sha512-g62n3Kb9cszeZvmvBUqP/dsEJD/+80pDA8u8KqHnAPrVnQ2Je9rVV6opxkhuWCd1kCn2gOibzDKxCtBvD3q5kA==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/gulp-run/node_modules/clone-stats": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
- "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/gulp-run/node_modules/vinyl": {
- "version": "0.4.6",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
- "integrity": "sha512-pmza4M5VA15HOImIQYWhoXGlGNafCm0QK5BpBUXkzzEwrRxKqBsbAhTfkT2zMcJhUX1G1Gkid0xaV8WjOl7DsA==",
- "dev": true,
- "dependencies": {
- "clone": "^0.2.0",
- "clone-stats": "^0.0.1"
- },
- "engines": {
- "node": ">= 0.9"
- }
- },
- "node_modules/gulp-tar": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/gulp-tar/-/gulp-tar-4.0.0.tgz",
- "integrity": "sha512-lvBYoWV+I+0DVmjylWw/TZtHdQAQ9cVaqQ+u/fWcB8Hth3k4BKAT5EpLBoJiiU77ZXZmEgdPWzJ9KZmCuVCyFA==",
- "dev": true,
- "dependencies": {
- "archiver": "^6.0.1",
- "gulp-plugin-extras": "^0.3.0",
- "vinyl": "^3.0.0"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- },
- "peerDependencies": {
- "gulp": ">=4"
- },
- "peerDependenciesMeta": {
- "gulp": {
- "optional": true
- }
- }
- },
- "node_modules/gulp-tar/node_modules/replace-ext": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
- "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/gulp-tar/node_modules/vinyl": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
- "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.2",
- "clone-stats": "^1.0.0",
- "remove-trailing-separator": "^1.1.0",
- "replace-ext": "^2.0.0",
- "teex": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulp-uglify": {
- "version": "3.0.2",
- "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz",
- "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==",
- "dev": true,
- "dependencies": {
- "array-each": "^1.0.1",
- "extend-shallow": "^3.0.2",
- "gulplog": "^1.0.0",
- "has-gulplog": "^0.1.0",
- "isobject": "^3.0.1",
- "make-error-cause": "^1.1.1",
- "safe-buffer": "^5.1.2",
- "through2": "^2.0.0",
- "uglify-js": "^3.0.5",
- "vinyl-sourcemaps-apply": "^0.2.0"
- }
- },
- "node_modules/gulp-util": {
- "version": "3.0.8",
- "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
- "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==",
- "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "array-differ": "^1.0.0",
- "array-uniq": "^1.0.2",
- "beeper": "^1.0.0",
- "chalk": "^1.0.0",
- "dateformat": "^2.0.0",
- "fancy-log": "^1.1.0",
- "gulplog": "^1.0.0",
- "has-gulplog": "^0.1.0",
- "lodash._reescape": "^3.0.0",
- "lodash._reevaluate": "^3.0.0",
- "lodash._reinterpolate": "^3.0.0",
- "lodash.template": "^3.0.0",
- "minimist": "^1.1.0",
- "multipipe": "^0.1.2",
- "object-assign": "^3.0.0",
- "replace-ext": "0.0.1",
- "through2": "^2.0.0",
- "vinyl": "^0.5.0"
- },
- "engines": {
- "node": ">=0.10"
- }
- },
- "node_modules/gulp-util/node_modules/chalk": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
- "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-styles": "^2.2.1",
- "escape-string-regexp": "^1.0.2",
- "has-ansi": "^2.0.0",
- "strip-ansi": "^3.0.0",
- "supports-color": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/gulp-util/node_modules/clone": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
- "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/gulp-util/node_modules/clone-stats": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
- "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/gulp-util/node_modules/escape-string-regexp": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
- "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/gulp-util/node_modules/lodash.template": {
- "version": "3.6.2",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
- "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==",
- "deprecated": "This package is deprecated. Use https://socket.dev/npm/package/eta instead.",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._basecopy": "^3.0.0",
- "lodash._basetostring": "^3.0.0",
- "lodash._basevalues": "^3.0.0",
- "lodash._isiterateecall": "^3.0.0",
- "lodash._reinterpolate": "^3.0.0",
- "lodash.escape": "^3.0.0",
- "lodash.keys": "^3.0.0",
- "lodash.restparam": "^3.0.0",
- "lodash.templatesettings": "^3.0.0"
- }
- },
- "node_modules/gulp-util/node_modules/lodash.templatesettings": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
- "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._reinterpolate": "^3.0.0",
- "lodash.escape": "^3.0.0"
- }
- },
- "node_modules/gulp-util/node_modules/replace-ext": {
- "version": "0.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
- "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/gulp-util/node_modules/supports-color": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
- "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/gulp-util/node_modules/vinyl": {
- "version": "0.5.3",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
- "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "clone": "^1.0.0",
- "clone-stats": "^0.0.1",
- "replace-ext": "0.0.1"
- },
- "engines": {
- "node": ">= 0.9"
- }
- },
- "node_modules/gulp-zip": {
- "version": "6.1.0",
- "resolved": "https://registry.npmjs.org/gulp-zip/-/gulp-zip-6.1.0.tgz",
- "integrity": "sha512-couiqfO4CSM4q3oKnihLhYq5mVmwyXfgLP/0eeM7oVlN+psn45vfvJHcCL3AkPgTi4NojnUFV2IozYqZClIujQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "get-stream": "^9.0.1",
- "gulp-plugin-extras": "^1.1.0",
- "vinyl": "^3.0.0",
- "yazl": "^3.3.1"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- },
- "peerDependencies": {
- "gulp": ">=4"
- },
- "peerDependenciesMeta": {
- "gulp": {
- "optional": true
- }
- }
- },
- "node_modules/gulp-zip/node_modules/gulp-plugin-extras": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/gulp-plugin-extras/-/gulp-plugin-extras-1.1.0.tgz",
- "integrity": "sha512-T0AXOEVoKYzLIBlwEZ7LtAx2w4ExIozIoxVeYEVLFbdxI7i0sWvFDq0F8mm47djixDF3vAqDPoyGwh3Sg/PWtQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "@types/vinyl": "^2.0.12",
- "chalk": "^5.3.0",
- "easy-transform-stream": "^1.0.1"
- },
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/gulp-zip/node_modules/replace-ext": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
- "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/gulp-zip/node_modules/vinyl": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
- "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.2",
- "clone-stats": "^1.0.0",
- "remove-trailing-separator": "^1.1.0",
- "replace-ext": "^2.0.0",
- "teex": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/gulplog": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
- "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==",
- "dev": true,
- "dependencies": {
- "glogg": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/has-ansi": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
- "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/has-bigints": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
- "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-flag": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
- "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/has-gulplog": {
- "version": "0.1.0",
- "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
- "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==",
- "dev": true,
- "dependencies": {
- "sparkles": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/has-property-descriptors": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
- "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
- "dependencies": {
- "es-define-property": "^1.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-proto": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
- "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-symbols": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
- "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/has-tostringtag": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
- "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
- "dependencies": {
- "has-symbols": "^1.0.3"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/hasown": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
- "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
- "dependencies": {
- "function-bind": "^1.1.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/homedir-polyfill": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
- "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
- "dev": true,
- "dependencies": {
- "parse-passwd": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/html2canvas": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
- "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
- "dependencies": {
- "css-line-break": "^2.1.0",
- "text-segmentation": "^1.0.3"
- },
- "engines": {
- "node": ">=8.0.0"
- }
- },
- "node_modules/iconv-lite": {
- "version": "0.6.3",
- "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
- "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
- "dependencies": {
- "safer-buffer": ">= 2.1.2 < 3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/ieee754": {
- "version": "1.2.1",
- "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
- "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/inflight": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
- "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
- "dev": true,
- "dependencies": {
- "once": "^1.3.0",
- "wrappy": "1"
- }
- },
- "node_modules/inherits": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
- "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
- "dev": true
- },
- "node_modules/internal-slot": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
- "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
- "dependencies": {
- "es-errors": "^1.3.0",
- "hasown": "^2.0.0",
- "side-channel": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/interpret": {
- "version": "3.1.1",
- "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
- "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/irregular-plurals": {
- "version": "3.5.0",
- "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz",
- "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-absolute": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
- "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
- "dev": true,
- "dependencies": {
- "is-relative": "^1.0.0",
- "is-windows": "^1.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-arguments": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
- "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-array-buffer": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
- "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "get-intrinsic": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-bigint": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
- "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
- "dependencies": {
- "has-bigints": "^1.0.1"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-binary-path": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
- "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
- "dev": true,
- "dependencies": {
- "binary-extensions": "^2.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-boolean-object": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
- "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-callable": {
- "version": "1.2.7",
- "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
- "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-core-module": {
- "version": "2.13.1",
- "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
- "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
- "dev": true,
- "dependencies": {
- "hasown": "^2.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-date-object": {
- "version": "1.0.5",
- "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
- "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-extendable": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
- "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^2.0.4"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-extendable/node_modules/is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-extglob": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
- "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-fullwidth-code-point": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
- "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/is-glob": {
- "version": "4.0.3",
- "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
- "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
- "dev": true,
- "dependencies": {
- "is-extglob": "^2.1.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-map": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
- "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-negated-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
- "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-number": {
- "version": "7.0.0",
- "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
- "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
- "dev": true,
- "engines": {
- "node": ">=0.12.0"
- }
- },
- "node_modules/is-number-object": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
- "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-obj": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz",
- "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-plain-obj": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
- "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-plain-object": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
- "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-regex": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
- "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
- "dependencies": {
- "call-bind": "^1.0.2",
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-regexp": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz",
- "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==",
- "dev": true,
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-relative": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
- "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
- "dev": true,
- "dependencies": {
- "is-unc-path": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-set": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
- "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-shared-array-buffer": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
- "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
- "dependencies": {
- "call-bind": "^1.0.7"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-stream": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
- "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=18"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/is-string": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
- "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
- "dependencies": {
- "has-tostringtag": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-symbol": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
- "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
- "dependencies": {
- "has-symbols": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-unc-path": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
- "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
- "dev": true,
- "dependencies": {
- "unc-path-regex": "^0.1.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-utf8": {
- "version": "0.2.1",
- "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
- "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
- "dev": true
- },
- "node_modules/is-valid-glob": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
- "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/is-weakmap": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
- "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-weakset": {
- "version": "2.0.3",
- "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
- "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
- "dependencies": {
- "call-bind": "^1.0.7",
- "get-intrinsic": "^1.2.4"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/is-windows": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
- "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/isarray": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
- "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
- "dev": true
- },
- "node_modules/isexe": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
- "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
- "dev": true
- },
- "node_modules/isobject": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
- "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/jasny-bootstrap": {
- "version": "3.1.3",
- "resolved": "https://registry.npmjs.org/jasny-bootstrap/-/jasny-bootstrap-3.1.3.tgz",
- "integrity": "sha512-i2O5dUFuYV56Pyl6aZ5hWmsttTySXRBp+4X4kFlKYHLsJeaeiT3IkpbCPMdrDa1zQbm856cuLoxMEh+3fSOVaQ=="
- },
- "node_modules/jquery": {
- "version": "3.7.1",
- "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
- "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
- },
- "node_modules/jquery-form": {
- "version": "4.3.0",
- "resolved": "https://registry.npmjs.org/jquery-form/-/jquery-form-4.3.0.tgz",
- "integrity": "sha512-q3uaVCEWdLOYUCI6dpNdwf/7cJFOsUgdpq6r0taxtGQ5NJSkOzofyWm4jpOuJ5YxdmL1FI5QR+q+HB63HHLGnQ==",
- "dependencies": {
- "jquery": ">=1.7.2"
- }
- },
- "node_modules/jquery-ui-dist": {
- "version": "1.13.2",
- "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.2.tgz",
- "integrity": "sha512-oVDRd1NLtTbBwpRKAYdIRgpWVDzeBhfy7Gu0RmY6JEaZtmBq6kDn1pm5SgDiAotrnDS+RoTRXO6xvcNTxA9tOA==",
- "dependencies": {
- "jquery": ">=1.8.0 <4.0.0"
- }
- },
- "node_modules/jquery-validation": {
- "version": "1.20.0",
- "resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.20.0.tgz",
- "integrity": "sha512-c8tg4ltIIP6L7l0bZ79sRzOJYquyjS48kQZ6iv8MJ2r0OYztxtkWYKTReZyU2/zVFYiINB29i0Z/IRNNuJQN1g==",
- "peerDependencies": {
- "jquery": "^1.7 || ^2.0 || ^3.1"
- }
- },
- "node_modules/js-cookie": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
- "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
- },
- "node_modules/jspdf": {
- "version": "2.5.1",
- "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
- "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
- "dependencies": {
- "@babel/runtime": "^7.14.0",
- "atob": "^2.1.2",
- "btoa": "^1.2.1",
- "fflate": "^0.4.8"
- },
- "optionalDependencies": {
- "canvg": "^3.0.6",
- "core-js": "^3.6.0",
- "dompurify": "^2.2.0",
- "html2canvas": "^1.0.0-rc.5"
- }
- },
- "node_modules/jspdf-autotable": {
- "version": "3.8.2",
- "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.2.tgz",
- "integrity": "sha512-zW1ix99/mtR4MbIni7IqvrpfHmuTaICl6iv6wqjRN86Nxtwaw/QtOeDbpXqYSzHIJK9JvgtLM283sc5x+ipkJg==",
- "peerDependencies": {
- "jspdf": "^2.5.1"
- }
- },
- "node_modules/last-run": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz",
- "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/lazystream": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
- "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
- "dev": true,
- "dependencies": {
- "readable-stream": "^2.0.5"
- },
- "engines": {
- "node": ">= 0.6.3"
- }
- },
- "node_modules/lazystream/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dev": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/lazystream/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/lazystream/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/lead": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz",
- "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==",
- "dev": true,
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/liftoff": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz",
- "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==",
- "dev": true,
- "dependencies": {
- "extend": "^3.0.2",
- "findup-sync": "^5.0.0",
- "fined": "^2.0.0",
- "flagged-respawn": "^2.0.0",
- "is-plain-object": "^5.0.0",
- "rechoir": "^0.8.0",
- "resolve": "^1.20.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/linebreak": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
- "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
- "dependencies": {
- "base64-js": "0.0.8",
- "unicode-trie": "^2.0.0"
- }
- },
- "node_modules/linebreak/node_modules/base64-js": {
- "version": "0.0.8",
- "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
- "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/lodash": {
- "version": "4.17.21",
- "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
- "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
- "dev": true
- },
- "node_modules/lodash._basecopy": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
- "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._basetostring": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
- "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._basevalues": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
- "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._getnative": {
- "version": "3.9.1",
- "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
- "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._isiterateecall": {
- "version": "3.0.9",
- "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
- "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._reescape": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
- "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._reevaluate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
- "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash._reinterpolate": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
- "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
- "dev": true
- },
- "node_modules/lodash._root": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
- "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.defaults": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
- "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.escape": {
- "version": "3.2.0",
- "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
- "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._root": "^3.0.0"
- }
- },
- "node_modules/lodash.isarguments": {
- "version": "3.1.0",
- "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
- "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.isarray": {
- "version": "3.0.4",
- "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
- "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.keys": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
- "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "lodash._getnative": "^3.0.0",
- "lodash.isarguments": "^3.0.0",
- "lodash.isarray": "^3.0.0"
- }
- },
- "node_modules/lodash.restparam": {
- "version": "3.6.1",
- "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
- "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==",
- "dev": true,
- "license": "MIT"
- },
- "node_modules/lodash.template": {
- "version": "4.5.0",
- "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
- "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
- "dev": true,
- "dependencies": {
- "lodash._reinterpolate": "^3.0.0",
- "lodash.templatesettings": "^4.0.0"
- }
- },
- "node_modules/lodash.templatesettings": {
- "version": "4.2.0",
- "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
- "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
- "dev": true,
- "dependencies": {
- "lodash._reinterpolate": "^3.0.0"
- }
- },
- "node_modules/make-error": {
- "version": "1.3.6",
- "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
- "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
- "dev": true
- },
- "node_modules/make-error-cause": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
- "integrity": "sha512-4TO2Y3HkBnis4c0dxhAgD/jprySYLACf7nwN6V0HAHDx59g12WlRpUmFy1bRHamjGUEEBrEvCq6SUpsEE2lhUg==",
- "dev": true,
- "dependencies": {
- "make-error": "^1.2.0"
- }
- },
- "node_modules/map-cache": {
- "version": "0.2.2",
- "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
- "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/map-stream": {
- "version": "0.0.7",
- "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
- "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
- "dev": true
- },
- "node_modules/micromatch": {
- "version": "4.0.8",
- "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
- "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
- "dev": true,
- "dependencies": {
- "braces": "^3.0.3",
- "picomatch": "^2.3.1"
- },
- "engines": {
- "node": ">=8.6"
- }
- },
- "node_modules/minimist": {
- "version": "1.2.8",
- "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
- "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
- "dev": true,
- "license": "MIT",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/modify-filename": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-2.0.0.tgz",
- "integrity": "sha512-VX9/MdgUN9StpSLImJ0+AyV2dxJJtyojIwRHF/Ja942tW7FTzxXI186jDSTk4k5wj2+59a4bRzFnJUgMSi+ygg==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/moment": {
- "version": "2.30.1",
- "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
- "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
- "engines": {
- "node": "*"
- }
- },
- "node_modules/multipipe": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
- "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "duplexer2": "0.0.2"
- }
- },
- "node_modules/mute-stdout": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz",
- "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/normalize-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
- "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/now-and-later": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz",
- "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==",
- "dev": true,
- "dependencies": {
- "once": "^1.4.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/npm-check-updates": {
- "version": "17.1.14",
- "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.14.tgz",
- "integrity": "sha512-dr4bXIxETubLI1tFGeock5hN8yVjahvaVpx+lPO4/O2md3zJuxB7FgH3MIoTvQSCgsgkIRpe0skti01IEAA5tA==",
- "license": "Apache-2.0",
- "bin": {
- "ncu": "build/cli.js",
- "npm-check-updates": "build/cli.js"
- },
- "engines": {
- "node": "^18.18.0 || >=20.0.0",
- "npm": ">=8.12.1"
- }
- },
- "node_modules/object-assign": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
- "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==",
- "dev": true,
- "license": "MIT",
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object-inspect": {
- "version": "1.13.1",
- "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
- "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-is": {
- "version": "1.1.6",
- "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
- "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
- "dependencies": {
- "call-bind": "^1.0.7",
- "define-properties": "^1.2.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object-keys": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
- "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/object.assign": {
- "version": "4.1.5",
- "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
- "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
- "dependencies": {
- "call-bind": "^1.0.5",
- "define-properties": "^1.2.1",
- "has-symbols": "^1.0.3",
- "object-keys": "^1.1.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/object.defaults": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
- "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==",
- "dev": true,
- "dependencies": {
- "array-each": "^1.0.1",
- "array-slice": "^1.0.0",
- "for-own": "^1.0.0",
- "isobject": "^3.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/object.pick": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
- "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/once": {
- "version": "1.4.0",
- "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
- "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
- "dev": true,
- "dependencies": {
- "wrappy": "1"
- }
- },
- "node_modules/pako": {
- "version": "0.2.9",
- "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
- "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
- },
- "node_modules/parse-filepath": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
- "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==",
- "dev": true,
- "dependencies": {
- "is-absolute": "^1.0.0",
- "map-cache": "^0.2.0",
- "path-root": "^0.1.1"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/parse-node-version": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
- "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
- "dev": true,
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/parse-passwd": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
- "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-is-absolute": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
- "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-parse": {
- "version": "1.0.7",
- "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
- "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
- "dev": true
- },
- "node_modules/path-root": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
- "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==",
- "dev": true,
- "dependencies": {
- "path-root-regex": "^0.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/path-root-regex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
- "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/pause-stream": {
- "version": "0.0.11",
- "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
- "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
- "dev": true,
- "dependencies": {
- "through": "~2.3"
- }
- },
- "node_modules/pdfkit": {
- "version": "0.12.3",
- "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.12.3.tgz",
- "integrity": "sha512-+qDLgm2yq6WOKcxTb43lDeo3EtMIDQs0CK1RNqhHC9iT6u0KOmgwAClkYh9xFw2ATbmUZzt4f7KMwDCOfPDluA==",
- "dependencies": {
- "crypto-js": "^4.0.0",
- "fontkit": "^1.8.1",
- "linebreak": "^1.0.2",
- "png-js": "^1.0.0"
- }
- },
- "node_modules/pdfmake": {
- "version": "0.1.72",
- "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.1.72.tgz",
- "integrity": "sha512-xZrPS+Safjf1I8ZYtMoXX83E6C6Pd1zFwa168yNTeeJWHclqf1z9DoYajjlY2uviN7gGyxwVZeou39uSk1oh1g==",
- "dependencies": {
- "iconv-lite": "^0.6.2",
- "linebreak": "^1.0.2",
- "pdfkit": "^0.12.0",
- "svg-to-pdfkit": "^0.1.8",
- "xmldoc": "^1.1.2"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/performance-now": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
- "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
- "optional": true
- },
- "node_modules/picomatch": {
- "version": "2.3.1",
- "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
- "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
- "dev": true,
- "engines": {
- "node": ">=8.6"
- },
- "funding": {
- "url": "https://github.com/sponsors/jonschlinkert"
- }
- },
- "node_modules/plugin-error": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
- "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==",
- "dev": true,
- "dependencies": {
- "ansi-cyan": "^0.1.1",
- "ansi-red": "^0.1.1",
- "arr-diff": "^1.0.1",
- "arr-union": "^2.0.1",
- "extend-shallow": "^1.1.2"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/plugin-error/node_modules/arr-diff": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
- "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==",
- "dev": true,
- "dependencies": {
- "arr-flatten": "^1.0.1",
- "array-slice": "^0.2.3"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/plugin-error/node_modules/array-slice": {
- "version": "0.2.3",
- "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
- "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/plugin-error/node_modules/extend-shallow": {
- "version": "1.1.4",
- "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
- "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==",
- "dev": true,
- "dependencies": {
- "kind-of": "^1.1.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/plugin-error/node_modules/kind-of": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
- "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/plur": {
- "version": "5.1.0",
- "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz",
- "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==",
- "dev": true,
- "dependencies": {
- "irregular-plurals": "^3.3.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/png-js": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
- "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
- },
- "node_modules/possible-typed-array-names": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
- "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/process": {
- "version": "0.11.10",
- "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
- "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
- "dev": true,
- "engines": {
- "node": ">= 0.6.0"
- }
- },
- "node_modules/process-nextick-args": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
- "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
- "dev": true
- },
- "node_modules/queue-tick": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
- "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
- "dev": true
- },
- "node_modules/raf": {
- "version": "3.4.1",
- "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
- "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
- "optional": true,
- "dependencies": {
- "performance-now": "^2.1.0"
- }
- },
- "node_modules/readable-stream": {
- "version": "4.5.2",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
- "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
- "dev": true,
- "dependencies": {
- "abort-controller": "^3.0.0",
- "buffer": "^6.0.3",
- "events": "^3.3.0",
- "process": "^0.11.10",
- "string_decoder": "^1.3.0"
- },
- "engines": {
- "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
- }
- },
- "node_modules/readdir-glob": {
- "version": "1.1.3",
- "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
- "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
- "dev": true,
- "dependencies": {
- "minimatch": "^5.1.0"
- }
- },
- "node_modules/readdir-glob/node_modules/minimatch": {
- "version": "5.1.6",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
- "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^2.0.1"
- },
- "engines": {
- "node": ">=10"
- }
- },
- "node_modules/readdirp": {
- "version": "3.6.0",
- "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
- "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
- "dev": true,
- "dependencies": {
- "picomatch": "^2.2.1"
- },
- "engines": {
- "node": ">=8.10.0"
- }
- },
- "node_modules/rechoir": {
- "version": "0.8.0",
- "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
- "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
- "dev": true,
- "dependencies": {
- "resolve": "^1.20.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/regenerator-runtime": {
- "version": "0.14.1",
- "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
- "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
- },
- "node_modules/regexp.prototype.flags": {
- "version": "1.5.2",
- "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
- "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
- "dependencies": {
- "call-bind": "^1.0.6",
- "define-properties": "^1.2.1",
- "es-errors": "^1.3.0",
- "set-function-name": "^2.0.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/remove-trailing-separator": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
- "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
- "dev": true
- },
- "node_modules/replace-ext": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
- "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
- "dev": true,
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/replace-homedir": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz",
- "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/require-directory": {
- "version": "2.1.1",
- "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
- "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve": {
- "version": "1.22.8",
- "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
- "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
- "dev": true,
- "dependencies": {
- "is-core-module": "^2.13.0",
- "path-parse": "^1.0.7",
- "supports-preserve-symlinks-flag": "^1.0.0"
- },
- "bin": {
- "resolve": "bin/resolve"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/resolve-dir": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
- "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
- "dev": true,
- "dependencies": {
- "expand-tilde": "^2.0.0",
- "global-modules": "^1.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/resolve-options": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz",
- "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==",
- "dev": true,
- "dependencies": {
- "value-or-function": "^4.0.0"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/restructure": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
- "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg=="
- },
- "node_modules/reusify": {
- "version": "1.0.4",
- "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
- "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
- "dev": true,
- "engines": {
- "iojs": ">=1.0.0",
- "node": ">=0.10.0"
- }
- },
- "node_modules/rev-hash": {
- "version": "4.1.0",
- "resolved": "https://registry.npmjs.org/rev-hash/-/rev-hash-4.1.0.tgz",
- "integrity": "sha512-e0EGnaveLY2IYpYwHNdh43WZ2M84KgW3Z/T4F6+Z/BlZI/T1ZbxTWj36xgYgUPOieGXYo2q225jTeUXn+LWYjw==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/rev-path": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/rev-path/-/rev-path-3.0.0.tgz",
- "integrity": "sha512-2fUuv6IC7Z+Vj+DXEunJYJDZuwSsaJJHeLar3n2PGvHSH7j5+Xpd/Xh7PenekH4WQhxFuHtsGwd1dCh/HvT6Gw==",
- "dev": true,
- "dependencies": {
- "modify-filename": "^2.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/rgbcolor": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
- "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
- "optional": true,
- "engines": {
- "node": ">= 0.8.15"
- }
- },
- "node_modules/rimraf": {
- "version": "2.7.1",
- "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
- "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
- "dev": true,
- "dependencies": {
- "glob": "^7.1.3"
- },
- "bin": {
- "rimraf": "bin.js"
- }
- },
- "node_modules/rimraf/node_modules/brace-expansion": {
- "version": "1.1.11",
- "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
- "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
- "dev": true,
- "dependencies": {
- "balanced-match": "^1.0.0",
- "concat-map": "0.0.1"
- }
- },
- "node_modules/rimraf/node_modules/glob": {
- "version": "7.2.3",
- "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
- "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
- "dev": true,
- "dependencies": {
- "fs.realpath": "^1.0.0",
- "inflight": "^1.0.4",
- "inherits": "2",
- "minimatch": "^3.1.1",
- "once": "^1.3.0",
- "path-is-absolute": "^1.0.0"
- },
- "engines": {
- "node": "*"
- },
- "funding": {
- "url": "https://github.com/sponsors/isaacs"
- }
- },
- "node_modules/rimraf/node_modules/minimatch": {
- "version": "3.1.2",
- "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
- "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
- "dev": true,
- "dependencies": {
- "brace-expansion": "^1.1.7"
- },
- "engines": {
- "node": "*"
- }
- },
- "node_modules/safe-buffer": {
- "version": "5.2.1",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
- "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
- "dev": true,
- "funding": [
- {
- "type": "github",
- "url": "https://github.com/sponsors/feross"
- },
- {
- "type": "patreon",
- "url": "https://www.patreon.com/feross"
- },
- {
- "type": "consulting",
- "url": "https://feross.org/support"
- }
- ]
- },
- "node_modules/safer-buffer": {
- "version": "2.1.2",
- "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
- "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
- },
- "node_modules/sax": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
- "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
- },
- "node_modules/select": {
- "version": "1.1.2",
- "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
- "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
- },
- "node_modules/semver-greatest-satisfied-range": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz",
- "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==",
- "dev": true,
- "dependencies": {
- "sver": "^1.8.3"
- },
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/set-function-length": {
- "version": "1.2.2",
- "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
- "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "function-bind": "^1.1.2",
- "get-intrinsic": "^1.2.4",
- "gopd": "^1.0.1",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/set-function-name": {
- "version": "2.0.2",
- "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
- "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
- "dependencies": {
- "define-data-property": "^1.1.4",
- "es-errors": "^1.3.0",
- "functions-have-names": "^1.2.3",
- "has-property-descriptors": "^1.0.2"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/side-channel": {
- "version": "1.0.6",
- "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
- "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
- "dependencies": {
- "call-bind": "^1.0.7",
- "es-errors": "^1.3.0",
- "get-intrinsic": "^1.2.4",
- "object-inspect": "^1.13.1"
- },
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/sort-keys": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-5.0.0.tgz",
- "integrity": "sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==",
- "dev": true,
- "dependencies": {
- "is-plain-obj": "^4.0.0"
- },
- "engines": {
- "node": ">=12"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/source-map": {
- "version": "0.6.1",
- "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
- "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/sparkles": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
- "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
- "dev": true,
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/ssf": {
- "version": "0.11.2",
- "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
- "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
- "dependencies": {
- "frac": "~1.1.2"
- },
- "engines": {
- "node": ">=0.8"
- }
- },
- "node_modules/stackblur-canvas": {
- "version": "2.7.0",
- "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
- "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
- "optional": true,
- "engines": {
- "node": ">=0.1.14"
- }
- },
- "node_modules/stop-iteration-iterator": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
- "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
- "dependencies": {
- "internal-slot": "^1.0.4"
- },
- "engines": {
- "node": ">= 0.4"
- }
- },
- "node_modules/stream-composer": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz",
- "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==",
- "dev": true,
- "dependencies": {
- "streamx": "^2.13.2"
- }
- },
- "node_modules/stream-exhaust": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
- "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
- "dev": true
- },
- "node_modules/stream-series": {
- "version": "0.1.1",
- "resolved": "https://registry.npmjs.org/stream-series/-/stream-series-0.1.1.tgz",
- "integrity": "sha512-OrmvvBgH+6PUeVp/hZGycQIrFegjTEbObxsQGXuPPjtFGIJL5E7JTmjHriUcdPOEiTlpc8wWatgnGCZHKVo7zg==",
- "dev": true,
- "dependencies": {
- "pause-stream": "0.0.11"
- }
- },
- "node_modules/stream-to-array": {
- "version": "2.3.0",
- "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz",
- "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==",
- "dev": true,
- "dependencies": {
- "any-promise": "^1.1.0"
- }
- },
- "node_modules/streamx": {
- "version": "2.16.1",
- "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
- "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
- "dev": true,
- "dependencies": {
- "fast-fifo": "^1.1.0",
- "queue-tick": "^1.0.1"
- },
- "optionalDependencies": {
- "bare-events": "^2.2.0"
- }
- },
- "node_modules/string_decoder": {
- "version": "1.3.0",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
- "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.2.0"
- }
- },
- "node_modules/string-width": {
- "version": "4.2.3",
- "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
- "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
- "dev": true,
- "dependencies": {
- "emoji-regex": "^8.0.0",
- "is-fullwidth-code-point": "^3.0.0",
- "strip-ansi": "^6.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width/node_modules/ansi-regex": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
- "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
- "dev": true,
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/string-width/node_modules/strip-ansi": {
- "version": "6.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
- "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
- "dev": true,
- "dependencies": {
- "ansi-regex": "^5.0.1"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/stringify-object": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz",
- "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==",
- "dev": true,
- "dependencies": {
- "get-own-enumerable-keys": "^1.0.0",
- "is-obj": "^3.0.0",
- "is-regexp": "^3.1.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/yeoman/stringify-object?sponsor=1"
- }
- },
- "node_modules/strip-ansi": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
- "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
- "dev": true,
- "license": "MIT",
- "dependencies": {
- "ansi-regex": "^2.0.0"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/strip-bom-buf": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-3.0.1.tgz",
- "integrity": "sha512-iJaWw2WroigLHzQysdc5WWeUc99p7ea7AEgB6JkY8CMyiO1yTVAA1gIlJJgORElUIR+lcZJkNl1OGChMhvc2Cw==",
- "dev": true,
- "dependencies": {
- "is-utf8": "^0.2.1"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/strip-bom-stream": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-5.0.0.tgz",
- "integrity": "sha512-Yo472mU+3smhzqeKlIxClre4s4pwtYZEvDNQvY/sJpnChdaxmKuwU28UVx/v1ORKNMxkmj1GBuvxJQyBk6wYMQ==",
- "dev": true,
- "dependencies": {
- "first-chunk-stream": "^5.0.0",
- "strip-bom-buf": "^3.0.0"
- },
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/supports-color": {
- "version": "7.2.0",
- "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
- "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
- "dev": true,
- "dependencies": {
- "has-flag": "^4.0.0"
- },
- "engines": {
- "node": ">=8"
- }
- },
- "node_modules/supports-preserve-symlinks-flag": {
- "version": "1.0.0",
- "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
- "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
- "dev": true,
- "engines": {
- "node": ">= 0.4"
- },
- "funding": {
- "url": "https://github.com/sponsors/ljharb"
- }
- },
- "node_modules/sver": {
- "version": "1.8.4",
- "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz",
- "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==",
- "dev": true,
- "optionalDependencies": {
- "semver": "^6.3.0"
- }
- },
- "node_modules/sver/node_modules/semver": {
- "version": "6.3.1",
- "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
- "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
- "dev": true,
- "optional": true,
- "bin": {
- "semver": "bin/semver.js"
- }
- },
- "node_modules/svg-pathdata": {
- "version": "6.0.3",
- "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
- "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
- "optional": true,
- "engines": {
- "node": ">=12.0.0"
- }
- },
- "node_modules/svg-to-pdfkit": {
- "version": "0.1.8",
- "resolved": "https://registry.npmjs.org/svg-to-pdfkit/-/svg-to-pdfkit-0.1.8.tgz",
- "integrity": "sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==",
- "dependencies": {
- "pdfkit": ">=0.8.1"
- }
- },
- "node_modules/tableexport.jquery.plugin": {
- "version": "1.30.0",
- "resolved": "https://registry.npmjs.org/tableexport.jquery.plugin/-/tableexport.jquery.plugin-1.30.0.tgz",
- "integrity": "sha512-kMztiFUsGbxsknFVCDph+5j4e9xmqBBV6Na7T9vRYCUGDxtlndrdxMs9qLJDSOXjlgkIqCUv+S/e5iTUNAFF/g==",
- "dependencies": {
- "file-saver": ">=2.0.4",
- "html2canvas": ">=1.0.0",
- "jquery": ">=3.2.1",
- "jspdf": ">=2.0.0",
- "pdfmake": "^0.1.71",
- "xlsx": ">=0.16.0"
- }
- },
- "node_modules/tar-stream": {
- "version": "3.1.7",
- "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
- "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
- "dev": true,
- "dependencies": {
- "b4a": "^1.6.4",
- "fast-fifo": "^1.2.0",
- "streamx": "^2.15.0"
- }
- },
- "node_modules/teex": {
- "version": "1.0.1",
- "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
- "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
- "dev": true,
- "dependencies": {
- "streamx": "^2.12.5"
- }
- },
- "node_modules/text-segmentation": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
- "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
- "dependencies": {
- "utrie": "^1.0.2"
- }
- },
- "node_modules/through": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
- "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
- "dev": true
- },
- "node_modules/through2": {
- "version": "2.0.5",
- "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
- "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
- "dev": true,
- "dependencies": {
- "readable-stream": "~2.3.6",
- "xtend": "~4.0.1"
- }
- },
- "node_modules/through2/node_modules/readable-stream": {
- "version": "2.3.8",
- "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
- "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
- "dev": true,
- "dependencies": {
- "core-util-is": "~1.0.0",
- "inherits": "~2.0.3",
- "isarray": "~1.0.0",
- "process-nextick-args": "~2.0.0",
- "safe-buffer": "~5.1.1",
- "string_decoder": "~1.1.1",
- "util-deprecate": "~1.0.1"
- }
- },
- "node_modules/through2/node_modules/safe-buffer": {
- "version": "5.1.2",
- "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
- "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
- "dev": true
- },
- "node_modules/through2/node_modules/string_decoder": {
- "version": "1.1.1",
- "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
- "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
- "dev": true,
- "dependencies": {
- "safe-buffer": "~5.1.0"
- }
- },
- "node_modules/tildify": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/tildify/-/tildify-3.0.0.tgz",
- "integrity": "sha512-9ZLMl75qnTLr7oSEmWJbKemFS/fP4TMBiF6PFwGwLpgobebU1ehXoGbadJ+7jT8fjaz2G82JgN9G4taz+o1j1w==",
- "dev": true,
- "engines": {
- "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/time-stamp": {
- "version": "1.1.0",
- "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
- "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/tiny-emitter": {
- "version": "2.1.0",
- "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
- "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
- },
- "node_modules/tiny-inflate": {
- "version": "1.0.3",
- "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
- "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
- },
- "node_modules/to-regex-range": {
- "version": "5.0.1",
- "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
- "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
- "dev": true,
- "dependencies": {
- "is-number": "^7.0.0"
- },
- "engines": {
- "node": ">=8.0"
- }
- },
- "node_modules/to-through": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz",
- "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==",
- "dev": true,
- "dependencies": {
- "streamx": "^2.12.5"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/tslib": {
- "version": "2.6.2",
- "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
- "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
- },
- "node_modules/uglify-js": {
- "version": "3.17.4",
- "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
- "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
- "dev": true,
- "bin": {
- "uglifyjs": "bin/uglifyjs"
- },
- "engines": {
- "node": ">=0.8.0"
- }
- },
- "node_modules/unc-path-regex": {
- "version": "0.1.2",
- "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
- "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
- "dev": true,
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/undertaker": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz",
- "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==",
- "dev": true,
- "dependencies": {
- "bach": "^2.0.1",
- "fast-levenshtein": "^3.0.0",
- "last-run": "^2.0.0",
- "undertaker-registry": "^2.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/undertaker-registry": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz",
- "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/undici-types": {
- "version": "5.26.5",
- "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
- "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
- "dev": true
- },
- "node_modules/unicode-properties": {
- "version": "1.4.1",
- "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
- "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
- "dependencies": {
- "base64-js": "^1.3.0",
- "unicode-trie": "^2.0.0"
- }
- },
- "node_modules/unicode-trie": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
- "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
- "dependencies": {
- "pako": "^0.2.5",
- "tiny-inflate": "^1.0.0"
- }
- },
- "node_modules/union-value": {
- "version": "2.0.1",
- "resolved": "https://registry.npmjs.org/union-value/-/union-value-2.0.1.tgz",
- "integrity": "sha512-NmcRHHhUy1qWmp6yYWsaURV2qwfS24TmTtO9S9x0L41wCNNVBQFD3toOzO0cd8SsNrFhbw/O0iYO5uffXGYocw==",
- "dev": true,
- "dependencies": {
- "get-value": "^3.0.1",
- "set-value": "^3.0.0"
- },
- "engines": {
- "node": ">=6"
- }
- },
- "node_modules/union-value/node_modules/get-value": {
- "version": "3.0.1",
- "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz",
- "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/union-value/node_modules/is-plain-object": {
- "version": "2.0.4",
- "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
- "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
- "dev": true,
- "dependencies": {
- "isobject": "^3.0.1"
- },
- "engines": {
- "node": ">=0.10.0"
- }
- },
- "node_modules/union-value/node_modules/set-value": {
- "version": "3.0.3",
- "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.3.tgz",
- "integrity": "sha512-Xsn/XSatoVOGBbp5hs3UylFDs5Bi9i+ArpVJKdHPniZHoEgRniXTqHWrWrGQ0PbEClVT6WtfnBwR8CAHC9sveg==",
- "dev": true,
- "dependencies": {
- "is-plain-object": "^2.0.4"
- },
- "engines": {
- "node": ">=6.0"
- }
- },
- "node_modules/util-deprecate": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
- "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
- "dev": true
- },
- "node_modules/utrie": {
- "version": "1.0.2",
- "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
- "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
- "dependencies": {
- "base64-arraybuffer": "^1.0.2"
- }
- },
- "node_modules/v8flags": {
- "version": "4.0.1",
- "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz",
- "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/value-or-function": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz",
- "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==",
- "dev": true,
- "engines": {
- "node": ">= 10.13.0"
- }
- },
- "node_modules/vinyl": {
- "version": "2.2.1",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
- "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.1",
- "clone-buffer": "^1.0.0",
- "clone-stats": "^1.0.0",
- "cloneable-readable": "^1.0.0",
- "remove-trailing-separator": "^1.0.1",
- "replace-ext": "^1.0.0"
- },
- "engines": {
- "node": ">= 0.10"
- }
- },
- "node_modules/vinyl-contents": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz",
- "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==",
- "dev": true,
- "dependencies": {
- "bl": "^5.0.0",
- "vinyl": "^3.0.0"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/vinyl-contents/node_modules/replace-ext": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
- "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/vinyl-contents/node_modules/vinyl": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
- "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.2",
- "clone-stats": "^1.0.0",
- "remove-trailing-separator": "^1.1.0",
- "replace-ext": "^2.0.0",
- "teex": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/vinyl-file": {
- "version": "5.0.0",
- "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-5.0.0.tgz",
- "integrity": "sha512-MvkPF/yA1EX7c6p+juVIvp9+Lxp70YUfNKzEWeHMKpUNVSnTZh2coaOqLxI0pmOe2V9nB+OkgFaMDkodaJUyGw==",
- "dev": true,
- "dependencies": {
- "@types/vinyl": "^2.0.7",
- "strip-bom-buf": "^3.0.1",
- "strip-bom-stream": "^5.0.0",
- "vinyl": "^3.0.0"
- },
- "engines": {
- "node": ">=14.16"
- },
- "funding": {
- "url": "https://github.com/sponsors/sindresorhus"
- }
- },
- "node_modules/vinyl-file/node_modules/replace-ext": {
- "version": "2.0.0",
- "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
- "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
- "dev": true,
- "engines": {
- "node": ">= 10"
- }
- },
- "node_modules/vinyl-file/node_modules/vinyl": {
- "version": "3.0.0",
- "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
- "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
- "dev": true,
- "dependencies": {
- "clone": "^2.1.2",
- "clone-stats": "^1.0.0",
- "remove-trailing-separator": "^1.1.0",
- "replace-ext": "^2.0.0",
- "teex": "^1.0.1"
- },
- "engines": {
- "node": ">=10.13.0"
- }
- },
- "node_modules/vinyl-fs": {
- "version": "4.0.0",
- "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz",
- "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==",
- "dev": true,
- "dependencies": {
+ "name": "@opensourcepos/opensourcepos",
+ "version": "3.4.0",
+ "lockfileVersion": 3,
+ "requires": true,
+ "packages": {
+ "": {
+ "name": "@opensourcepos/opensourcepos",
+ "version": "3.4.0",
+ "license": "MIT",
+ "dependencies": {
+ "bootstrap": "^3.4.1",
+ "bootstrap-daterangepicker": "^2.1.27",
+ "bootstrap-datetime-picker": "2.4.4",
+ "bootstrap-notify": "^3.1.3",
+ "bootstrap-select": "^1.13.18",
+ "bootstrap-table": "^1.23.5",
+ "bootstrap-tagsinput-2021": "^0.8.6",
+ "bootstrap-toggle": "^2.2.2",
+ "bootstrap3-dialog": "github:nakupanda/bootstrap3-dialog#master",
+ "bootstrap5": "npm:bootstrap@^5.3.3",
+ "bootswatch": "^3.4.1",
+ "bootswatch5": "npm:bootswatch@^5.3.3",
+ "chartist": "^0.11.4",
+ "chartist-plugin-axistitle": "^0.0.7",
+ "chartist-plugin-barlabels": "^0.0.5",
+ "chartist-plugin-pointlabels": "^0.0.6",
+ "chartist-plugin-tooltips": "^0.0.17",
+ "clipboard": "^2.0.11",
+ "coffeescript": "^2.7.0",
+ "es6-promise": "^4.2.8",
+ "file-saver": "^2.0.5",
+ "html2canvas": "^1.4.1",
+ "jasny-bootstrap": "^3.1.3",
+ "jquery": "^3.7.1",
+ "jquery-form": "^4.3.0",
+ "jquery-ui-dist": "^1.12.1",
+ "jquery-validation": "^1.19.5",
+ "js-cookie": "^2.2.1",
+ "jspdf": "^2.5.1",
+ "jspdf-autotable": "^3.8.2",
+ "npm-check-updates": "^17.1.14",
+ "tableexport.jquery.plugin": "^1.30.0"
+ },
+ "devDependencies": {
+ "gulp": "^5.0.0",
+ "gulp-clean": "^0.4.0",
+ "gulp-clean-css": "^4.3.0",
+ "gulp-concat": "^2.6.1",
+ "gulp-debug": "^5.0.1",
+ "gulp-gzip": "^1.4.2",
+ "gulp-header": "^2.0.9",
+ "gulp-inject": "^5.0.5",
+ "gulp-rename": "^2.0.0",
+ "gulp-rev": "^10.0.0",
+ "gulp-run": "^1.7.1",
+ "gulp-tar": "^4.0.0",
+ "gulp-uglify": "^3.0.2",
+ "gulp-zip": "^6.1.0",
+ "readable-stream": "^4.4.2",
+ "stream-series": "^0.1.1"
+ }
+ },
+ "node_modules/@babel/runtime": {
+ "version": "7.24.4",
+ "resolved": "https://registry.npmjs.org/@babel/runtime/-/runtime-7.24.4.tgz",
+ "integrity": "sha512-dkxf7+hn8mFBwKjs9bvBlArzLVxVbS8usaPUDd5p2a9JCL9tB8OaOVN1isD4+Xyk4ns89/xeOmbQvgdK7IIVdA==",
+ "dependencies": {
+ "regenerator-runtime": "^0.14.0"
+ },
+ "engines": {
+ "node": ">=6.9.0"
+ }
+ },
+ "node_modules/@gulpjs/messages": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/@gulpjs/messages/-/messages-1.1.0.tgz",
+ "integrity": "sha512-Ys9sazDatyTgZVb4xPlDufLweJ/Os2uHWOv+Caxvy2O85JcnT4M3vc73bi8pdLWlv3fdWQz3pdI9tVwo8rQQSg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/@gulpjs/to-absolute-glob": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/@gulpjs/to-absolute-glob/-/to-absolute-glob-4.0.0.tgz",
+ "integrity": "sha512-kjotm7XJrJ6v+7knhPaRgaT6q8F8K2jiafwYdNHLzmV0uGLuZY43FK6smNSHUPrhq5kX2slCUy+RGG/xGqmIKA==",
+ "dev": true,
+ "dependencies": {
+ "is-negated-glob": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/@popperjs/core": {
+ "version": "2.11.8",
+ "resolved": "https://registry.npmjs.org/@popperjs/core/-/core-2.11.8.tgz",
+ "integrity": "sha512-P1st0aksCrn9sGZhp8GMYwBnQsbvAWsZAX44oXNNvLHGqAOcoVxmjZiohstwQ7SqKnbR47akdNi+uleWD8+g6A==",
+ "peer": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/popperjs"
+ }
+ },
+ "node_modules/@sec-ant/readable-stream": {
+ "version": "0.4.1",
+ "resolved": "https://registry.npmjs.org/@sec-ant/readable-stream/-/readable-stream-0.4.1.tgz",
+ "integrity": "sha512-831qok9r2t8AlxLko40y2ebgSDhenenCatLVeW/uBtnHPyhHOvG0C7TvfgecV+wHzIm5KUICgzmVpWS+IMEAeg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/@swc/helpers": {
+ "version": "0.3.17",
+ "resolved": "https://registry.npmjs.org/@swc/helpers/-/helpers-0.3.17.tgz",
+ "integrity": "sha512-tb7Iu+oZ+zWJZ3HJqwx8oNwSDIU440hmVMDPhpACWQWnrZHK99Bxs70gT1L2dnr5Hg50ZRWEFkQCAnOVVV0z1Q==",
+ "dependencies": {
+ "tslib": "^2.4.0"
+ }
+ },
+ "node_modules/@types/expect": {
+ "version": "1.20.4",
+ "resolved": "https://registry.npmjs.org/@types/expect/-/expect-1.20.4.tgz",
+ "integrity": "sha512-Q5Vn3yjTDyCMV50TB6VRIbQNxSE4OmZR86VSbGaNpfUolm0iePBB4KdEEHmxoY5sT2+2DIvXW0rvMDP2nHZ4Mg==",
+ "dev": true
+ },
+ "node_modules/@types/node": {
+ "version": "20.12.7",
+ "resolved": "https://registry.npmjs.org/@types/node/-/node-20.12.7.tgz",
+ "integrity": "sha512-wq0cICSkRLVaf3UGLMGItu/PtdY7oaXaI/RVU+xliKVOtRna3PRY57ZDfztpDL0n11vfymMUnXv8QwYCO7L1wg==",
+ "dev": true,
+ "dependencies": {
+ "undici-types": "~5.26.4"
+ }
+ },
+ "node_modules/@types/raf": {
+ "version": "3.4.3",
+ "resolved": "https://registry.npmjs.org/@types/raf/-/raf-3.4.3.tgz",
+ "integrity": "sha512-c4YAvMedbPZ5tEyxzQdMoOhhJ4RD3rngZIdwC2/qDN3d7JpEhB6fiBRKVY1lg5B7Wk+uPBjn5f39j1/2MY1oOw==",
+ "optional": true
+ },
+ "node_modules/@types/vinyl": {
+ "version": "2.0.12",
+ "resolved": "https://registry.npmjs.org/@types/vinyl/-/vinyl-2.0.12.tgz",
+ "integrity": "sha512-Sr2fYMBUVGYq8kj3UthXFAu5UN6ZW+rYr4NACjZQJvHvj+c8lYv0CahmZ2P/r7iUkN44gGUBwqxZkrKXYPb7cw==",
+ "dev": true,
+ "dependencies": {
+ "@types/expect": "^1.20.4",
+ "@types/node": "*"
+ }
+ },
+ "node_modules/abort-controller": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/abort-controller/-/abort-controller-3.0.0.tgz",
+ "integrity": "sha512-h8lQ8tacZYnR3vNQTgibj+tODHI5/+l06Au2Pcriv/Gmet0eaj4TwWH41sO9wnHDiQsEj19q0drzdWdeAHtweg==",
+ "dev": true,
+ "dependencies": {
+ "event-target-shim": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=6.5"
+ }
+ },
+ "node_modules/adler-32": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/adler-32/-/adler-32-1.3.1.tgz",
+ "integrity": "sha512-ynZ4w/nUUv5rrsR8UUGoe1VC9hZj6V5hU9Qw1HlMDJGEJw5S7TfTErWTjMys6M7vr0YWcPqs3qAr4ss0nDfP+A==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/ansi-colors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-wrap": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-cyan": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-cyan/-/ansi-cyan-0.1.1.tgz",
+ "integrity": "sha512-eCjan3AVo/SxZ0/MyIYRtkpxIu/H3xZN7URr1vXVrISxeyz8fUFz0FJziamK4sS8I+t35y4rHg1b2PklyBe/7A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-wrap": "0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-gray": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz",
+ "integrity": "sha512-HrgGIZUl8h2EHuZaU9hTR/cU5nhKxpVE1V6kdGsQ8e4zirElJ5fvtfc8N7Q1oq1aatO275i8pUFUCpNWCAnVWw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-wrap": "0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-red": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-red/-/ansi-red-0.1.1.tgz",
+ "integrity": "sha512-ewaIr5y+9CUTGFwZfpECUbFlGcC0GCw1oqR9RI6h1gQCd9Aj2GxSckCnPsVJnmfMZbwFYE+leZGASgkWl06Jow==",
+ "dev": true,
+ "dependencies": {
+ "ansi-wrap": "0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-regex": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz",
+ "integrity": "sha512-TIGnTpdo+E3+pCyAluZvtED5p5wCqLdezCyhPZzKPcxvFplEt4i+W7OONCKgeZFT3+y5NZZfOOS/Bdcanm1MYA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-styles": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz",
+ "integrity": "sha512-kmCevFghRiWM7HB5zTPULl4r9bVFSWjz62MhqizDGUrq2NWuNMQyuv4tHHoKJHs69M/MF64lEcHdYIocrdWQYA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ansi-wrap": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz",
+ "integrity": "sha512-ZyznvL8k/FZeQHr2T6LzcJ/+vBApDnMNZvfVFy3At0knswWd6rJ3/0Hhmpu8oqa6C92npmozs890sX9Dl6q+Qw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/any-promise": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/any-promise/-/any-promise-1.3.0.tgz",
+ "integrity": "sha512-7UvmKalWRt1wgjL1RrGxoSJW/0QZFIegpeGvZG9kjp8vrRu55XTHbwnqq2GpXm9uLbcuhxm3IqX9OB4MZR1b2A==",
+ "dev": true
+ },
+ "node_modules/anymatch": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-3.1.3.tgz",
+ "integrity": "sha512-KMReFUr0B4t+D+OBkjR3KYqvocp2XaSzO55UcB6mgQMd3KbcE+mWTyvVV7D/zsdEbNnV6acZUutkiHQXvTr1Rw==",
+ "dev": true,
+ "dependencies": {
+ "normalize-path": "^3.0.0",
+ "picomatch": "^2.0.4"
+ },
+ "engines": {
+ "node": ">= 8"
+ }
+ },
+ "node_modules/archiver": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/archiver/-/archiver-6.0.2.tgz",
+ "integrity": "sha512-UQ/2nW7NMl1G+1UnrLypQw1VdT9XZg/ECcKPq7l+STzStrSivFIXIp34D8M5zeNGW5NoOupdYCHv6VySCPNNlw==",
+ "dev": true,
+ "dependencies": {
+ "archiver-utils": "^4.0.1",
+ "async": "^3.2.4",
+ "buffer-crc32": "^0.2.1",
+ "readable-stream": "^3.6.0",
+ "readdir-glob": "^1.1.2",
+ "tar-stream": "^3.0.0",
+ "zip-stream": "^5.0.1"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/archiver-utils": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/archiver-utils/-/archiver-utils-4.0.1.tgz",
+ "integrity": "sha512-Q4Q99idbvzmgCTEAAhi32BkOyq8iVI5EwdO0PmBDSGIzzjYNdcFn7Q7k3OzbLy4kLUPXfJtG6fO2RjftXbobBg==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^8.0.0",
+ "graceful-fs": "^4.2.0",
+ "lazystream": "^1.0.0",
+ "lodash": "^4.17.15",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/glob": {
+ "version": "8.1.0",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-8.1.0.tgz",
+ "integrity": "sha512-r8hpEjiQEYlF2QU0df3dS+nxxSIreXQS1qRhMJM0Q5NDdR386C7jb7Hwwod8Fgiuex+k0GFjgft18yvxm5XoCQ==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^5.0.1",
+ "once": "^1.3.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/archiver-utils/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/archiver/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/arr-diff": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz",
+ "integrity": "sha512-YVIQ82gZPGBebQV/a8dar4AitzCQs0jjXwMPZllpXMaGjXPYVUawSxQrRsjhjupyVxEvbHgUmIhKVlND+j02kA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-flatten": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz",
+ "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arr-union": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-2.1.0.tgz",
+ "integrity": "sha512-t5db90jq+qdgk8aFnxEkjqta0B/GHrM1pxzuuZz2zWsOXc5nKu3t+76s/PQBA8FTcM/ipspIH9jWG4OxCBc2eA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-buffer-byte-length": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-buffer-byte-length/-/array-buffer-byte-length-1.0.1.tgz",
+ "integrity": "sha512-ahC5W1xgou+KTXix4sAO8Ki12Q+jf4i0+tmk3sC+zgcynshkHxzpXdImBehiUYKKKDwvfFiJl1tZt6ewscS1Mg==",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "is-array-buffer": "^3.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/array-differ": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/array-differ/-/array-differ-1.0.0.tgz",
+ "integrity": "sha512-LeZY+DZDRnvP7eMuQ6LHfCzUGxAAIViUBliK24P3hWXL6y4SortgR6Nim6xrkfSLlmH0+k+9NYNwVC2s53ZrYQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-each": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz",
+ "integrity": "sha512-zHjL5SZa68hkKHBFBK6DJCTtr9sfTCPCaph/L7tMSLcTFgy+zX7E+6q5UArbtOtMBCtxdICpfTCspRse+ywyXA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-slice": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz",
+ "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/array-uniq": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/array-uniq/-/array-uniq-1.0.3.tgz",
+ "integrity": "sha512-MNha4BWQ6JbwhFhj03YK552f7cb3AzoE8SzeljgChvL1dl3IcvggXVz1DilzySZkCja+CXuZbdW7yATchWn8/Q==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/arrify": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/arrify/-/arrify-2.0.1.tgz",
+ "integrity": "sha512-3duEwti880xqi4eAMN8AyR4a0ByT90zoYdLlevfrvU43vb0YZwZVfxOgxWrLXXXpyugL0hNZc9G6BiB5B3nUug==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/assign-symbols": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz",
+ "integrity": "sha512-Q+JC7Whu8HhmTdBph/Tq59IoRtoy6KAm5zzPv00WdujX82lbAL8K7WVjne7vdCsAmbF4AYaDOPyO3k0kl8qIrw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/async": {
+ "version": "3.2.5",
+ "resolved": "https://registry.npmjs.org/async/-/async-3.2.5.tgz",
+ "integrity": "sha512-baNZyqaaLhyLVKm/DlvdW051MSgO6b8eVfIezl9E5PqWxFgzLm/wQntEW4zOytVburDEr0JlALEpdOFwvErLsg==",
+ "dev": true
+ },
+ "node_modules/async-done": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/async-done/-/async-done-2.0.0.tgz",
+ "integrity": "sha512-j0s3bzYq9yKIVLKGE/tWlCpa3PfFLcrDZLTSVdnnCTGagXuXBJO4SsY9Xdk/fQBirCkH4evW5xOeJXqlAQFdsw==",
+ "dev": true,
+ "dependencies": {
+ "end-of-stream": "^1.4.4",
+ "once": "^1.4.0",
+ "stream-exhaust": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/async-settle": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-2.0.0.tgz",
+ "integrity": "sha512-Obu/KE8FurfQRN6ODdHN9LuXqwC+JFIM9NRyZqJJ4ZfLJmIYN9Rg0/kb+wF70VV5+fJusTMQlJ1t5rF7J/ETdg==",
+ "dev": true,
+ "dependencies": {
+ "async-done": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/atob": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz",
+ "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==",
+ "bin": {
+ "atob": "bin/atob.js"
+ },
+ "engines": {
+ "node": ">= 4.5.0"
+ }
+ },
+ "node_modules/available-typed-arrays": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/available-typed-arrays/-/available-typed-arrays-1.0.7.tgz",
+ "integrity": "sha512-wvUjBtSGN7+7SjNpq/9M2Tg350UZD3q62IFZLbRAR1bSMlCo1ZaeW+BJ+D090e4hIIZLBcTDWe4Mh4jvUDajzQ==",
+ "dependencies": {
+ "possible-typed-array-names": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/b4a": {
+ "version": "1.6.6",
+ "resolved": "https://registry.npmjs.org/b4a/-/b4a-1.6.6.tgz",
+ "integrity": "sha512-5Tk1HLk6b6ctmjIkAcU/Ujv/1WqiDl0F0JdRCR80VsOcUlHcu7pWeWRlOqQLHfDEsVx9YH/aif5AG4ehoCtTmg==",
+ "dev": true
+ },
+ "node_modules/bach": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/bach/-/bach-2.0.1.tgz",
+ "integrity": "sha512-A7bvGMGiTOxGMpNupYl9HQTf0FFDNF4VCmks4PJpFyN1AX2pdKuxuwdvUz2Hu388wcgp+OvGFNsumBfFNkR7eg==",
+ "dev": true,
+ "dependencies": {
+ "async-done": "^2.0.0",
+ "async-settle": "^2.0.0",
+ "now-and-later": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/balanced-match": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.2.tgz",
+ "integrity": "sha512-3oSeUO0TMV67hN1AmbXsK4yaqU7tjiHlbxRDZOpH0KW9+CeX4bRAaX0Anxt0tx2MrpRpWwQaPwIlISEJhYU5Pw==",
+ "dev": true
+ },
+ "node_modules/bare-events": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/bare-events/-/bare-events-2.2.2.tgz",
+ "integrity": "sha512-h7z00dWdG0PYOQEvChhOSWvOfkIKsdZGkWr083FgN/HyoQuebSew/cgirYqh9SCuy/hRvxc5Vy6Fw8xAmYHLkQ==",
+ "dev": true,
+ "optional": true
+ },
+ "node_modules/base64-arraybuffer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/base64-arraybuffer/-/base64-arraybuffer-1.0.2.tgz",
+ "integrity": "sha512-I3yl4r9QB5ZRY3XuJVEPfc2XhZO6YweFPI+UovAzn+8/hb3oJ6lnysaFcjVpkCPfVWFUDvoZ8kmVDP7WyRtYtQ==",
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/base64-js": {
+ "version": "1.5.1",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.5.1.tgz",
+ "integrity": "sha512-AKpaYlHn8t4SVbOHCy+b5+KKgvR4vrsD8vbvrbiQJps7fKDTkjkDry6ji0rUJjC0kzbNePLwzxq8iypo41qeWA==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/beeper": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/beeper/-/beeper-1.1.1.tgz",
+ "integrity": "sha512-3vqtKL1N45I5dV0RdssXZG7X6pCqQrWPNOlBPZPrd+QkE2HEhR57Z04m0KtpbsZH73j+a3F8UD1TQnn+ExTvIA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/binary-extensions": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-2.3.0.tgz",
+ "integrity": "sha512-Ceh+7ox5qe7LJuLHoY0feh3pHuUDHAcRUeyL2VYghZwfpkNIy/+8Ocg0a3UuSoYzavmylwuLWQOf3hl0jjMMIw==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/bl": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/bl/-/bl-5.1.0.tgz",
+ "integrity": "sha512-tv1ZJHLfTDnXE6tMHv73YgSJaWR2AFuPwMntBe7XL/GBFHnT0CLnsHMogfk5+GzCDC5ZWarSCYaIGATZt9dNsQ==",
+ "dev": true,
+ "dependencies": {
+ "buffer": "^6.0.3",
+ "inherits": "^2.0.4",
+ "readable-stream": "^3.4.0"
+ }
+ },
+ "node_modules/bl/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/bootstrap": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-3.4.1.tgz",
+ "integrity": "sha512-yN5oZVmRCwe5aKwzRj6736nSmKDX7pLYwsXiCj/EYmo16hODaBiT4En5btW/jhBF/seV+XMx3aYwukYC3A49DA==",
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/bootstrap-daterangepicker": {
+ "version": "2.1.30",
+ "resolved": "https://registry.npmjs.org/bootstrap-daterangepicker/-/bootstrap-daterangepicker-2.1.30.tgz",
+ "integrity": "sha512-lZAmyQxwsthEbsIBKl2KVcUca+b/O8uAJxxY8AvlsCYF9dQlIY7WjskuqMJ3b/1YdXUgxHN/R6HFdVVNFSgeVQ==",
+ "dependencies": {
+ "jquery": ">=1.10",
+ "moment": "^2.9.0"
+ }
+ },
+ "node_modules/bootstrap-datetime-picker": {
+ "version": "2.4.4",
+ "resolved": "https://registry.npmjs.org/bootstrap-datetime-picker/-/bootstrap-datetime-picker-2.4.4.tgz",
+ "integrity": "sha512-TTknlrqoJ7DcJJpkmvg+TneUiWNG65gfjHYbTM5MpJ60DGWmcQJWN7+6eU78WvqxE6Dz/yKmeyLDEzzWVgw43A=="
+ },
+ "node_modules/bootstrap-notify": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/bootstrap-notify/-/bootstrap-notify-3.1.3.tgz",
+ "integrity": "sha512-cnTactFVG8aHri03+RmuZ5sl9VcA+jTTM/mTdEOQN+R1V9u4YBu8Ca+Pf6NGeVfieGv0Z6CxK8FzlWg59omzyg=="
+ },
+ "node_modules/bootstrap-select": {
+ "version": "1.13.18",
+ "resolved": "https://registry.npmjs.org/bootstrap-select/-/bootstrap-select-1.13.18.tgz",
+ "integrity": "sha512-V1IzK4rxBq5FrJtkzSH6RmFLFBsjx50byFbfAf8jYyXROWs7ZpprGjdHeoyq2HSsHyjJhMMwjsQhRoYAfxCGow==",
+ "peerDependencies": {
+ "bootstrap": ">=3.0.0",
+ "jquery": "1.9.1 - 3"
+ }
+ },
+ "node_modules/bootstrap-table": {
+ "version": "1.23.5",
+ "resolved": "https://registry.npmjs.org/bootstrap-table/-/bootstrap-table-1.23.5.tgz",
+ "integrity": "sha512-9WByoSpJvA73gi2YYIlX6IWR74oZtBmSixul/Th8FTBtBd/kZRpbKESGTjhA3BA3AYTnfyY8Iy1KeRWPlV2GWQ==",
+ "license": "MIT",
+ "peerDependencies": {
+ "jquery": "3"
+ }
+ },
+ "node_modules/bootstrap-tagsinput-2021": {
+ "version": "0.8.6",
+ "resolved": "https://registry.npmjs.org/bootstrap-tagsinput-2021/-/bootstrap-tagsinput-2021-0.8.6.tgz",
+ "integrity": "sha512-/ZbR3Hl6BtpbuVuoXPxiyoh4a4fKyoyKn4pFXyL4fGEEQ3uwPS4/urrJ5O9ew2WkfBkJUdHnCLtNuVeUlz6HoA=="
+ },
+ "node_modules/bootstrap-toggle": {
+ "version": "2.2.2",
+ "resolved": "https://registry.npmjs.org/bootstrap-toggle/-/bootstrap-toggle-2.2.2.tgz",
+ "integrity": "sha512-AkYD/i3NGCEksIb/PmmUrrxpa0DYi7Si30e9Ldhou2t1HTd9npoXUsxJJjFPvlV7iLUptlysWTcYD7i3DKV6qg=="
+ },
+ "node_modules/bootstrap3-dialog": {
+ "version": "1.35.4",
+ "resolved": "git+ssh://git@github.com/nakupanda/bootstrap3-dialog.git#a491a98c97921114883ad44e5715fe28396dbaea"
+ },
+ "node_modules/bootstrap5": {
+ "name": "bootstrap",
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootstrap/-/bootstrap-5.3.3.tgz",
+ "integrity": "sha512-8HLCdWgyoMguSO9o+aH+iuZ+aht+mzW0u3HIMzVu7Srrpv7EBBxTnrFlSCskwdY1+EOFQSm7uMJhNQHkdPcmjg==",
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/twbs"
+ },
+ {
+ "type": "opencollective",
+ "url": "https://opencollective.com/bootstrap"
+ }
+ ],
+ "peerDependencies": {
+ "@popperjs/core": "^2.11.8"
+ }
+ },
+ "node_modules/bootswatch": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-3.4.1.tgz",
+ "integrity": "sha512-0hL4A8OUiqABgPipGrojf/hyhr5RS257xCNARlbK34HaMfhV5fXvwEooN4/ri9+jgX47J4Wg24ZPmfZ2xD2cKw==",
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/bootswatch5": {
+ "name": "bootswatch",
+ "version": "5.3.3",
+ "resolved": "https://registry.npmjs.org/bootswatch/-/bootswatch-5.3.3.tgz",
+ "integrity": "sha512-cJLhobnZsVCelU7zdH/L7wpcXAyUoTX4/5l2dWQ0JXgaVK80BdTQNU/ImWwoyIGBeyms4iQDAdNtOfPQZf0Atg=="
+ },
+ "node_modules/brace-expansion": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-2.0.1.tgz",
+ "integrity": "sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0"
+ }
+ },
+ "node_modules/braces": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/braces/-/braces-3.0.3.tgz",
+ "integrity": "sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA==",
+ "dev": true,
+ "dependencies": {
+ "fill-range": "^7.1.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/brotli": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/brotli/-/brotli-1.3.3.tgz",
+ "integrity": "sha512-oTKjJdShmDuGW94SyyaoQvAjf30dZaHnjJ8uAF+u2/vGJkJbJPJAT1gDiOJP5v1Zb6f9KEyW/1HpuaWIXtGHPg==",
+ "dependencies": {
+ "base64-js": "^1.1.2"
+ }
+ },
+ "node_modules/btoa": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/btoa/-/btoa-1.2.1.tgz",
+ "integrity": "sha512-SB4/MIGlsiVkMcHmT+pSmIPoNDoHg+7cMzmt3Uxt628MTz2487DKSqK/fuhFBrkuqrYv5UCEnACpF4dTFNKc/g==",
+ "bin": {
+ "btoa": "bin/btoa.js"
+ },
+ "engines": {
+ "node": ">= 0.4.0"
+ }
+ },
+ "node_modules/buffer": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/buffer/-/buffer-6.0.3.tgz",
+ "integrity": "sha512-FTiCpNxtwiZZHEZbcbTIcZjERVICn9yq/pDFkTl95/AxzD1naBctN7YO68riM/gLSDY7sdrMby8hofADYuuqOA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ],
+ "dependencies": {
+ "base64-js": "^1.3.1",
+ "ieee754": "^1.2.1"
+ }
+ },
+ "node_modules/buffer-crc32": {
+ "version": "0.2.13",
+ "resolved": "https://registry.npmjs.org/buffer-crc32/-/buffer-crc32-0.2.13.tgz",
+ "integrity": "sha512-VO9Ht/+p3SN7SKWqcrgEzjGbRSJYTx+Q1pTQC0wrWqHx0vpJraQ6GtHx8tvcg1rlK1byhU5gccxgOgj7B0TDkQ==",
+ "dev": true,
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/bytes": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/bytes/-/bytes-3.1.2.tgz",
+ "integrity": "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.8"
+ }
+ },
+ "node_modules/call-bind": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/call-bind/-/call-bind-1.0.7.tgz",
+ "integrity": "sha512-GHTSNSYICQ7scH7sZ+M2rFopRoLh8t2bLSW6BbgrtLsahOIB5iyAVJf9GjWK3cYTDaMj4XdBpM1cA6pIS0Kv2w==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "set-function-length": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/canvg": {
+ "version": "3.0.10",
+ "resolved": "https://registry.npmjs.org/canvg/-/canvg-3.0.10.tgz",
+ "integrity": "sha512-qwR2FRNO9NlzTeKIPIKpnTY6fqwuYSequ8Ru8c0YkYU7U0oW+hLUvWadLvAu1Rl72OMNiFhoLu4f8eUjQ7l/+Q==",
+ "optional": true,
+ "dependencies": {
+ "@babel/runtime": "^7.12.5",
+ "@types/raf": "^3.4.0",
+ "core-js": "^3.8.3",
+ "raf": "^3.4.1",
+ "regenerator-runtime": "^0.13.7",
+ "rgbcolor": "^1.0.1",
+ "stackblur-canvas": "^2.0.0",
+ "svg-pathdata": "^6.0.3"
+ },
+ "engines": {
+ "node": ">=10.0.0"
+ }
+ },
+ "node_modules/canvg/node_modules/regenerator-runtime": {
+ "version": "0.13.11",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.13.11.tgz",
+ "integrity": "sha512-kY1AZVr2Ra+t+piVaJ4gxaFaReZVH40AKNo7UCX6W+dEwBo/2oZJzqfuN1qLq1oL45o56cPaTXELwrTh8Fpggg==",
+ "optional": true
+ },
+ "node_modules/cfb": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/cfb/-/cfb-1.2.2.tgz",
+ "integrity": "sha512-KfdUZsSOw19/ObEWasvBP/Ac4reZvAGauZhs6S/gqNhXhI7cKwvlH7ulj+dOEYnca4bm4SGo8C1bTAQvnTjgQA==",
+ "dependencies": {
+ "adler-32": "~1.3.0",
+ "crc-32": "~1.2.0"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/chalk": {
+ "version": "5.3.0",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-5.3.0.tgz",
+ "integrity": "sha512-dLitG79d+GV1Nb/VYcCDFivJeK1hiukt9QjRNVOsUtTy1rR1YJsmpGGTZ3qJos+uw7WmWF4wUwBd9jxjocFC2w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.17.0 || ^14.13 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/chartist": {
+ "version": "0.11.4",
+ "resolved": "https://registry.npmjs.org/chartist/-/chartist-0.11.4.tgz",
+ "integrity": "sha512-H4AimxaUD738/u9Mq8t27J4lh6STsLi4BQHt65nOtpLk3xyrBPaLiLMrHw7/WV9CmsjGA02WihjuL5qpSagLYw==",
+ "engines": {
+ "node": ">=4.6.0"
+ }
+ },
+ "node_modules/chartist-plugin-axistitle": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/chartist-plugin-axistitle/-/chartist-plugin-axistitle-0.0.7.tgz",
+ "integrity": "sha512-qFG7R/qiZZyCn/gx9WJpMcnyhE0LIpGBxDnPpYtzY5cG53fHBkvJDsAEHEFFfO1l/RHI0G8oN9fpoUD/BMeiFA==",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/chartist-plugin-barlabels": {
+ "version": "0.0.5",
+ "resolved": "https://registry.npmjs.org/chartist-plugin-barlabels/-/chartist-plugin-barlabels-0.0.5.tgz",
+ "integrity": "sha512-QJpFB37jCD0pyDqb0/FSnaXXqUhnzabN1gULkBqK0VOoC/KerihR5EomNdOPnjZoEm8T9gRSNbxGGObZKJFKiw==",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/chartist-plugin-pointlabels": {
+ "version": "0.0.6",
+ "resolved": "https://registry.npmjs.org/chartist-plugin-pointlabels/-/chartist-plugin-pointlabels-0.0.6.tgz",
+ "integrity": "sha512-DUemVUBWAN0qAHBUMXKKLrDCsUL1qWWwN+EfxN8gpftgXSheMiYeq83uHoHyp4X+W5Pz/aUWBf3N/HJwj+eRFw==",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/chartist-plugin-tooltips": {
+ "version": "0.0.17",
+ "resolved": "https://registry.npmjs.org/chartist-plugin-tooltips/-/chartist-plugin-tooltips-0.0.17.tgz",
+ "integrity": "sha512-frXv269MyRHfuhyZILdTTsNG4PP3+Ab0NkysdnMk73aN4w76oWarsGguuciYzZawKrctp8RZzU/W44A4+Y4vOg==",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/chokidar": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-3.6.0.tgz",
+ "integrity": "sha512-7VT13fmjotKpGipCW9JEQAusEPE+Ei8nl6/g4FBAmIm0GOOLMua9NDDo/DWp0ZAxCr3cPq5ZpBqmPAQgDda2Pw==",
+ "dev": true,
+ "dependencies": {
+ "anymatch": "~3.1.2",
+ "braces": "~3.0.2",
+ "glob-parent": "~5.1.2",
+ "is-binary-path": "~2.1.0",
+ "is-glob": "~4.0.1",
+ "normalize-path": "~3.0.0",
+ "readdirp": "~3.6.0"
+ },
+ "engines": {
+ "node": ">= 8.10.0"
+ },
+ "funding": {
+ "url": "https://paulmillr.com/funding/"
+ },
+ "optionalDependencies": {
+ "fsevents": "~2.3.2"
+ }
+ },
+ "node_modules/clean-css": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.3.tgz",
+ "integrity": "sha512-VcMWDN54ZN/DS+g58HYL5/n4Zrqe8vHJpGA8KdgUXFU4fuP/aHNw8eld9SyEIyabIMJX/0RaY/fplOo5hYLSFA==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "~0.6.0"
+ },
+ "engines": {
+ "node": ">= 4.0"
+ }
+ },
+ "node_modules/clipboard": {
+ "version": "2.0.11",
+ "resolved": "https://registry.npmjs.org/clipboard/-/clipboard-2.0.11.tgz",
+ "integrity": "sha512-C+0bbOqkezLIsmWSvlsXS0Q0bmkugu7jcfMIACB+RDEntIzQIkdr148we28AfSloQLRdZlYL/QYyrq05j/3Faw==",
+ "dependencies": {
+ "good-listener": "^1.2.2",
+ "select": "^1.1.2",
+ "tiny-emitter": "^2.0.0"
+ }
+ },
+ "node_modules/cliui": {
+ "version": "7.0.4",
+ "resolved": "https://registry.npmjs.org/cliui/-/cliui-7.0.4.tgz",
+ "integrity": "sha512-OcRE68cOsVMXp1Yvonl/fzkQOyjLSu/8bhPDfQt0e0/Eb283TKP20Fs2MqoPsr9SwA595rRCA+QMzYc9nBP+JQ==",
+ "dev": true,
+ "dependencies": {
+ "string-width": "^4.2.0",
+ "strip-ansi": "^6.0.0",
+ "wrap-ansi": "^7.0.0"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/cliui/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/cliui/node_modules/wrap-ansi": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-7.0.0.tgz",
+ "integrity": "sha512-YVGIj2kamLSTxw6NsZjoBxfSwsn0ycdesmc4p+Q21c5zPuZ1pl+NfxVdxPtdHvmNVOQ6XSYG4AUtyt/Fi7D16Q==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.0.0",
+ "string-width": "^4.1.0",
+ "strip-ansi": "^6.0.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/wrap-ansi?sponsor=1"
+ }
+ },
+ "node_modules/clone": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz",
+ "integrity": "sha512-3Pe/CF1Nn94hyhIYpjtiLhdCoEoz0DqQ+988E9gmeEdQZlojxnOb74wctFyuwWQHzqyf9X7C7MG8juUpqBJT8w==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/clone-buffer": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz",
+ "integrity": "sha512-KLLTJWrvwIP+OPfMn0x2PheDEP20RPUcGXj/ERegTgdmPEZylALQldygiqrPPu8P45uNuPs7ckmReLY6v/iA5g==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/clone-stats": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz",
+ "integrity": "sha512-au6ydSpg6nsrigcZ4m8Bc9hxjeW+GJ8xh5G3BJCMt4WXe1H10UNaVOamqQTmrx1kjVuxAHIQSNU6hY4Nsn9/ag==",
+ "dev": true
+ },
+ "node_modules/cloneable-readable": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.3.tgz",
+ "integrity": "sha512-2EF8zTQOxYq70Y4XKtorQupqF0m49MBz2/yf5Bj+MHjvpG3Hy7sImifnqD6UA+TKYxeSV+u6qqQPawN5UvnpKQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.1",
+ "process-nextick-args": "^2.0.0",
+ "readable-stream": "^2.3.5"
+ }
+ },
+ "node_modules/cloneable-readable/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/cloneable-readable/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/cloneable-readable/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/codepage": {
+ "version": "1.15.0",
+ "resolved": "https://registry.npmjs.org/codepage/-/codepage-1.15.0.tgz",
+ "integrity": "sha512-3g6NUTPd/YtuuGrhMnOMRjFc+LJw/bnMp3+0r/Wcz3IXUuCosKRJvMphm5+Q+bvTVGcJJuRvVLuYba+WojaFaA==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/coffeescript": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/coffeescript/-/coffeescript-2.7.0.tgz",
+ "integrity": "sha512-hzWp6TUE2d/jCcN67LrW1eh5b/rSDKQK6oD6VMLlggYVUUFexgTH9z3dNYihzX4RMhze5FTUsUmOXViJKFQR/A==",
+ "bin": {
+ "cake": "bin/cake",
+ "coffee": "bin/coffee"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/color-convert": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-2.0.1.tgz",
+ "integrity": "sha512-RRECPsj7iu/xb5oKYcsFHSppFNnsj/52OVTRKb4zP5onXwVF3zVmmToNcOfGC+CRDpfK/U584fMg38ZHCaElKQ==",
+ "dev": true,
+ "dependencies": {
+ "color-name": "~1.1.4"
+ },
+ "engines": {
+ "node": ">=7.0.0"
+ }
+ },
+ "node_modules/color-name": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.4.tgz",
+ "integrity": "sha512-dOy+3AuW3a2wNbZHIuMZpTcgjGuLU/uBL/ubcZF9OXbDo8ff4O8yVp5Bf0efS8uEoYo5q4Fx7dY9OgQGXgAsQA==",
+ "dev": true
+ },
+ "node_modules/color-support": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz",
+ "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==",
+ "dev": true,
+ "bin": {
+ "color-support": "bin.js"
+ }
+ },
+ "node_modules/compress-commons": {
+ "version": "5.0.3",
+ "resolved": "https://registry.npmjs.org/compress-commons/-/compress-commons-5.0.3.tgz",
+ "integrity": "sha512-/UIcLWvwAQyVibgpQDPtfNM3SvqN7G9elAPAV7GM0L53EbNWwWiCsWtK8Fwed/APEbptPHXs5PuW+y8Bq8lFTA==",
+ "dev": true,
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "crc32-stream": "^5.0.0",
+ "normalize-path": "^3.0.0",
+ "readable-stream": "^3.6.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/compress-commons/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/concat-map": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz",
+ "integrity": "sha512-/Srv4dswyQNBfohGpz9o6Yb3Gz3SrUDqBH5rTuhGR7ahtlbYKnVxw2bCFMRljaA7EXHaXZ8wsHdodFvbkhKmqg==",
+ "dev": true
+ },
+ "node_modules/concat-with-sourcemaps": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz",
+ "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==",
+ "dev": true,
+ "dependencies": {
+ "source-map": "^0.6.1"
+ }
+ },
+ "node_modules/convert-source-map": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-2.0.0.tgz",
+ "integrity": "sha512-Kvp459HrV2FEJ1CAsi1Ku+MY3kasH19TFykTz2xWmMeq6bk2NU3XXvfJ+Q61m0xktWwt+1HSYf3JZsTms3aRJg==",
+ "dev": true
+ },
+ "node_modules/copy-props": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-4.0.0.tgz",
+ "integrity": "sha512-bVWtw1wQLzzKiYROtvNlbJgxgBYt2bMJpkCbKmXM3xyijvcjjWXEk5nyrrT3bgJ7ODb19ZohE2T0Y3FgNPyoTw==",
+ "dev": true,
+ "dependencies": {
+ "each-props": "^3.0.0",
+ "is-plain-object": "^5.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/core-js": {
+ "version": "3.37.0",
+ "resolved": "https://registry.npmjs.org/core-js/-/core-js-3.37.0.tgz",
+ "integrity": "sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug==",
+ "hasInstallScript": true,
+ "optional": true,
+ "funding": {
+ "type": "opencollective",
+ "url": "https://opencollective.com/core-js"
+ }
+ },
+ "node_modules/core-util-is": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz",
+ "integrity": "sha512-3lqz5YjWTYnW6dlDa5TLaTCcShfar1e40rmcJVwCBJC6mWlFuj0eCHIElmG1g5kyuJ/GD+8Wn4FFCcz4gJPfaQ==",
+ "dev": true
+ },
+ "node_modules/crc-32": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/crc-32/-/crc-32-1.2.2.tgz",
+ "integrity": "sha512-ROmzCKrTnOwybPcJApAA6WBWij23HVfGVNKqqrZpuyZOHqK2CwHSvpGuyt/UNNvaIjEd8X5IFGp4Mh+Ie1IHJQ==",
+ "bin": {
+ "crc32": "bin/crc32.njs"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/crc32-stream": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/crc32-stream/-/crc32-stream-5.0.1.tgz",
+ "integrity": "sha512-lO1dFui+CEUh/ztYIpgpKItKW9Bb4NWakCRJrnqAbFIYD+OZAwb2VfD5T5eXMw2FNcsDHkQcNl/Wh3iVXYwU6g==",
+ "dev": true,
+ "dependencies": {
+ "crc-32": "^1.2.0",
+ "readable-stream": "^3.4.0"
+ },
+ "engines": {
+ "node": ">= 12.0.0"
+ }
+ },
+ "node_modules/crc32-stream/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/crypto-js": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/crypto-js/-/crypto-js-4.2.0.tgz",
+ "integrity": "sha512-KALDyEYgpY+Rlob/iriUtjV6d5Eq+Y191A5g4UqLAi8CyGP9N1+FdVbkc1SxKc2r4YAYqG8JzO2KGL+AizD70Q=="
+ },
+ "node_modules/css-line-break": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/css-line-break/-/css-line-break-2.1.0.tgz",
+ "integrity": "sha512-FHcKFCZcAha3LwfVBhCQbW2nCNbkZXn7KVUJcsT5/P8YmfsVja0FMPJr0B903j/E69HUphKiV9iQArX8SDYA4w==",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/dateformat": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/dateformat/-/dateformat-2.2.0.tgz",
+ "integrity": "sha512-GODcnWq3YGoTnygPfi02ygEiRxqUxpJwuRHjdhJYuxpcZmDq4rjBiXYmbCCzStxo176ixfLT6i4NPwQooRySnw==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/deep-equal": {
+ "version": "2.2.3",
+ "resolved": "https://registry.npmjs.org/deep-equal/-/deep-equal-2.2.3.tgz",
+ "integrity": "sha512-ZIwpnevOurS8bpT4192sqAowWM76JDKSHYzMLty3BZGSswgq6pBaH3DhCSW5xVAZICZyKdOBPjwww5wfgT/6PA==",
+ "dependencies": {
+ "array-buffer-byte-length": "^1.0.0",
+ "call-bind": "^1.0.5",
+ "es-get-iterator": "^1.1.3",
+ "get-intrinsic": "^1.2.2",
+ "is-arguments": "^1.1.1",
+ "is-array-buffer": "^3.0.2",
+ "is-date-object": "^1.0.5",
+ "is-regex": "^1.1.4",
+ "is-shared-array-buffer": "^1.0.2",
+ "isarray": "^2.0.5",
+ "object-is": "^1.1.5",
+ "object-keys": "^1.1.1",
+ "object.assign": "^4.1.4",
+ "regexp.prototype.flags": "^1.5.1",
+ "side-channel": "^1.0.4",
+ "which-boxed-primitive": "^1.0.2",
+ "which-collection": "^1.0.1",
+ "which-typed-array": "^1.1.13"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/deep-equal/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
+ },
+ "node_modules/define-data-property": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/define-data-property/-/define-data-property-1.1.4.tgz",
+ "integrity": "sha512-rBMvIzlpA8v6E+SJZoo++HAYqsLrkg7MSfIinMPFhmkorw7X+dOXVJQs+QT69zGkzMyfDnIMN2Wid1+NbL3T+A==",
+ "dependencies": {
+ "es-define-property": "^1.0.0",
+ "es-errors": "^1.3.0",
+ "gopd": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/define-properties": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.2.1.tgz",
+ "integrity": "sha512-8QmQKqEASLd5nx0U1B1okLElbUuuttJ/AnYmRXbbbGDWh6uS208EjD4Xqq/I9wK7u0v6O08XhTWnt5XtEbR6Dg==",
+ "dependencies": {
+ "define-data-property": "^1.0.1",
+ "has-property-descriptors": "^1.0.0",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/delegate": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/delegate/-/delegate-3.2.0.tgz",
+ "integrity": "sha512-IofjkYBZaZivn0V8nnsMJGBr4jVLxHDheKSW88PyxS5QC4Vo9ZbZVvhzlSxY87fVq3STR6r+4cGepyHkcWOQSw=="
+ },
+ "node_modules/detect-file": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz",
+ "integrity": "sha512-DtCOLG98P007x7wiiOmfI0fi3eIKyWiLTGJ2MDnVi/E04lWGbf+JzrRHMm0rgIIZJGtHpKpbVgLWHrv8xXpc3Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/dfa": {
+ "version": "1.2.0",
+ "resolved": "https://registry.npmjs.org/dfa/-/dfa-1.2.0.tgz",
+ "integrity": "sha512-ED3jP8saaweFTjeGX8HQPjeC1YYyZs98jGNZx6IiBvxW7JG5v492kamAQB3m2wop07CvU/RQmzcKr6bgcC5D/Q=="
+ },
+ "node_modules/dompurify": {
+ "version": "2.5.6",
+ "resolved": "https://registry.npmjs.org/dompurify/-/dompurify-2.5.6.tgz",
+ "integrity": "sha512-zUTaUBO8pY4+iJMPE1B9XlO2tXVYIcEA4SNGtvDELzTSCQO7RzH+j7S180BmhmJId78lqGU2z19vgVx2Sxs/PQ==",
+ "optional": true
+ },
+ "node_modules/duplexer2": {
+ "version": "0.0.2",
+ "resolved": "https://registry.npmjs.org/duplexer2/-/duplexer2-0.0.2.tgz",
+ "integrity": "sha512-+AWBwjGadtksxjOQSFDhPNQbed7icNXApT4+2BNpsXzcCBiInq2H9XW0O8sfHFaPmnQRs7cg/P0fAr2IWQSW0g==",
+ "dev": true,
+ "license": "BSD",
+ "dependencies": {
+ "readable-stream": "~1.1.9"
+ }
+ },
+ "node_modules/duplexer2/node_modules/isarray": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-0.0.1.tgz",
+ "integrity": "sha512-D2S+3GLxWH+uhrNEcoh/fnmYeP8E8/zHl644d/jdA0g2uyXvy3sb0qxotE+ne0LtccHknQzWwZEzhak7oJ0COQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/duplexer2/node_modules/readable-stream": {
+ "version": "1.1.14",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-1.1.14.tgz",
+ "integrity": "sha512-+MeVjFf4L44XUkhM1eYbD8fyEsxcV81pqMSR5gblfcLCHfZvbrqy4/qYHE+/R5HoBUT11WV5O08Cr1n3YXkWVQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.1",
+ "isarray": "0.0.1",
+ "string_decoder": "~0.10.x"
+ }
+ },
+ "node_modules/duplexer2/node_modules/string_decoder": {
+ "version": "0.10.31",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-0.10.31.tgz",
+ "integrity": "sha512-ev2QzSzWPYmy9GuqfIVildA4OdcGLeFZQrq5ys6RtiuF+RQQiZWr8TZNyAcuVXyQRYfEO+MsoB/1BuQVhOJuoQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/each-props": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/each-props/-/each-props-3.0.0.tgz",
+ "integrity": "sha512-IYf1hpuWrdzse/s/YJOrFmU15lyhSzxelNVAHTEG3DtP4QsLTWZUzcUL3HMXmKQxXpa4EIrBPpwRgj0aehdvAw==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^5.0.0",
+ "object.defaults": "^1.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/easy-transform-stream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/easy-transform-stream/-/easy-transform-stream-1.0.1.tgz",
+ "integrity": "sha512-ktkaa6XR7COAR3oj02CF3IOgz2m1hCaY3SfzvKT4Svt2MhHw9XCt+ncJNWfe2TGz31iqzNGZ8spdKQflj+Rlog==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/emoji-regex": {
+ "version": "8.0.0",
+ "resolved": "https://registry.npmjs.org/emoji-regex/-/emoji-regex-8.0.0.tgz",
+ "integrity": "sha512-MSjYzcWNOA0ewAHpz0MxpYFvwg6yjy1NG3xteoqz644VCo/RPgnr1/GGt+ic3iJTzQ8Eu3TdM14SawnVUmGE6A==",
+ "dev": true
+ },
+ "node_modules/end-of-stream": {
+ "version": "1.4.4",
+ "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.4.tgz",
+ "integrity": "sha512-+uw1inIHVPQoaVuHzRyXd21icM+cnt4CzD5rW+NC1wjOUSTOs+Te7FOv7AhN7vS9x/oIyhLP5PR1H+phQAHu5Q==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ }
+ },
+ "node_modules/es-define-property": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/es-define-property/-/es-define-property-1.0.0.tgz",
+ "integrity": "sha512-jxayLKShrEqqzJ0eumQbVhTYQM27CfT1T35+gCgDFoL82JLsXqTJ76zv6A0YLOgEnLUMvLzsDsGIrl8NFpT2gQ==",
+ "dependencies": {
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-errors": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/es-errors/-/es-errors-1.3.0.tgz",
+ "integrity": "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/es-get-iterator": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/es-get-iterator/-/es-get-iterator-1.1.3.tgz",
+ "integrity": "sha512-sPZmqHBe6JIiTfN5q2pEi//TwxmAFHwj/XEuYjTuse78i8KxaqMTTzxPoFKuzRpDpTJ+0NAbpfenkmH2rePtuw==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.1.3",
+ "has-symbols": "^1.0.3",
+ "is-arguments": "^1.1.1",
+ "is-map": "^2.0.2",
+ "is-set": "^2.0.2",
+ "is-string": "^1.0.7",
+ "isarray": "^2.0.5",
+ "stop-iteration-iterator": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/es-get-iterator/node_modules/isarray": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-2.0.5.tgz",
+ "integrity": "sha512-xHjhDr3cNBK0BzdUJSPXZntQUx/mwMS5Rw4A7lPJ90XGAO6ISP/ePDNuo0vhqOZU+UD5JoodwCAAoZQd3FeAKw=="
+ },
+ "node_modules/es6-promise": {
+ "version": "4.2.8",
+ "resolved": "https://registry.npmjs.org/es6-promise/-/es6-promise-4.2.8.tgz",
+ "integrity": "sha512-HJDGx5daxeIvxdBxvG2cb9g4tEvwIk3i8+nhX0yGrYmZUzbkdg8QbDevheDB8gd0//uPj4c1EQua8Q+MViT0/w=="
+ },
+ "node_modules/escalade": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/escalade/-/escalade-3.1.2.tgz",
+ "integrity": "sha512-ErCHMCae19vR8vQGe50xIsVomy19rg6gFu3+r3jkEO46suLMWBksvVyoGgQV+jOfl84ZSOSlmv6Gxa89PmTGmA==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/escape-string-regexp": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-2.0.0.tgz",
+ "integrity": "sha512-UpzcLCXolUWcNu5HtVMHYdXJjArjsF9C0aNnquZYY4uW/Vu0miy5YoWvbV345HauVvcAUnpRuhMMcqTcGOY2+w==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/event-target-shim": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/event-target-shim/-/event-target-shim-5.0.1.tgz",
+ "integrity": "sha512-i/2XbnSz/uxRCU6+NdVJgKWDTM427+MqYbkQzD321DuCQJUqOuJKIA0IM2+W2xtYHdKOmZ4dR6fExsd4SXL+WQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/events": {
+ "version": "3.3.0",
+ "resolved": "https://registry.npmjs.org/events/-/events-3.3.0.tgz",
+ "integrity": "sha512-mQw+2fkQbALzQ7V0MY0IqdnXNOeTtP4r0lN9z7AAawCXgqea7bDii20AYrIBrFd/Hx0M2Ocz6S111CaFkUcb0Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.8.x"
+ }
+ },
+ "node_modules/expand-tilde": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz",
+ "integrity": "sha512-A5EmesHW6rfnZ9ysHQjPdJRni0SRar0tjtG5MNtm9n5TUvsYU8oozprtRD4AqHxcZWWlVuAmQo2nWKfN9oyjTw==",
+ "dev": true,
+ "dependencies": {
+ "homedir-polyfill": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/extend": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz",
+ "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==",
+ "dev": true
+ },
+ "node_modules/extend-shallow": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz",
+ "integrity": "sha512-BwY5b5Ql4+qZoefgMj2NUmx+tehVTH/Kf4k1ZEtOHNFcm2wSxMRo992l6X3TIgni2eZVTZ85xMOjF31fwZAj6Q==",
+ "dev": true,
+ "dependencies": {
+ "assign-symbols": "^1.0.0",
+ "is-extendable": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/fancy-log": {
+ "version": "1.3.3",
+ "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz",
+ "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-gray": "^0.1.1",
+ "color-support": "^1.1.3",
+ "parse-node-version": "^1.0.0",
+ "time-stamp": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/fast-fifo": {
+ "version": "1.3.2",
+ "resolved": "https://registry.npmjs.org/fast-fifo/-/fast-fifo-1.3.2.tgz",
+ "integrity": "sha512-/d9sfos4yxzpwkDkuN7k2SqFKtYNmCTzgfEpz82x34IM9/zc8KGxQoXg1liNC/izpRM/MBdt44Nmx41ZWqk+FQ==",
+ "dev": true
+ },
+ "node_modules/fast-levenshtein": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/fast-levenshtein/-/fast-levenshtein-3.0.0.tgz",
+ "integrity": "sha512-hKKNajm46uNmTlhHSyZkmToAc56uZJwYq7yrciZjqOxnlfQwERDQJmHPUp7m1m9wx8vgOe8IaCKZ5Kv2k1DdCQ==",
+ "dev": true,
+ "dependencies": {
+ "fastest-levenshtein": "^1.0.7"
+ }
+ },
+ "node_modules/fastest-levenshtein": {
+ "version": "1.0.16",
+ "resolved": "https://registry.npmjs.org/fastest-levenshtein/-/fastest-levenshtein-1.0.16.tgz",
+ "integrity": "sha512-eRnCtTTtGZFpQCwhJiUOuxPQWRXVKYDn0b2PeHfXL6/Zi53SLAzAHfVhVWK2AryC/WH05kGfxhFIPvTF0SXQzg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 4.9.1"
+ }
+ },
+ "node_modules/fastq": {
+ "version": "1.17.1",
+ "resolved": "https://registry.npmjs.org/fastq/-/fastq-1.17.1.tgz",
+ "integrity": "sha512-sRVD3lWVIXWg6By68ZN7vho9a1pQcN/WBFaAAsDDFzlJjvoGx0P8z7V1t72grFJfJhu3YPZBuu25f7Kaw2jN1w==",
+ "dev": true,
+ "dependencies": {
+ "reusify": "^1.0.4"
+ }
+ },
+ "node_modules/fflate": {
+ "version": "0.4.8",
+ "resolved": "https://registry.npmjs.org/fflate/-/fflate-0.4.8.tgz",
+ "integrity": "sha512-FJqqoDBR00Mdj9ppamLa/Y7vxm+PRmNWA67N846RvsoYVMKB4q3y/de5PA7gUmRMYK/8CMz2GDZQmCRN1wBcWA=="
+ },
+ "node_modules/file-saver": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/file-saver/-/file-saver-2.0.5.tgz",
+ "integrity": "sha512-P9bmyZ3h/PRG+Nzga+rbdI4OEpNDzAVyy74uVO9ATgzLK6VtAsYybF/+TOCvrc0MO793d6+42lLyZTw7/ArVzA=="
+ },
+ "node_modules/fill-range": {
+ "version": "7.1.1",
+ "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-7.1.1.tgz",
+ "integrity": "sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg==",
+ "dev": true,
+ "dependencies": {
+ "to-regex-range": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/findup-sync": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-5.0.0.tgz",
+ "integrity": "sha512-MzwXju70AuyflbgeOhzvQWAvvQdo1XL0A9bVvlXsYcFEBM87WR4OakL4OfZq+QRmr+duJubio+UtNQCPsVESzQ==",
+ "dev": true,
+ "dependencies": {
+ "detect-file": "^1.0.0",
+ "is-glob": "^4.0.3",
+ "micromatch": "^4.0.4",
+ "resolve-dir": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/fined": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/fined/-/fined-2.0.0.tgz",
+ "integrity": "sha512-OFRzsL6ZMHz5s0JrsEr+TpdGNCtrVtnuG3x1yzGNiQHT0yaDnXAj8V/lWcpJVrnoDpcwXcASxAZYbuXda2Y82A==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.2",
+ "is-plain-object": "^5.0.0",
+ "object.defaults": "^1.1.0",
+ "object.pick": "^1.3.0",
+ "parse-filepath": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/first-chunk-stream": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/first-chunk-stream/-/first-chunk-stream-5.0.0.tgz",
+ "integrity": "sha512-WdHo4ejd2cG2Dl+sLkW79SctU7mUQDfr4s1i26ffOZRs5mgv+BRttIM9gwcq0rDbemo0KlpVPaa3LBVLqPXzcQ==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/flagged-respawn": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-2.0.0.tgz",
+ "integrity": "sha512-Gq/a6YCi8zexmGHMuJwahTGzXlAZAOsbCVKduWXC6TlLCjjFRlExMJc4GC2NYPYZ0r/brw9P7CpRgQmlPVeOoA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/fontkit": {
+ "version": "1.9.0",
+ "resolved": "https://registry.npmjs.org/fontkit/-/fontkit-1.9.0.tgz",
+ "integrity": "sha512-HkW/8Lrk8jl18kzQHvAw9aTHe1cqsyx5sDnxncx652+CIfhawokEPkeM3BoIC+z/Xv7a0yMr0f3pRRwhGH455g==",
+ "dependencies": {
+ "@swc/helpers": "^0.3.13",
+ "brotli": "^1.3.2",
+ "clone": "^2.1.2",
+ "deep-equal": "^2.0.5",
+ "dfa": "^1.2.0",
+ "restructure": "^2.0.1",
+ "tiny-inflate": "^1.0.3",
+ "unicode-properties": "^1.3.1",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/for-each": {
+ "version": "0.3.3",
+ "resolved": "https://registry.npmjs.org/for-each/-/for-each-0.3.3.tgz",
+ "integrity": "sha512-jqYfLp7mo9vIyQf8ykW2v7A+2N4QjeCeI5+Dz9XraiO1ign81wjiH7Fb9vSOWvQfNtmSa4H2RoQTrrXivdUZmw==",
+ "dependencies": {
+ "is-callable": "^1.1.3"
+ }
+ },
+ "node_modules/for-in": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz",
+ "integrity": "sha512-7EwmXrOjyL+ChxMhmG5lnW9MPt1aIeZEwKhQzoBUdTV0N3zuwWDZYVJatDvZ2OyzPUvdIAZDsCetk3coyMfcnQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/for-own": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz",
+ "integrity": "sha512-0OABksIGrxKK8K4kynWkQ7y1zounQxP+CWnyclVwj81KW3vlLlGUx57DKGcP/LH216GzqnstnPocF16Nxs0Ycg==",
+ "dev": true,
+ "dependencies": {
+ "for-in": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/frac": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/frac/-/frac-1.1.2.tgz",
+ "integrity": "sha512-w/XBfkibaTl3YDqASwfDUqkna4Z2p9cFSr1aHDt0WoMTECnRfBOv2WArlZILlqgWlmdIlALXGpM2AOhEk5W3IA==",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/fs-mkdirp-stream": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-2.0.1.tgz",
+ "integrity": "sha512-UTOY+59K6IA94tec8Wjqm0FSh5OVudGNB0NL/P6fB3HiE3bYOY3VYBGijsnOHNkQSwC1FKkU77pmq7xp9CskLw==",
+ "dev": true,
+ "dependencies": {
+ "graceful-fs": "^4.2.8",
+ "streamx": "^2.12.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/fs.realpath": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz",
+ "integrity": "sha512-OO0pH2lK6a0hZnAdau5ItzHPI6pUlvI7jMVnxUQRtw4owF2wk8lOSabtGDCTP4Ggrg2MbGnWO9X8K1t4+fGMDw==",
+ "dev": true
+ },
+ "node_modules/fsevents": {
+ "version": "2.3.3",
+ "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-2.3.3.tgz",
+ "integrity": "sha512-5xoDfX+fL7faATnagmWPpbFtwh/R77WmMMqqHGS65C3vvB0YHrgF+B1YmZ3441tMj5n63k0212XNoJwzlhffQw==",
+ "dev": true,
+ "hasInstallScript": true,
+ "optional": true,
+ "os": [
+ "darwin"
+ ],
+ "engines": {
+ "node": "^8.16.0 || ^10.6.0 || >=11.0.0"
+ }
+ },
+ "node_modules/function-bind": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.2.tgz",
+ "integrity": "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/functions-have-names": {
+ "version": "1.2.3",
+ "resolved": "https://registry.npmjs.org/functions-have-names/-/functions-have-names-1.2.3.tgz",
+ "integrity": "sha512-xckBUXyTIqT97tq2x2AMb+g163b5JFysYk0x4qxNFwbfQkmNZoiRHb6sPzI9/QV33WeuvVYBUIiD4NzNIyqaRQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-caller-file": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-2.0.5.tgz",
+ "integrity": "sha512-DyFP3BM/3YHTQOCUL/w0OZHR0lpKeGrxotcHWcqNEdnltqFwXVfhEBQ94eIo34AfQpo0rGki4cyIiftY06h2Fg==",
+ "dev": true,
+ "engines": {
+ "node": "6.* || 8.* || >= 10.*"
+ }
+ },
+ "node_modules/get-intrinsic": {
+ "version": "1.2.4",
+ "resolved": "https://registry.npmjs.org/get-intrinsic/-/get-intrinsic-1.2.4.tgz",
+ "integrity": "sha512-5uYhsJH8VJBTv7oslg4BznJYhDoRI6waYCxMmCdnTrcCrHA/fCFKoTFz2JKKE0HdDFUF7/oQuhzumXJK7paBRQ==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "has-proto": "^1.0.1",
+ "has-symbols": "^1.0.3",
+ "hasown": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/get-own-enumerable-keys": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/get-own-enumerable-keys/-/get-own-enumerable-keys-1.0.0.tgz",
+ "integrity": "sha512-PKsK2FSrQCyxcGHsGrLDcK0lx+0Ke+6e8KFFozA9/fIQLhQzPaRvJFdcz7+Axg3jUH/Mq+NI4xa5u/UT2tQskA==",
+ "dev": true,
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/get-stream": {
+ "version": "9.0.1",
+ "resolved": "https://registry.npmjs.org/get-stream/-/get-stream-9.0.1.tgz",
+ "integrity": "sha512-kVCxPF3vQM/N0B1PmoqVUqgHP+EeVjmZSQn+1oCRPxd2P21P2F19lIgbR3HBosbB1PUhOAoctJnfEn2GbN2eZA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@sec-ant/readable-stream": "^0.4.1",
+ "is-stream": "^4.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/glob-parent": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-5.1.2.tgz",
+ "integrity": "sha512-AOIgSQCepiJYwP3ARnGx+5VnTu2HBYdzbGP45eLw1vr3zB3vZLeyed1sC9hnbcOc9/SrMyM5RPQrkGz4aS9Zow==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/glob-stream": {
+ "version": "8.0.2",
+ "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-8.0.2.tgz",
+ "integrity": "sha512-R8z6eTB55t3QeZMmU1C+Gv+t5UnNRkA55c5yo67fAVfxODxieTwsjNG7utxS/73NdP1NbDgCrhVEg2h00y4fFw==",
+ "dev": true,
+ "dependencies": {
+ "@gulpjs/to-absolute-glob": "^4.0.0",
+ "anymatch": "^3.1.3",
+ "fastq": "^1.13.0",
+ "glob-parent": "^6.0.2",
+ "is-glob": "^4.0.3",
+ "is-negated-glob": "^1.0.0",
+ "normalize-path": "^3.0.0",
+ "streamx": "^2.12.5"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-stream/node_modules/glob-parent": {
+ "version": "6.0.2",
+ "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-6.0.2.tgz",
+ "integrity": "sha512-XxwI8EOhVQgWp6iDL+3b0r86f4d6AX6zSU55HfB4ydCEuXLXc5FcYeOu+nnGftS4TEju/11rt4KJPTMgbfmv4A==",
+ "dev": true,
+ "dependencies": {
+ "is-glob": "^4.0.3"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/glob-watcher": {
+ "version": "6.0.0",
+ "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-6.0.0.tgz",
+ "integrity": "sha512-wGM28Ehmcnk2NqRORXFOTOR064L4imSw3EeOqU5bIwUf62eXGwg89WivH6VMahL8zlQHeodzvHpXplrqzrz3Nw==",
+ "dev": true,
+ "dependencies": {
+ "async-done": "^2.0.0",
+ "chokidar": "^3.5.3"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/global-modules": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz",
+ "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==",
+ "dev": true,
+ "dependencies": {
+ "global-prefix": "^1.0.1",
+ "is-windows": "^1.0.1",
+ "resolve-dir": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/global-prefix": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz",
+ "integrity": "sha512-5lsx1NUDHtSjfg0eHlmYvZKv8/nVqX4ckFbM+FrGcQ+04KWcWFo9P5MxPZYSzUvyzmdTbI7Eix8Q4IbELDqzKg==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.2",
+ "homedir-polyfill": "^1.0.1",
+ "ini": "^1.3.4",
+ "is-windows": "^1.0.1",
+ "which": "^1.2.14"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/global-prefix/node_modules/ini": {
+ "version": "1.3.8",
+ "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.8.tgz",
+ "integrity": "sha512-JV/yugV2uzW5iMRSiZAyDtQd+nxtUnjeLt0acNdw98kKLrvuRVyB80tsREOE7yvGVgalhZ6RNXCmEHkUKBKxew==",
+ "dev": true
+ },
+ "node_modules/global-prefix/node_modules/which": {
+ "version": "1.3.1",
+ "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz",
+ "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==",
+ "dev": true,
+ "dependencies": {
+ "isexe": "^2.0.0"
+ },
+ "bin": {
+ "which": "bin/which"
+ }
+ },
+ "node_modules/glogg": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz",
+ "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==",
+ "dev": true,
+ "dependencies": {
+ "sparkles": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/good-listener": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/good-listener/-/good-listener-1.2.2.tgz",
+ "integrity": "sha512-goW1b+d9q/HIwbVYZzZ6SsTr4IgE+WA44A0GmPIQstuOrgsFcT7VEJ48nmr9GaRtNu0XTKacFLGnBPAM6Afouw==",
+ "dependencies": {
+ "delegate": "^3.1.2"
+ }
+ },
+ "node_modules/gopd": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/gopd/-/gopd-1.0.1.tgz",
+ "integrity": "sha512-d65bNlIadxvpb/A2abVdlqKqV563juRnZ1Wtk6s1sIR8uNsXR70xqIzVqxVf1eTqDunwT2MkczEeaezCKTZhwA==",
+ "dependencies": {
+ "get-intrinsic": "^1.1.3"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/graceful-fs": {
+ "version": "4.2.11",
+ "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.2.11.tgz",
+ "integrity": "sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ==",
+ "dev": true
+ },
+ "node_modules/group-array": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/group-array/-/group-array-1.0.0.tgz",
+ "integrity": "sha512-PJresALe5TUzSIcdWKLdAKcdUDxv8du2EGueShgAL2xknbcTo5Bk1xbNaNhxpWxxAx/SV7N+5S0UyK7XV0+QhA==",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.1.0",
+ "for-own": "^1.0.0",
+ "get-value": "^3.0.1",
+ "kind-of": "^6.0.2",
+ "split-string": "^6.1.0",
+ "union-value": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/group-array/node_modules/get-value": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz",
+ "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/group-array/node_modules/kind-of": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz",
+ "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/group-array/node_modules/split-string": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/split-string/-/split-string-6.1.0.tgz",
+ "integrity": "sha512-9UBdnmnvx2NLLd4bMs7CEKK+wSzbujVv3ONyorkP1o8M3pVJQtXDO1cN19xD1JJs6ltOrtPrkUND0HzLSinUcA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/gulp": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/gulp/-/gulp-5.0.0.tgz",
+ "integrity": "sha512-S8Z8066SSileaYw1S2N1I64IUc/myI2bqe2ihOBzO6+nKpvNSg7ZcWJt/AwF8LC/NVN+/QZ560Cb/5OPsyhkhg==",
+ "dev": true,
+ "dependencies": {
+ "glob-watcher": "^6.0.0",
+ "gulp-cli": "^3.0.0",
+ "undertaker": "^2.0.0",
+ "vinyl-fs": "^4.0.0"
+ },
+ "bin": {
+ "gulp": "bin/gulp.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulp-clean": {
+ "version": "0.4.0",
+ "resolved": "https://registry.npmjs.org/gulp-clean/-/gulp-clean-0.4.0.tgz",
+ "integrity": "sha512-DARK8rNMo4lHOFLGTiHEJdf19GuoBDHqGUaypz+fOhrvOs3iFO7ntdYtdpNxv+AzSJBx/JfypF0yEj9ks1IStQ==",
+ "dev": true,
+ "dependencies": {
+ "fancy-log": "^1.3.2",
+ "plugin-error": "^0.1.2",
+ "rimraf": "^2.6.2",
+ "through2": "^2.0.3",
+ "vinyl": "^2.1.0"
+ },
+ "engines": {
+ "node": ">=0.9"
+ }
+ },
+ "node_modules/gulp-clean-css": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.3.0.tgz",
+ "integrity": "sha512-mGyeT3qqFXTy61j0zOIciS4MkYziF2U594t2Vs9rUnpkEHqfu6aDITMp8xOvZcvdX61Uz3y1mVERRYmjzQF5fg==",
+ "dev": true,
+ "dependencies": {
+ "clean-css": "4.2.3",
+ "plugin-error": "1.0.1",
+ "through2": "3.0.1",
+ "vinyl-sourcemaps-apply": "0.2.1"
+ }
+ },
+ "node_modules/gulp-clean-css/node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gulp-clean-css/node_modules/plugin-error": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
+ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^1.0.1",
+ "arr-diff": "^4.0.0",
+ "arr-union": "^3.1.0",
+ "extend-shallow": "^3.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/gulp-clean-css/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gulp-clean-css/node_modules/through2": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz",
+ "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "2 || 3"
+ }
+ },
+ "node_modules/gulp-cli": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-3.0.0.tgz",
+ "integrity": "sha512-RtMIitkT8DEMZZygHK2vEuLPqLPAFB4sntSxg4NoDta7ciwGZ18l7JuhCTiS5deOJi2IoK0btE+hs6R4sfj7AA==",
+ "dev": true,
+ "dependencies": {
+ "@gulpjs/messages": "^1.1.0",
+ "chalk": "^4.1.2",
+ "copy-props": "^4.0.0",
+ "gulplog": "^2.2.0",
+ "interpret": "^3.1.1",
+ "liftoff": "^5.0.0",
+ "mute-stdout": "^2.0.0",
+ "replace-homedir": "^2.0.0",
+ "semver-greatest-satisfied-range": "^2.0.0",
+ "string-width": "^4.2.3",
+ "v8flags": "^4.0.0",
+ "yargs": "^16.2.0"
+ },
+ "bin": {
+ "gulp": "bin/gulp.js"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulp-cli/node_modules/ansi-styles": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-4.3.0.tgz",
+ "integrity": "sha512-zbB9rCJAT1rbjiVDb2hqKFHNYLxgtk8NURxZ3IZwD3F6NtxbXZQCnnSi1Lkx+IDohdPlFp222wVALIheZJQSEg==",
+ "dev": true,
+ "dependencies": {
+ "color-convert": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/ansi-styles?sponsor=1"
+ }
+ },
+ "node_modules/gulp-cli/node_modules/chalk": {
+ "version": "4.1.2",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-4.1.2.tgz",
+ "integrity": "sha512-oKnbhFyRIXpUuez8iBMmyEa4nbj4IOQyuhc/wy9kY7/WVPcwIO9VA668Pu8RkO7+0G76SLROeyw9CpQ061i4mA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-styles": "^4.1.0",
+ "supports-color": "^7.1.0"
+ },
+ "engines": {
+ "node": ">=10"
+ },
+ "funding": {
+ "url": "https://github.com/chalk/chalk?sponsor=1"
+ }
+ },
+ "node_modules/gulp-cli/node_modules/glogg": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/glogg/-/glogg-2.2.0.tgz",
+ "integrity": "sha512-eWv1ds/zAlz+M1ioHsyKJomfY7jbDDPpwSkv14KQj89bycx1nvK5/2Cj/T9g7kzJcX5Bc7Yv22FjfBZS/jl94A==",
+ "dev": true,
+ "dependencies": {
+ "sparkles": "^2.1.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/gulp-cli/node_modules/gulplog": {
+ "version": "2.2.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-2.2.0.tgz",
+ "integrity": "sha512-V2FaKiOhpR3DRXZuYdRLn/qiY0yI5XmqbTKrYbdemJ+xOh2d2MOweI/XFgMzd/9+1twdvMwllnZbWZNJ+BOm4A==",
+ "dev": true,
+ "dependencies": {
+ "glogg": "^2.2.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/gulp-cli/node_modules/sparkles": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-2.1.0.tgz",
+ "integrity": "sha512-r7iW1bDw8R/cFifrD3JnQJX0K1jqT0kprL48BiBpLZLJPmAm34zsVBsK5lc7HirZYZqMW65dOXZgbAGt/I6frg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/gulp-concat": {
+ "version": "2.6.1",
+ "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz",
+ "integrity": "sha512-a2scActrQrDBpBbR3WUZGyGS1JEPLg5PZJdIa7/Bi3GuKAmPYDK6SFhy/NZq5R8KsKKFvtfR0fakbUCcKGCCjg==",
+ "dev": true,
+ "dependencies": {
+ "concat-with-sourcemaps": "^1.0.0",
+ "through2": "^2.0.0",
+ "vinyl": "^2.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/gulp-debug": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/gulp-debug/-/gulp-debug-5.0.1.tgz",
+ "integrity": "sha512-2MZFfzg95/6JlfKchX+ZY+6Awn2KoEvg4GeJh+uVi/lwD3W4LEeLDo3SfQEFBF9X5jhQYgUazKD/xyxd2dG9cw==",
+ "dev": true,
+ "dependencies": {
+ "chalk": "^5.3.0",
+ "gulp-plugin-extras": "^0.3.0",
+ "plur": "^5.1.0",
+ "stringify-object": "^5.0.0",
+ "tildify": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ },
+ "peerDependencies": {
+ "gulp": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "gulp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/gulp-gzip": {
+ "version": "1.4.2",
+ "resolved": "https://registry.npmjs.org/gulp-gzip/-/gulp-gzip-1.4.2.tgz",
+ "integrity": "sha512-ZIxfkUwk2XmZPTT9pPHrHUQlZMyp9nPhg2sfoeN27mBGpi7OaHnOD+WCN41NXjfJQ69lV1nQ9LLm1hYxx4h3UQ==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^1.0.1",
+ "bytes": "^3.0.0",
+ "fancy-log": "^1.3.2",
+ "plugin-error": "^1.0.0",
+ "stream-to-array": "^2.3.0",
+ "through2": "^2.0.3"
+ },
+ "engines": {
+ "node": ">= 0.10.0"
+ }
+ },
+ "node_modules/gulp-gzip/node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gulp-gzip/node_modules/plugin-error": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
+ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^1.0.1",
+ "arr-diff": "^4.0.0",
+ "arr-union": "^3.1.0",
+ "extend-shallow": "^3.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/gulp-header": {
+ "version": "2.0.9",
+ "resolved": "https://registry.npmjs.org/gulp-header/-/gulp-header-2.0.9.tgz",
+ "integrity": "sha512-LMGiBx+qH8giwrOuuZXSGvswcIUh0OiioNkUpLhNyvaC6/Ga8X6cfAeme2L5PqsbXMhL8o8b/OmVqIQdxprhcQ==",
+ "dev": true,
+ "dependencies": {
+ "concat-with-sourcemaps": "^1.1.0",
+ "lodash.template": "^4.5.0",
+ "map-stream": "0.0.7",
+ "through2": "^2.0.0"
+ }
+ },
+ "node_modules/gulp-inject": {
+ "version": "5.0.5",
+ "resolved": "https://registry.npmjs.org/gulp-inject/-/gulp-inject-5.0.5.tgz",
+ "integrity": "sha512-5bGMjqleXUHPu4CI1pnVzHtwyMy+Zt8EMo1RFwNsOpidPxwjFwyLgmsRZWGMMI8UenJMJRjURqwznfFmqb5wgw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^4.1.1",
+ "arrify": "^2.0.1",
+ "escape-string-regexp": "^2.0.0",
+ "fancy-log": "^1.3.3",
+ "group-array": "^1.0.0",
+ "plugin-error": "^1.0.1",
+ "stream-to-array": "^2.3.0",
+ "through2": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/ansi-colors": {
+ "version": "4.1.3",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-4.1.3.tgz",
+ "integrity": "sha512-/6w/C21Pm1A7aZitlI5Ni/2J6FFQN8i1Cvz3kHABAAbw93v/NlvKdVOqz7CCWz/3iv/JplRSEEZ83XION15ovw==",
+ "dev": true,
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/arr-union": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz",
+ "integrity": "sha512-sKpyeERZ02v1FeCZT8lrfJq5u6goHCtpTAzPwJYe7c8SPFOboNjNg1vz2L4VTn9T4PQxEx13TbXLmYUcS6Ug7Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/plugin-error": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz",
+ "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^1.0.1",
+ "arr-diff": "^4.0.0",
+ "arr-union": "^3.1.0",
+ "extend-shallow": "^3.0.2"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/plugin-error/node_modules/ansi-colors": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz",
+ "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==",
+ "dev": true,
+ "dependencies": {
+ "ansi-wrap": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/readable-stream": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-3.6.2.tgz",
+ "integrity": "sha512-9u/sniCrY3D5WdsERHzHE4G2YCXqoG5FTHUiCC4SIbr6XcLZBY05ya9EKjYek9O5xOAwjGq+1JdGBAS7Q9ScoA==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.3",
+ "string_decoder": "^1.1.1",
+ "util-deprecate": "^1.0.1"
+ },
+ "engines": {
+ "node": ">= 6"
+ }
+ },
+ "node_modules/gulp-inject/node_modules/through2": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.2.tgz",
+ "integrity": "sha512-enaDQ4MUyP2W6ZyT6EsMzqBPZaM/avg8iuo+l2d3QCs0J+6RaqkHV/2/lOwDTueBHeJ/2LG9lrLW3d5rWPucuQ==",
+ "dev": true,
+ "dependencies": {
+ "inherits": "^2.0.4",
+ "readable-stream": "2 || 3"
+ }
+ },
+ "node_modules/gulp-plugin-extras": {
+ "version": "0.3.0",
+ "resolved": "https://registry.npmjs.org/gulp-plugin-extras/-/gulp-plugin-extras-0.3.0.tgz",
+ "integrity": "sha512-I/kOBSpo61QsGQZcqozZYEnDseKvpudUafVVWDLYgBFAUJ37kW5R8Sjw9cMYzpGyPUfEYOeoY4p+dkfLqgyJUQ==",
+ "dev": true,
+ "dependencies": {
+ "@types/vinyl": "^2.0.9",
+ "chalk": "^5.3.0",
+ "easy-transform-stream": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gulp-rename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/gulp-rename/-/gulp-rename-2.0.0.tgz",
+ "integrity": "sha512-97Vba4KBzbYmR5VBs9mWmK+HwIf5mj+/zioxfZhOKeXtx5ZjBk57KFlePf5nxq9QsTtFl0ejnHE3zTC9MHXqyQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=4"
+ }
+ },
+ "node_modules/gulp-rev": {
+ "version": "10.0.0",
+ "resolved": "https://registry.npmjs.org/gulp-rev/-/gulp-rev-10.0.0.tgz",
+ "integrity": "sha512-5mP6oOGp1DUzBQuiy9IrtyAWHWUOz2n1qLUHfo7LU0p111t7sTkUhKW01b70B2MsDWgScTdz6sGLg76KCbqclw==",
+ "dev": true,
+ "dependencies": {
+ "easy-transform-stream": "^1.0.0",
+ "modify-filename": "^2.0.0",
+ "plugin-error": "^2.0.1",
+ "rev-hash": "^4.0.0",
+ "rev-path": "^3.0.0",
+ "sort-keys": "^5.0.0",
+ "vinyl": "^3.0.0",
+ "vinyl-file": "^5.0.0"
+ },
+ "engines": {
+ "node": ">=16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ },
+ "peerDependencies": {
+ "gulp": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "gulp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/gulp-rev/node_modules/plugin-error": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-2.0.1.tgz",
+ "integrity": "sha512-zMakqvIDyY40xHOvzXka0kUvf40nYIuwRE8dWhti2WtjQZ31xAgBZBhxsK7vK3QbRXS1Xms/LO7B5cuAsfB2Gg==",
+ "dev": true,
+ "dependencies": {
+ "ansi-colors": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulp-rev/node_modules/replace-ext": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
+ "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/gulp-rev/node_modules/vinyl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
+ "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.2",
+ "clone-stats": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0",
+ "replace-ext": "^2.0.0",
+ "teex": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulp-run": {
+ "version": "1.7.1",
+ "resolved": "https://registry.npmjs.org/gulp-run/-/gulp-run-1.7.1.tgz",
+ "integrity": "sha512-4OcXhBE5xpRWmbcKzE0EQWEqpLRAkX3ju6k85qkYLfmnCVGK6nPmu/sbVgDiGg6mjuzsF2b9nHFbImZBZPH3zg==",
+ "dev": true,
+ "license": "ISC",
+ "dependencies": {
+ "gulp-util": "^3.0.0",
+ "lodash.defaults": "^4.0.1",
+ "lodash.template": "^4.0.2",
+ "vinyl": "^0.4.6"
+ }
+ },
+ "node_modules/gulp-run/node_modules/clone": {
+ "version": "0.2.0",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-0.2.0.tgz",
+ "integrity": "sha512-g62n3Kb9cszeZvmvBUqP/dsEJD/+80pDA8u8KqHnAPrVnQ2Je9rVV6opxkhuWCd1kCn2gOibzDKxCtBvD3q5kA==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/gulp-run/node_modules/clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/gulp-run/node_modules/vinyl": {
+ "version": "0.4.6",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.4.6.tgz",
+ "integrity": "sha512-pmza4M5VA15HOImIQYWhoXGlGNafCm0QK5BpBUXkzzEwrRxKqBsbAhTfkT2zMcJhUX1G1Gkid0xaV8WjOl7DsA==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^0.2.0",
+ "clone-stats": "^0.0.1"
+ },
+ "engines": {
+ "node": ">= 0.9"
+ }
+ },
+ "node_modules/gulp-tar": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/gulp-tar/-/gulp-tar-4.0.0.tgz",
+ "integrity": "sha512-lvBYoWV+I+0DVmjylWw/TZtHdQAQ9cVaqQ+u/fWcB8Hth3k4BKAT5EpLBoJiiU77ZXZmEgdPWzJ9KZmCuVCyFA==",
+ "dev": true,
+ "dependencies": {
+ "archiver": "^6.0.1",
+ "gulp-plugin-extras": "^0.3.0",
+ "vinyl": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ },
+ "peerDependencies": {
+ "gulp": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "gulp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/gulp-tar/node_modules/replace-ext": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
+ "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/gulp-tar/node_modules/vinyl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
+ "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.2",
+ "clone-stats": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0",
+ "replace-ext": "^2.0.0",
+ "teex": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulp-uglify": {
+ "version": "3.0.2",
+ "resolved": "https://registry.npmjs.org/gulp-uglify/-/gulp-uglify-3.0.2.tgz",
+ "integrity": "sha512-gk1dhB74AkV2kzqPMQBLA3jPoIAPd/nlNzP2XMDSG8XZrqnlCiDGAqC+rZOumzFvB5zOphlFh6yr3lgcAb/OOg==",
+ "dev": true,
+ "dependencies": {
+ "array-each": "^1.0.1",
+ "extend-shallow": "^3.0.2",
+ "gulplog": "^1.0.0",
+ "has-gulplog": "^0.1.0",
+ "isobject": "^3.0.1",
+ "make-error-cause": "^1.1.1",
+ "safe-buffer": "^5.1.2",
+ "through2": "^2.0.0",
+ "uglify-js": "^3.0.5",
+ "vinyl-sourcemaps-apply": "^0.2.0"
+ }
+ },
+ "node_modules/gulp-util": {
+ "version": "3.0.8",
+ "resolved": "https://registry.npmjs.org/gulp-util/-/gulp-util-3.0.8.tgz",
+ "integrity": "sha512-q5oWPc12lwSFS9h/4VIjG+1NuNDlJ48ywV2JKItY4Ycc/n1fXJeYPVQsfu5ZrhQi7FGSDBalwUCLar/GyHXKGw==",
+ "deprecated": "gulp-util is deprecated - replace it, following the guidelines at https://medium.com/gulpjs/gulp-util-ca3b1f9f9ac5",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "array-differ": "^1.0.0",
+ "array-uniq": "^1.0.2",
+ "beeper": "^1.0.0",
+ "chalk": "^1.0.0",
+ "dateformat": "^2.0.0",
+ "fancy-log": "^1.1.0",
+ "gulplog": "^1.0.0",
+ "has-gulplog": "^0.1.0",
+ "lodash._reescape": "^3.0.0",
+ "lodash._reevaluate": "^3.0.0",
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.template": "^3.0.0",
+ "minimist": "^1.1.0",
+ "multipipe": "^0.1.2",
+ "object-assign": "^3.0.0",
+ "replace-ext": "0.0.1",
+ "through2": "^2.0.0",
+ "vinyl": "^0.5.0"
+ },
+ "engines": {
+ "node": ">=0.10"
+ }
+ },
+ "node_modules/gulp-util/node_modules/chalk": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz",
+ "integrity": "sha512-U3lRVLMSlsCfjqYPbLyVv11M9CPW4I728d6TCKMAOJueEeB9/8o+eSsMnxPJD+Q+K909sdESg7C+tIkoH6on1A==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-styles": "^2.2.1",
+ "escape-string-regexp": "^1.0.2",
+ "has-ansi": "^2.0.0",
+ "strip-ansi": "^3.0.0",
+ "supports-color": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/gulp-util/node_modules/clone": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/clone/-/clone-1.0.4.tgz",
+ "integrity": "sha512-JQHZ2QMW6l3aH/j6xCqQThY/9OH4D/9ls34cgkUBiEeocRTU04tHfKPBsUK1PqZCUQM7GiA0IIXJSuXHI64Kbg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/gulp-util/node_modules/clone-stats": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-0.0.1.tgz",
+ "integrity": "sha512-dhUqc57gSMCo6TX85FLfe51eC/s+Im2MLkAgJwfaRRexR2tA4dd3eLEW4L6efzHc2iNorrRRXITifnDLlRrhaA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/gulp-util/node_modules/escape-string-regexp": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz",
+ "integrity": "sha512-vbRorB5FUQWvla16U8R/qgaFIya2qGzwDrNmCZuYKrbdSUMG6I1ZCGQRefkRVhuOkIGVne7BQ35DSfo1qvJqFg==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/gulp-util/node_modules/lodash.template": {
+ "version": "3.6.2",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-3.6.2.tgz",
+ "integrity": "sha512-0B4Y53I0OgHUJkt+7RmlDFWKjVAI/YUpWNiL9GQz5ORDr4ttgfQGo+phBWKFLJbBdtOwgMuUkdOHOnPg45jKmQ==",
+ "deprecated": "This package is deprecated. Use https://socket.dev/npm/package/eta instead.",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash._basecopy": "^3.0.0",
+ "lodash._basetostring": "^3.0.0",
+ "lodash._basevalues": "^3.0.0",
+ "lodash._isiterateecall": "^3.0.0",
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.escape": "^3.0.0",
+ "lodash.keys": "^3.0.0",
+ "lodash.restparam": "^3.0.0",
+ "lodash.templatesettings": "^3.0.0"
+ }
+ },
+ "node_modules/gulp-util/node_modules/lodash.templatesettings": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-3.1.1.tgz",
+ "integrity": "sha512-TcrlEr31tDYnWkHFWDCV3dHYroKEXpJZ2YJYvJdhN+y4AkWMDZ5I4I8XDtUKqSAyG81N7w+I1mFEJtcED+tGqQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.escape": "^3.0.0"
+ }
+ },
+ "node_modules/gulp-util/node_modules/replace-ext": {
+ "version": "0.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-0.0.1.tgz",
+ "integrity": "sha512-AFBWBy9EVRTa/LhEcG8QDP3FvpwZqmvN2QFDuJswFeaVhWnZMp8q3E6Zd90SR04PlIwfGdyVjNyLPyen/ek5CQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/gulp-util/node_modules/supports-color": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz",
+ "integrity": "sha512-KKNVtd6pCYgPIKU4cp2733HWYCpplQhddZLBUryaAHou723x+FRzQ5Df824Fj+IyyuiQTRoub4SnIFfIcrp70g==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/gulp-util/node_modules/vinyl": {
+ "version": "0.5.3",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-0.5.3.tgz",
+ "integrity": "sha512-P5zdf3WB9uzr7IFoVQ2wZTmUwHL8cMZWJGzLBNCHNZ3NB6HTMsYABtt7z8tAGIINLXyAob9B9a1yzVGMFOYKEA==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "clone": "^1.0.0",
+ "clone-stats": "^0.0.1",
+ "replace-ext": "0.0.1"
+ },
+ "engines": {
+ "node": ">= 0.9"
+ }
+ },
+ "node_modules/gulp-zip": {
+ "version": "6.1.0",
+ "resolved": "https://registry.npmjs.org/gulp-zip/-/gulp-zip-6.1.0.tgz",
+ "integrity": "sha512-couiqfO4CSM4q3oKnihLhYq5mVmwyXfgLP/0eeM7oVlN+psn45vfvJHcCL3AkPgTi4NojnUFV2IozYqZClIujQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "get-stream": "^9.0.1",
+ "gulp-plugin-extras": "^1.1.0",
+ "vinyl": "^3.0.0",
+ "yazl": "^3.3.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ },
+ "peerDependencies": {
+ "gulp": ">=4"
+ },
+ "peerDependenciesMeta": {
+ "gulp": {
+ "optional": true
+ }
+ }
+ },
+ "node_modules/gulp-zip/node_modules/gulp-plugin-extras": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/gulp-plugin-extras/-/gulp-plugin-extras-1.1.0.tgz",
+ "integrity": "sha512-T0AXOEVoKYzLIBlwEZ7LtAx2w4ExIozIoxVeYEVLFbdxI7i0sWvFDq0F8mm47djixDF3vAqDPoyGwh3Sg/PWtQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "@types/vinyl": "^2.0.12",
+ "chalk": "^5.3.0",
+ "easy-transform-stream": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/gulp-zip/node_modules/replace-ext": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
+ "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/gulp-zip/node_modules/vinyl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
+ "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.2",
+ "clone-stats": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0",
+ "replace-ext": "^2.0.0",
+ "teex": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/gulplog": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz",
+ "integrity": "sha512-hm6N8nrm3Y08jXie48jsC55eCZz9mnb4OirAStEk2deqeyhXU3C1otDVh+ccttMuc1sBi6RX6ZJ720hs9RCvgw==",
+ "dev": true,
+ "dependencies": {
+ "glogg": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/has-ansi": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz",
+ "integrity": "sha512-C8vBJ8DwUCx19vhm7urhTuUsr4/IyP6l4VzNQDv+ryHQObW3TTTp9yB68WpYgRe2bbaGuZ/se74IqFeVnMnLZg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/has-bigints": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-bigints/-/has-bigints-1.0.2.tgz",
+ "integrity": "sha512-tSvCKtBr9lkF0Ex0aQiP9N+OpV4zi2r/Nee5VkRDbaqv35RLYMzbwQfFSZZH0kR+Rd6302UJZ2p/bJCEoR3VoQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-flag": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-4.0.0.tgz",
+ "integrity": "sha512-EykJT/Q1KjTWctppgIAgfSO0tKVuZUjhgMr17kqTumMl6Afv3EISleU7qZUzoXDFTAHTDC4NOoG/ZxU3EvlMPQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/has-gulplog": {
+ "version": "0.1.0",
+ "resolved": "https://registry.npmjs.org/has-gulplog/-/has-gulplog-0.1.0.tgz",
+ "integrity": "sha512-+F4GzLjwHNNDEAJW2DC1xXfEoPkRDmUdJ7CBYw4MpqtDwOnqdImJl7GWlpqx+Wko6//J8uKTnIe4wZSv7yCqmw==",
+ "dev": true,
+ "dependencies": {
+ "sparkles": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/has-property-descriptors": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-property-descriptors/-/has-property-descriptors-1.0.2.tgz",
+ "integrity": "sha512-55JNKuIW+vq4Ke1BjOTjM2YctQIvCT7GFzHwmfZPGo5wnrgkid0YQtnAleFSqumZm4az3n2BS+erby5ipJdgrg==",
+ "dependencies": {
+ "es-define-property": "^1.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-proto": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-proto/-/has-proto-1.0.3.tgz",
+ "integrity": "sha512-SJ1amZAJUiZS+PhsVLf5tGydlaVB8EdFpaSO4gmiUKUOxk8qzn5AIy4ZeJUmh22znIdk/uMAUT2pl3FxzVUH+Q==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-symbols": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.3.tgz",
+ "integrity": "sha512-l3LCuF6MgDNwTDKkdYGEihYjt5pRPbEg46rtlmnSPlUbgmB8LOIrKJbYYFBSbnPaJexMKtiPO8hmeRjRz2Td+A==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/has-tostringtag": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/has-tostringtag/-/has-tostringtag-1.0.2.tgz",
+ "integrity": "sha512-NqADB8VjPFLM2V0VvHUewwwsw0ZWBaIdgo+ieHtK3hasLz4qeCRjYcqfB6AQrBggRKppKF8L52/VqdVsO47Dlw==",
+ "dependencies": {
+ "has-symbols": "^1.0.3"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/hasown": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/hasown/-/hasown-2.0.2.tgz",
+ "integrity": "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ==",
+ "dependencies": {
+ "function-bind": "^1.1.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/homedir-polyfill": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz",
+ "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==",
+ "dev": true,
+ "dependencies": {
+ "parse-passwd": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/html2canvas": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/html2canvas/-/html2canvas-1.4.1.tgz",
+ "integrity": "sha512-fPU6BHNpsyIhr8yyMpTLLxAbkaK8ArIBcmZIRiBLiDhjeqvXolaEmDGmELFuX9I4xDcaKKcJl+TKZLqruBbmWA==",
+ "dependencies": {
+ "css-line-break": "^2.1.0",
+ "text-segmentation": "^1.0.3"
+ },
+ "engines": {
+ "node": ">=8.0.0"
+ }
+ },
+ "node_modules/iconv-lite": {
+ "version": "0.6.3",
+ "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.6.3.tgz",
+ "integrity": "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw==",
+ "dependencies": {
+ "safer-buffer": ">= 2.1.2 < 3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/ieee754": {
+ "version": "1.2.1",
+ "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.2.1.tgz",
+ "integrity": "sha512-dcyqhDvX1C46lXZcVqCpK+FtMRQVdIMN6/Df5js2zouUsqG7I6sFxitIC+7KYK29KdXOLHdu9zL4sFnoVQnqaA==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/inflight": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz",
+ "integrity": "sha512-k92I/b08q4wvFscXCLvqfsHCrjrF7yiXsQuIVvVE7N82W3+aqpzuUdBbfhWcy/FZR3/4IgflMgKLOsvPDrGCJA==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.3.0",
+ "wrappy": "1"
+ }
+ },
+ "node_modules/inherits": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.4.tgz",
+ "integrity": "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ==",
+ "dev": true
+ },
+ "node_modules/internal-slot": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/internal-slot/-/internal-slot-1.0.7.tgz",
+ "integrity": "sha512-NGnrKwXzSms2qUUih/ILZ5JBqNTSa1+ZmP6flaIp6KmSElgE9qdndzS3cqjrDovwFdmwsGsLdeFgB6suw+1e9g==",
+ "dependencies": {
+ "es-errors": "^1.3.0",
+ "hasown": "^2.0.0",
+ "side-channel": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/interpret": {
+ "version": "3.1.1",
+ "resolved": "https://registry.npmjs.org/interpret/-/interpret-3.1.1.tgz",
+ "integrity": "sha512-6xwYfHbajpoF0xLW+iwLkhwgvLoZDfjYfoFNu8ftMoXINzwuymNLd9u/KmwtdT2GbR+/Cz66otEGEVVUHX9QLQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/irregular-plurals": {
+ "version": "3.5.0",
+ "resolved": "https://registry.npmjs.org/irregular-plurals/-/irregular-plurals-3.5.0.tgz",
+ "integrity": "sha512-1ANGLZ+Nkv1ptFb2pa8oG8Lem4krflKuX/gINiHJHjJUKaJHk/SXk5x6K3J+39/p0h1RQ2saROclJJ+QLvETCQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-absolute": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz",
+ "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==",
+ "dev": true,
+ "dependencies": {
+ "is-relative": "^1.0.0",
+ "is-windows": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-arguments": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/is-arguments/-/is-arguments-1.1.1.tgz",
+ "integrity": "sha512-8Q7EARjzEnKpt/PCD7e1cgUS0a6X8u5tdSiMqXhojOdoV9TsMsiO+9VLC5vAmO8N7/GmXn7yjR8qnA6bVAEzfA==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-array-buffer": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/is-array-buffer/-/is-array-buffer-3.0.4.tgz",
+ "integrity": "sha512-wcjaerHw0ydZwfhiKbXJWLDY8A7yV7KhjQOpb83hGgGfId/aQa4TOvwyzn2PuswW2gPCYEL/nEAiSVpdOj1lXw==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "get-intrinsic": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-bigint": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-bigint/-/is-bigint-1.0.4.tgz",
+ "integrity": "sha512-zB9CruMamjym81i2JZ3UMn54PKGsQzsJeo6xvN3HJJ4CAsQNB6iRutp2To77OfCNuoxspsIhzaPoO1zyCEhFOg==",
+ "dependencies": {
+ "has-bigints": "^1.0.1"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-binary-path": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-2.1.0.tgz",
+ "integrity": "sha512-ZMERYes6pDydyuGidse7OsHxtbI7WVeUEozgR/g7rd0xUimYNlvZRE/K2MgZTjWy725IfelLeVcEM97mmtRGXw==",
+ "dev": true,
+ "dependencies": {
+ "binary-extensions": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-boolean-object": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/is-boolean-object/-/is-boolean-object-1.1.2.tgz",
+ "integrity": "sha512-gDYaKHJmnj4aWxyj6YHyXVpdQawtVLHU5cb+eztPGczf6cjuTdwve5ZIEfgXqH4e57An1D1AKf8CZ3kYrQRqYA==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-callable": {
+ "version": "1.2.7",
+ "resolved": "https://registry.npmjs.org/is-callable/-/is-callable-1.2.7.tgz",
+ "integrity": "sha512-1BC0BVFhS/p0qtw6enp8e+8OD0UrK0oFLztSjNzhcKA3WDuJxxAPXzPuPtKkjEY9UUoEWlX/8fgKeu2S8i9JTA==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-core-module": {
+ "version": "2.13.1",
+ "resolved": "https://registry.npmjs.org/is-core-module/-/is-core-module-2.13.1.tgz",
+ "integrity": "sha512-hHrIjvZsftOsvKSn2TRYl63zvxsgE0K+0mYMoH6gD4omR5IWB2KynivBQczo3+wF1cCkjzvptnI9Q0sPU66ilw==",
+ "dev": true,
+ "dependencies": {
+ "hasown": "^2.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-date-object": {
+ "version": "1.0.5",
+ "resolved": "https://registry.npmjs.org/is-date-object/-/is-date-object-1.0.5.tgz",
+ "integrity": "sha512-9YQaSxsAiSwcvS33MBk3wTCVnWK+HhF8VZR2jRxehM16QcVOdHqPn4VPHmRK4lSr38n9JriurInLcP90xsYNfQ==",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-extendable": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz",
+ "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extendable/node_modules/is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-extglob": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz",
+ "integrity": "sha512-SbKbANkN603Vi4jEZv49LeVJMn4yGwsbzZworEoyEiutsN3nJYdbO36zfhGJ6QEDpOZIFkDtnq5JRxmvl3jsoQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-fullwidth-code-point": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-3.0.0.tgz",
+ "integrity": "sha512-zymm5+u+sCsSWyD9qNaejV3DFvhCKclKdizYaJUuHA83RLjb7nSuGnddCHGv0hk+KY7BMAlsWeK4Ueg6EV6XQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/is-glob": {
+ "version": "4.0.3",
+ "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.3.tgz",
+ "integrity": "sha512-xelSayHH36ZgE7ZWhli7pW34hNbNl8Ojv5KVmkJD4hBdD3th8Tfk9vYasLM+mXWOZhFkgZfxhLSnrwRr4elSSg==",
+ "dev": true,
+ "dependencies": {
+ "is-extglob": "^2.1.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-map": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-map/-/is-map-2.0.3.tgz",
+ "integrity": "sha512-1Qed0/Hr2m+YqxnM09CjA2d/i6YZNfF6R2oRAOj36eUdS6qIV/huPJNSEpKbupewFs+ZsJlxsjjPbc0/afW6Lw==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-negated-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz",
+ "integrity": "sha512-czXVVn/QEmgvej1f50BZ648vUI+em0xqMq2Sn+QncCLN4zj1UAxlT+kw/6ggQTOaZPd1HqKQGEqbpQVtJucWug==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-number": {
+ "version": "7.0.0",
+ "resolved": "https://registry.npmjs.org/is-number/-/is-number-7.0.0.tgz",
+ "integrity": "sha512-41Cifkg6e8TylSpdtTpeLVMqvSBEVzTttHvERD741+pnZ8ANv0004MRL43QKPDlK9cGvNp6NZWZUBlbGXYxxng==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.12.0"
+ }
+ },
+ "node_modules/is-number-object": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-number-object/-/is-number-object-1.0.7.tgz",
+ "integrity": "sha512-k1U0IRzLMo7ZlYIfzRu23Oh6MiIFasgpb9X76eqfFZAqwH44UI4KTBvBYIZ1dSL9ZzChTB9ShHfLkR4pdW5krQ==",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-obj": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/is-obj/-/is-obj-3.0.0.tgz",
+ "integrity": "sha512-IlsXEHOjtKhpN8r/tRFj2nDyTmHvcfNeu/nrRIcXE17ROeatXchkojffa1SpdqW4cr/Fj6QkEf/Gn4zf6KKvEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-plain-obj": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/is-plain-obj/-/is-plain-obj-4.1.0.tgz",
+ "integrity": "sha512-+Pgi+vMuUNkJyExiMBt5IlFoMyKnr5zhJ4Uspz58WOhBF5QoIZkFyNHIbBAtHwzVAgk5RtndVNsDRN61/mmDqg==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-plain-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-5.0.0.tgz",
+ "integrity": "sha512-VRSzKkbMm5jMDoKLbltAkFQ5Qr7VDiTFGXxYFXXowVj387GeGNOCsOH6Msy00SGZ3Fp84b1Naa1psqgcCIEP5Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-regex": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/is-regex/-/is-regex-1.1.4.tgz",
+ "integrity": "sha512-kvRdxDsxZjhzUX07ZnLydzS1TU/TJlTUHHY4YLL87e37oUA49DfkLqgy+VjFocowy29cKvcSiu+kIv728jTTVg==",
+ "dependencies": {
+ "call-bind": "^1.0.2",
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-regexp": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/is-regexp/-/is-regexp-3.1.0.tgz",
+ "integrity": "sha512-rbku49cWloU5bSMI+zaRaXdQHXnthP6DZ/vLnfdSKyL4zUzuWnomtOEiZZOd+ioQ+avFo/qau3KPTc7Fjy1uPA==",
+ "dev": true,
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-relative": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz",
+ "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==",
+ "dev": true,
+ "dependencies": {
+ "is-unc-path": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-set": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-set/-/is-set-2.0.3.tgz",
+ "integrity": "sha512-iPAjerrse27/ygGLxw+EBR9agv9Y6uLeYVJMu+QNCoouJ1/1ri0mGrcWpfCqFZuzzx3WjtwxG098X+n4OuRkPg==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-shared-array-buffer": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/is-shared-array-buffer/-/is-shared-array-buffer-1.0.3.tgz",
+ "integrity": "sha512-nA2hv5XIhLR3uVzDDfCIknerhx8XUKnstuOERPNNIinXG7v9u+ohXF67vxm4TPTEPU6lm61ZkwP3c9PCB97rhg==",
+ "dependencies": {
+ "call-bind": "^1.0.7"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-stream": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/is-stream/-/is-stream-4.0.1.tgz",
+ "integrity": "sha512-Dnz92NInDqYckGEUJv689RbRiTSEHCQ7wOVeALbkOz999YpqT46yMRIGtSNl2iCL1waAZSx40+h59NV/EwzV/A==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=18"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/is-string": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/is-string/-/is-string-1.0.7.tgz",
+ "integrity": "sha512-tE2UXzivje6ofPW7l23cjDOMa09gb7xlAqG6jG5ej6uPV32TlWP3NKPigtaGeHNu9fohccRYvIiZMfOOnOYUtg==",
+ "dependencies": {
+ "has-tostringtag": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-symbol": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/is-symbol/-/is-symbol-1.0.4.tgz",
+ "integrity": "sha512-C/CPBqKWnvdcxqIARxyOh4v1UUEOCHpgDa0WYgpKDFMszcrPcffg5uhwSgPCLD2WWxmq6isisz87tzT01tuGhg==",
+ "dependencies": {
+ "has-symbols": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-unc-path": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz",
+ "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==",
+ "dev": true,
+ "dependencies": {
+ "unc-path-regex": "^0.1.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-utf8": {
+ "version": "0.2.1",
+ "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz",
+ "integrity": "sha512-rMYPYvCzsXywIsldgLaSoPlw5PfoB/ssr7hY4pLfcodrA5M/eArza1a9VmTiNIBNMjOGr1Ow9mTyU2o69U6U9Q==",
+ "dev": true
+ },
+ "node_modules/is-valid-glob": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz",
+ "integrity": "sha512-AhiROmoEFDSsjx8hW+5sGwgKVIORcXnrlAx/R0ZSeaPw70Vw0CqkGBBhHGL58Uox2eXnU1AnvXJl1XlyedO5bA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/is-weakmap": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/is-weakmap/-/is-weakmap-2.0.2.tgz",
+ "integrity": "sha512-K5pXYOm9wqY1RgjpL3YTkF39tni1XajUIkawTLUo9EZEVUFga5gSQJF8nNS7ZwJQ02y+1YCNYcMh+HIf1ZqE+w==",
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-weakset": {
+ "version": "2.0.3",
+ "resolved": "https://registry.npmjs.org/is-weakset/-/is-weakset-2.0.3.tgz",
+ "integrity": "sha512-LvIm3/KWzS9oRFHugab7d+M/GcBXuXX5xZkzPmN+NxihdQlZUQ4dWuSV1xR/sq6upL1TJEDrfBgRepHFdBtSNQ==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "get-intrinsic": "^1.2.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/is-windows": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz",
+ "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/isarray": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz",
+ "integrity": "sha512-VLghIWNM6ELQzo7zwmcg0NmTVyWKYjvIeM83yjp0wRDTmUnrM678fQbcKBo6n2CJEF0szoG//ytg+TKla89ALQ==",
+ "dev": true
+ },
+ "node_modules/isexe": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz",
+ "integrity": "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw==",
+ "dev": true
+ },
+ "node_modules/isobject": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz",
+ "integrity": "sha512-WhB9zCku7EGTj/HQQRz5aUQEUeoQZH2bWcltRErOpymJ4boYE6wL9Tbr23krRPSZ+C5zqNSrSw+Cc7sZZ4b7vg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/jasny-bootstrap": {
+ "version": "3.1.3",
+ "resolved": "https://registry.npmjs.org/jasny-bootstrap/-/jasny-bootstrap-3.1.3.tgz",
+ "integrity": "sha512-i2O5dUFuYV56Pyl6aZ5hWmsttTySXRBp+4X4kFlKYHLsJeaeiT3IkpbCPMdrDa1zQbm856cuLoxMEh+3fSOVaQ=="
+ },
+ "node_modules/jquery": {
+ "version": "3.7.1",
+ "resolved": "https://registry.npmjs.org/jquery/-/jquery-3.7.1.tgz",
+ "integrity": "sha512-m4avr8yL8kmFN8psrbFFFmB/If14iN5o9nw/NgnnM+kybDJpRsAynV2BsfpTYrTRysYUdADVD7CkUUizgkpLfg=="
+ },
+ "node_modules/jquery-form": {
+ "version": "4.3.0",
+ "resolved": "https://registry.npmjs.org/jquery-form/-/jquery-form-4.3.0.tgz",
+ "integrity": "sha512-q3uaVCEWdLOYUCI6dpNdwf/7cJFOsUgdpq6r0taxtGQ5NJSkOzofyWm4jpOuJ5YxdmL1FI5QR+q+HB63HHLGnQ==",
+ "dependencies": {
+ "jquery": ">=1.7.2"
+ }
+ },
+ "node_modules/jquery-ui-dist": {
+ "version": "1.13.2",
+ "resolved": "https://registry.npmjs.org/jquery-ui-dist/-/jquery-ui-dist-1.13.2.tgz",
+ "integrity": "sha512-oVDRd1NLtTbBwpRKAYdIRgpWVDzeBhfy7Gu0RmY6JEaZtmBq6kDn1pm5SgDiAotrnDS+RoTRXO6xvcNTxA9tOA==",
+ "dependencies": {
+ "jquery": ">=1.8.0 <4.0.0"
+ }
+ },
+ "node_modules/jquery-validation": {
+ "version": "1.20.0",
+ "resolved": "https://registry.npmjs.org/jquery-validation/-/jquery-validation-1.20.0.tgz",
+ "integrity": "sha512-c8tg4ltIIP6L7l0bZ79sRzOJYquyjS48kQZ6iv8MJ2r0OYztxtkWYKTReZyU2/zVFYiINB29i0Z/IRNNuJQN1g==",
+ "peerDependencies": {
+ "jquery": "^1.7 || ^2.0 || ^3.1"
+ }
+ },
+ "node_modules/js-cookie": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/js-cookie/-/js-cookie-2.2.1.tgz",
+ "integrity": "sha512-HvdH2LzI/EAZcUwA8+0nKNtWHqS+ZmijLA30RwZA0bo7ToCckjK5MkGhjED9KoRcXO6BaGI3I9UIzSA1FKFPOQ=="
+ },
+ "node_modules/jspdf": {
+ "version": "2.5.1",
+ "resolved": "https://registry.npmjs.org/jspdf/-/jspdf-2.5.1.tgz",
+ "integrity": "sha512-hXObxz7ZqoyhxET78+XR34Xu2qFGrJJ2I2bE5w4SM8eFaFEkW2xcGRVUss360fYelwRSid/jT078kbNvmoW0QA==",
+ "dependencies": {
+ "@babel/runtime": "^7.14.0",
+ "atob": "^2.1.2",
+ "btoa": "^1.2.1",
+ "fflate": "^0.4.8"
+ },
+ "optionalDependencies": {
+ "canvg": "^3.0.6",
+ "core-js": "^3.6.0",
+ "dompurify": "^2.2.0",
+ "html2canvas": "^1.0.0-rc.5"
+ }
+ },
+ "node_modules/jspdf-autotable": {
+ "version": "3.8.2",
+ "resolved": "https://registry.npmjs.org/jspdf-autotable/-/jspdf-autotable-3.8.2.tgz",
+ "integrity": "sha512-zW1ix99/mtR4MbIni7IqvrpfHmuTaICl6iv6wqjRN86Nxtwaw/QtOeDbpXqYSzHIJK9JvgtLM283sc5x+ipkJg==",
+ "peerDependencies": {
+ "jspdf": "^2.5.1"
+ }
+ },
+ "node_modules/last-run": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/last-run/-/last-run-2.0.0.tgz",
+ "integrity": "sha512-j+y6WhTLN4Itnf9j5ZQos1BGPCS8DAwmgMroR3OzfxAsBxam0hMw7J8M3KqZl0pLQJ1jNnwIexg5DYpC/ctwEQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/lazystream": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.1.tgz",
+ "integrity": "sha512-b94GiNHQNy6JNTrt5w6zNyffMrNkXZb3KTkCZJb2V1xaEGCk093vkZ2jk3tpaeP33/OiXC+WvK9AxUebnf5nbw==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "^2.0.5"
+ },
+ "engines": {
+ "node": ">= 0.6.3"
+ }
+ },
+ "node_modules/lazystream/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/lazystream/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/lazystream/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/lead": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/lead/-/lead-4.0.0.tgz",
+ "integrity": "sha512-DpMa59o5uGUWWjruMp71e6knmwKU3jRBBn1kjuLWN9EeIOxNeSAwvHf03WIl8g/ZMR2oSQC9ej3yeLBwdDc/pg==",
+ "dev": true,
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/liftoff": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-5.0.0.tgz",
+ "integrity": "sha512-a5BQjbCHnB+cy+gsro8lXJ4kZluzOijzJ1UVVfyJYZC+IP2pLv1h4+aysQeKuTmyO8NAqfyQAk4HWaP/HjcKTg==",
+ "dev": true,
+ "dependencies": {
+ "extend": "^3.0.2",
+ "findup-sync": "^5.0.0",
+ "fined": "^2.0.0",
+ "flagged-respawn": "^2.0.0",
+ "is-plain-object": "^5.0.0",
+ "rechoir": "^0.8.0",
+ "resolve": "^1.20.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/linebreak": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/linebreak/-/linebreak-1.1.0.tgz",
+ "integrity": "sha512-MHp03UImeVhB7XZtjd0E4n6+3xr5Dq/9xI/5FptGk5FrbDR3zagPa2DS6U8ks/3HjbKWG9Q1M2ufOzxV2qLYSQ==",
+ "dependencies": {
+ "base64-js": "0.0.8",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/linebreak/node_modules/base64-js": {
+ "version": "0.0.8",
+ "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-0.0.8.tgz",
+ "integrity": "sha512-3XSA2cR/h/73EzlXXdU6YNycmYI7+kicTxks4eJg2g39biHR84slg2+des+p7iHYhbRg/udIS4TD53WabcOUkw==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/lodash": {
+ "version": "4.17.21",
+ "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.21.tgz",
+ "integrity": "sha512-v2kDEe57lecTulaDIuNTPy3Ry4gLGJ6Z1O3vE1krgXZNrsQ+LFTGHVxVjcXPs17LhbZVGedAJv8XZ1tvj5FvSg==",
+ "dev": true
+ },
+ "node_modules/lodash._basecopy": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basecopy/-/lodash._basecopy-3.0.1.tgz",
+ "integrity": "sha512-rFR6Vpm4HeCK1WPGvjZSJ+7yik8d8PVUdCJx5rT2pogG4Ve/2ZS7kfmO5l5T2o5V2mqlNIfSF5MZlr1+xOoYQQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._basetostring": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._basetostring/-/lodash._basetostring-3.0.1.tgz",
+ "integrity": "sha512-mTzAr1aNAv/i7W43vOR/uD/aJ4ngbtsRaCubp2BfZhlGU/eORUjg/7F6X0orNMdv33JOrdgGybtvMN/po3EWrA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._basevalues": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._basevalues/-/lodash._basevalues-3.0.0.tgz",
+ "integrity": "sha512-H94wl5P13uEqlCg7OcNNhMQ8KvWSIyqXzOPusRgHC9DK3o54P6P3xtbXlVbRABG4q5gSmp7EDdJ0MSuW9HX6Mg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._getnative": {
+ "version": "3.9.1",
+ "resolved": "https://registry.npmjs.org/lodash._getnative/-/lodash._getnative-3.9.1.tgz",
+ "integrity": "sha512-RrL9VxMEPyDMHOd9uFbvMe8X55X16/cGM5IgOKgRElQZutpX89iS6vwl64duTV1/16w5JY7tuFNXqoekmh1EmA==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._isiterateecall": {
+ "version": "3.0.9",
+ "resolved": "https://registry.npmjs.org/lodash._isiterateecall/-/lodash._isiterateecall-3.0.9.tgz",
+ "integrity": "sha512-De+ZbrMu6eThFti/CSzhRvTKMgQToLxbij58LMfM8JnYDNSOjkjTCIaa8ixglOeGh2nyPlakbt5bJWJ7gvpYlQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._reescape": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reescape/-/lodash._reescape-3.0.0.tgz",
+ "integrity": "sha512-Sjlavm5y+FUVIF3vF3B75GyXrzsfYV8Dlv3L4mEpuB9leg8N6yf/7rU06iLPx9fY0Mv3khVp9p7Dx0mGV6V5OQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._reevaluate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reevaluate/-/lodash._reevaluate-3.0.0.tgz",
+ "integrity": "sha512-OrPwdDc65iJiBeUe5n/LIjd7Viy99bKwDdk7Z5ljfZg0uFRFlfQaCy9tZ4YMAag9WAZmlVpe1iZrkIMMSMHD3w==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash._reinterpolate": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/lodash._reinterpolate/-/lodash._reinterpolate-3.0.0.tgz",
+ "integrity": "sha512-xYHt68QRoYGjeeM/XOE1uJtvXQAgvszfBhjV4yvsQH0u2i9I6cI6c6/eG4Hh3UAOVn0y/xAXwmTzEay49Q//HA==",
+ "dev": true
+ },
+ "node_modules/lodash._root": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/lodash._root/-/lodash._root-3.0.1.tgz",
+ "integrity": "sha512-O0pWuFSK6x4EXhM1dhZ8gchNtG7JMqBtrHdoUFUWXD7dJnNSUze1GuyQr5sOs0aCvgGeI3o/OJW8f4ca7FDxmQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.defaults": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.defaults/-/lodash.defaults-4.2.0.tgz",
+ "integrity": "sha512-qjxPLHd3r5DnsdGacqOMU6pb/avJzdh9tFX2ymgoZE27BmjXrNy/y4LoaiTeAb+O3gL8AfpJGtqfX/ae2leYYQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.escape": {
+ "version": "3.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.escape/-/lodash.escape-3.2.0.tgz",
+ "integrity": "sha512-n1PZMXgaaDWZDSvuNZ/8XOcYO2hOKDqZel5adtR30VKQAtoWs/5AOeFA0vPV8moiPzlqe7F4cP2tzpFewQyelQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash._root": "^3.0.0"
+ }
+ },
+ "node_modules/lodash.isarguments": {
+ "version": "3.1.0",
+ "resolved": "https://registry.npmjs.org/lodash.isarguments/-/lodash.isarguments-3.1.0.tgz",
+ "integrity": "sha512-chi4NHZlZqZD18a0imDHnZPrDeBbTtVN7GXMwuGdRH9qotxAjYs3aVLKc7zNOG9eddR5Ksd8rvFEBc9SsggPpg==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.isarray": {
+ "version": "3.0.4",
+ "resolved": "https://registry.npmjs.org/lodash.isarray/-/lodash.isarray-3.0.4.tgz",
+ "integrity": "sha512-JwObCrNJuT0Nnbuecmqr5DgtuBppuCvGD9lxjFpAzwnVtdGoDQ1zig+5W8k5/6Gcn0gZ3936HDAlGd28i7sOGQ==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.keys": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/lodash.keys/-/lodash.keys-3.1.2.tgz",
+ "integrity": "sha512-CuBsapFjcubOGMn3VD+24HOAPxM79tH+V6ivJL3CHYjtrawauDJHUk//Yew9Hvc6e9rbCrURGk8z6PC+8WJBfQ==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "lodash._getnative": "^3.0.0",
+ "lodash.isarguments": "^3.0.0",
+ "lodash.isarray": "^3.0.0"
+ }
+ },
+ "node_modules/lodash.restparam": {
+ "version": "3.6.1",
+ "resolved": "https://registry.npmjs.org/lodash.restparam/-/lodash.restparam-3.6.1.tgz",
+ "integrity": "sha512-L4/arjjuq4noiUJpt3yS6KIKDtJwNe2fIYgMqyYYKoeIfV1iEqvPwhCx23o+R9dzouGihDAPN1dTIRWa7zk8tw==",
+ "dev": true,
+ "license": "MIT"
+ },
+ "node_modules/lodash.template": {
+ "version": "4.5.0",
+ "resolved": "https://registry.npmjs.org/lodash.template/-/lodash.template-4.5.0.tgz",
+ "integrity": "sha512-84vYFxIkmidUiFxidA/KjjH9pAycqW+h980j7Fuz5qxRtO9pgB7MDFTdys1N7A5mcucRiDyEq4fusljItR1T/A==",
+ "dev": true,
+ "dependencies": {
+ "lodash._reinterpolate": "^3.0.0",
+ "lodash.templatesettings": "^4.0.0"
+ }
+ },
+ "node_modules/lodash.templatesettings": {
+ "version": "4.2.0",
+ "resolved": "https://registry.npmjs.org/lodash.templatesettings/-/lodash.templatesettings-4.2.0.tgz",
+ "integrity": "sha512-stgLz+i3Aa9mZgnjr/O+v9ruKZsPsndy7qPZOchbqk2cnTU1ZaldKK+v7m54WoKIyxiuMZTKT2H81F8BeAc3ZQ==",
+ "dev": true,
+ "dependencies": {
+ "lodash._reinterpolate": "^3.0.0"
+ }
+ },
+ "node_modules/make-error": {
+ "version": "1.3.6",
+ "resolved": "https://registry.npmjs.org/make-error/-/make-error-1.3.6.tgz",
+ "integrity": "sha512-s8UhlNe7vPKomQhC1qFelMokr/Sc3AgNbso3n74mVPA5LTZwkB9NlXf4XPamLxJE8h0gh73rM94xvwRT2CVInw==",
+ "dev": true
+ },
+ "node_modules/make-error-cause": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/make-error-cause/-/make-error-cause-1.2.2.tgz",
+ "integrity": "sha512-4TO2Y3HkBnis4c0dxhAgD/jprySYLACf7nwN6V0HAHDx59g12WlRpUmFy1bRHamjGUEEBrEvCq6SUpsEE2lhUg==",
+ "dev": true,
+ "dependencies": {
+ "make-error": "^1.2.0"
+ }
+ },
+ "node_modules/map-cache": {
+ "version": "0.2.2",
+ "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz",
+ "integrity": "sha512-8y/eV9QQZCiyn1SprXSrCmqJN0yNRATe+PO8ztwqrvrbdRLA3eYJF0yaR0YayLWkMbsQSKWS9N2gPcGEc4UsZg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/map-stream": {
+ "version": "0.0.7",
+ "resolved": "https://registry.npmjs.org/map-stream/-/map-stream-0.0.7.tgz",
+ "integrity": "sha512-C0X0KQmGm3N2ftbTGBhSyuydQ+vV1LC3f3zPvT3RXHXNZrvfPZcoXp/N5DOa8vedX/rTMm2CjTtivFg2STJMRQ==",
+ "dev": true
+ },
+ "node_modules/micromatch": {
+ "version": "4.0.8",
+ "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-4.0.8.tgz",
+ "integrity": "sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA==",
+ "dev": true,
+ "dependencies": {
+ "braces": "^3.0.3",
+ "picomatch": "^2.3.1"
+ },
+ "engines": {
+ "node": ">=8.6"
+ }
+ },
+ "node_modules/minimist": {
+ "version": "1.2.8",
+ "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.8.tgz",
+ "integrity": "sha512-2yyAR8qBkN3YuheJanUpWC5U3bb5osDywNB8RzDVlDwDHbocAJveqqj1u8+SVD7jkWT4yvsHCpWqqWqAxb0zCA==",
+ "dev": true,
+ "license": "MIT",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/modify-filename": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/modify-filename/-/modify-filename-2.0.0.tgz",
+ "integrity": "sha512-VX9/MdgUN9StpSLImJ0+AyV2dxJJtyojIwRHF/Ja942tW7FTzxXI186jDSTk4k5wj2+59a4bRzFnJUgMSi+ygg==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/moment": {
+ "version": "2.30.1",
+ "resolved": "https://registry.npmjs.org/moment/-/moment-2.30.1.tgz",
+ "integrity": "sha512-uEmtNhbDOrWPFS+hdjFCBfy9f2YoyzRpwcl+DqpC6taX21FzsTLQVbMV/W7PzNSX6x/bhC1zA3c2UQ5NzH6how==",
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/multipipe": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/multipipe/-/multipipe-0.1.2.tgz",
+ "integrity": "sha512-7ZxrUybYv9NonoXgwoOqtStIu18D1c3eFZj27hqgf5kBrBF8Q+tE8V0MW8dKM5QLkQPh1JhhbKgHLY9kifov4Q==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "duplexer2": "0.0.2"
+ }
+ },
+ "node_modules/mute-stdout": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-2.0.0.tgz",
+ "integrity": "sha512-32GSKM3Wyc8dg/p39lWPKYu8zci9mJFzV1Np9Of0ZEpe6Fhssn/FbI7ywAMd40uX+p3ZKh3T5EeCFv81qS3HmQ==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/normalize-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-3.0.0.tgz",
+ "integrity": "sha512-6eZs5Ls3WtCisHWp9S2GUy8dqkpGi4BVSz3GaqiE6ezub0512ESztXUwUB6C6IKbQkY2Pnb/mD4WYojCRwcwLA==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/now-and-later": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-3.0.0.tgz",
+ "integrity": "sha512-pGO4pzSdaxhWTGkfSfHx3hVzJVslFPwBp2Myq9MYN/ChfJZF87ochMAXnvz6/58RJSf5ik2q9tXprBBrk2cpcg==",
+ "dev": true,
+ "dependencies": {
+ "once": "^1.4.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/npm-check-updates": {
+ "version": "17.1.14",
+ "resolved": "https://registry.npmjs.org/npm-check-updates/-/npm-check-updates-17.1.14.tgz",
+ "integrity": "sha512-dr4bXIxETubLI1tFGeock5hN8yVjahvaVpx+lPO4/O2md3zJuxB7FgH3MIoTvQSCgsgkIRpe0skti01IEAA5tA==",
+ "license": "Apache-2.0",
+ "bin": {
+ "ncu": "build/cli.js",
+ "npm-check-updates": "build/cli.js"
+ },
+ "engines": {
+ "node": "^18.18.0 || >=20.0.0",
+ "npm": ">=8.12.1"
+ }
+ },
+ "node_modules/object-assign": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-3.0.0.tgz",
+ "integrity": "sha512-jHP15vXVGeVh1HuaA2wY6lxk+whK/x4KBG88VXeRma7CCun7iGD5qPc4eYykQ9sdQvg8jkwFKsSxHln2ybW3xQ==",
+ "dev": true,
+ "license": "MIT",
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object-inspect": {
+ "version": "1.13.1",
+ "resolved": "https://registry.npmjs.org/object-inspect/-/object-inspect-1.13.1.tgz",
+ "integrity": "sha512-5qoj1RUiKOMsCCNLV1CBiPYE10sziTsnmNxkAI/rZhiD63CF7IqdFGC/XzjWjpSgLf0LxXX3bDFIh0E18f6UhQ==",
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-is": {
+ "version": "1.1.6",
+ "resolved": "https://registry.npmjs.org/object-is/-/object-is-1.1.6.tgz",
+ "integrity": "sha512-F8cZ+KfGlSGi09lJT7/Nd6KJZ9ygtvYC0/UYYLI9nmQKLMnydpB9yvbv9K1uSkEu7FU9vYPmVwLg328tX+ot3Q==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "define-properties": "^1.2.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object-keys": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz",
+ "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/object.assign": {
+ "version": "4.1.5",
+ "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.5.tgz",
+ "integrity": "sha512-byy+U7gp+FVwmyzKPYhW2h5l3crpmGsxl7X2s8y43IgxvG4g3QZ6CffDtsNQy1WsmZpQbO+ybo0AlW7TY6DcBQ==",
+ "dependencies": {
+ "call-bind": "^1.0.5",
+ "define-properties": "^1.2.1",
+ "has-symbols": "^1.0.3",
+ "object-keys": "^1.1.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/object.defaults": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz",
+ "integrity": "sha512-c/K0mw/F11k4dEUBMW8naXUuBuhxRCfG7W+yFy8EcijU/rSmazOUd1XAEEe6bC0OuXY4HUKjTJv7xbxIMqdxrA==",
+ "dev": true,
+ "dependencies": {
+ "array-each": "^1.0.1",
+ "array-slice": "^1.0.0",
+ "for-own": "^1.0.0",
+ "isobject": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/object.pick": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz",
+ "integrity": "sha512-tqa/UMy/CCoYmj+H5qc07qvSL9dqcs/WZENZ1JbtWBlATP+iVOe778gE6MSijnyCnORzDuX6hU+LA4SZ09YjFQ==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/once": {
+ "version": "1.4.0",
+ "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz",
+ "integrity": "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w==",
+ "dev": true,
+ "dependencies": {
+ "wrappy": "1"
+ }
+ },
+ "node_modules/pako": {
+ "version": "0.2.9",
+ "resolved": "https://registry.npmjs.org/pako/-/pako-0.2.9.tgz",
+ "integrity": "sha512-NUcwaKxUxWrZLpDG+z/xZaCgQITkA/Dv4V/T6bw7VON6l1Xz/VnrBqrYjZQ12TamKHzITTfOEIYUj48y2KXImA=="
+ },
+ "node_modules/parse-filepath": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz",
+ "integrity": "sha512-FwdRXKCohSVeXqwtYonZTXtbGJKrn+HNyWDYVcp5yuJlesTwNH4rsmRZ+GrKAPJ5bLpRxESMeS+Rl0VCHRvB2Q==",
+ "dev": true,
+ "dependencies": {
+ "is-absolute": "^1.0.0",
+ "map-cache": "^0.2.0",
+ "path-root": "^0.1.1"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/parse-node-version": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz",
+ "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/parse-passwd": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz",
+ "integrity": "sha512-1Y1A//QUXEZK7YKz+rD9WydcE1+EuPr6ZBgKecAB8tmoW6UFv0NREVJe1p+jRxtThkcbbKkfwIbWJe/IeE6m2Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-is-absolute": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz",
+ "integrity": "sha512-AVbw3UJ2e9bq64vSaS9Am0fje1Pa8pbGqTTsmXfaIiMpnr5DlDhfJOuLj9Sf95ZPVDAUerDfEk88MPmPe7UCQg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-parse": {
+ "version": "1.0.7",
+ "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.7.tgz",
+ "integrity": "sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw==",
+ "dev": true
+ },
+ "node_modules/path-root": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz",
+ "integrity": "sha512-QLcPegTHF11axjfojBIoDygmS2E3Lf+8+jI6wOVmNVenrKSo3mFdSGiIgdSHenczw3wPtlVMQaFVwGmM7BJdtg==",
+ "dev": true,
+ "dependencies": {
+ "path-root-regex": "^0.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/path-root-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz",
+ "integrity": "sha512-4GlJ6rZDhQZFE0DPVKh0e9jmZ5egZfxTkp7bcRDuPlJXbAwhxcl2dINPUAsjLdejqaLsCeg8axcLjIbvBjN4pQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/pause-stream": {
+ "version": "0.0.11",
+ "resolved": "https://registry.npmjs.org/pause-stream/-/pause-stream-0.0.11.tgz",
+ "integrity": "sha512-e3FBlXLmN/D1S+zHzanP4E/4Z60oFAa3O051qt1pxa7DEJWKAyil6upYVXCWadEnuoqa4Pkc9oUx9zsxYeRv8A==",
+ "dev": true,
+ "dependencies": {
+ "through": "~2.3"
+ }
+ },
+ "node_modules/pdfkit": {
+ "version": "0.12.3",
+ "resolved": "https://registry.npmjs.org/pdfkit/-/pdfkit-0.12.3.tgz",
+ "integrity": "sha512-+qDLgm2yq6WOKcxTb43lDeo3EtMIDQs0CK1RNqhHC9iT6u0KOmgwAClkYh9xFw2ATbmUZzt4f7KMwDCOfPDluA==",
+ "dependencies": {
+ "crypto-js": "^4.0.0",
+ "fontkit": "^1.8.1",
+ "linebreak": "^1.0.2",
+ "png-js": "^1.0.0"
+ }
+ },
+ "node_modules/pdfmake": {
+ "version": "0.1.72",
+ "resolved": "https://registry.npmjs.org/pdfmake/-/pdfmake-0.1.72.tgz",
+ "integrity": "sha512-xZrPS+Safjf1I8ZYtMoXX83E6C6Pd1zFwa168yNTeeJWHclqf1z9DoYajjlY2uviN7gGyxwVZeou39uSk1oh1g==",
+ "dependencies": {
+ "iconv-lite": "^0.6.2",
+ "linebreak": "^1.0.2",
+ "pdfkit": "^0.12.0",
+ "svg-to-pdfkit": "^0.1.8",
+ "xmldoc": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/performance-now": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz",
+ "integrity": "sha512-7EAHlyLHI56VEIdK57uwHdHKIaAGbnXPiw0yWbarQZOKaKpvUIgW0jWRVLiatnM+XXlSwsanIBH/hzGMJulMow==",
+ "optional": true
+ },
+ "node_modules/picomatch": {
+ "version": "2.3.1",
+ "resolved": "https://registry.npmjs.org/picomatch/-/picomatch-2.3.1.tgz",
+ "integrity": "sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA==",
+ "dev": true,
+ "engines": {
+ "node": ">=8.6"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/jonschlinkert"
+ }
+ },
+ "node_modules/plugin-error": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-0.1.2.tgz",
+ "integrity": "sha512-WzZHcm4+GO34sjFMxQMqZbsz3xiNEgonCskQ9v+IroMmYgk/tas8dG+Hr2D6IbRPybZ12oWpzE/w3cGJ6FJzOw==",
+ "dev": true,
+ "dependencies": {
+ "ansi-cyan": "^0.1.1",
+ "ansi-red": "^0.1.1",
+ "arr-diff": "^1.0.1",
+ "arr-union": "^2.0.1",
+ "extend-shallow": "^1.1.2"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/plugin-error/node_modules/arr-diff": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-1.1.0.tgz",
+ "integrity": "sha512-OQwDZUqYaQwyyhDJHThmzId8daf4/RFNLaeh3AevmSeZ5Y7ug4Ga/yKc6l6kTZOBW781rCj103ZuTh8GAsB3+Q==",
+ "dev": true,
+ "dependencies": {
+ "arr-flatten": "^1.0.1",
+ "array-slice": "^0.2.3"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/plugin-error/node_modules/array-slice": {
+ "version": "0.2.3",
+ "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-0.2.3.tgz",
+ "integrity": "sha512-rlVfZW/1Ph2SNySXwR9QYkChp8EkOEiTMO5Vwx60usw04i4nWemkm9RXmQqgkQFaLHsqLuADvjp6IfgL9l2M8Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/plugin-error/node_modules/extend-shallow": {
+ "version": "1.1.4",
+ "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-1.1.4.tgz",
+ "integrity": "sha512-L7AGmkO6jhDkEBBGWlLtftA80Xq8DipnrRPr0pyi7GQLXkaq9JYA4xF4z6qnadIC6euiTDKco0cGSU9muw+WTw==",
+ "dev": true,
+ "dependencies": {
+ "kind-of": "^1.1.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/plugin-error/node_modules/kind-of": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-1.1.0.tgz",
+ "integrity": "sha512-aUH6ElPnMGon2/YkxRIigV32MOpTVcoXQ1Oo8aYn40s+sJ3j+0gFZsT8HKDcxNy7Fi9zuquWtGaGAahOdv5p/g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/plur": {
+ "version": "5.1.0",
+ "resolved": "https://registry.npmjs.org/plur/-/plur-5.1.0.tgz",
+ "integrity": "sha512-VP/72JeXqak2KiOzjgKtQen5y3IZHn+9GOuLDafPv0eXa47xq0At93XahYBs26MsifCQ4enGKwbjBTKgb9QJXg==",
+ "dev": true,
+ "dependencies": {
+ "irregular-plurals": "^3.3.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/png-js": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/png-js/-/png-js-1.0.0.tgz",
+ "integrity": "sha512-k+YsbhpA9e+EFfKjTCH3VW6aoKlyNYI6NYdTfDL4CIvFnvsuO84ttonmZE7rc+v23SLTH8XX+5w/Ak9v0xGY4g=="
+ },
+ "node_modules/possible-typed-array-names": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/possible-typed-array-names/-/possible-typed-array-names-1.0.0.tgz",
+ "integrity": "sha512-d7Uw+eZoloe0EHDIYoe+bQ5WXnGMOpmiZFTuMWCwpjzzkL2nTjcKiAk4hh8TjnGye2TwWOk3UXucZ+3rbmBa8Q==",
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/process": {
+ "version": "0.11.10",
+ "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz",
+ "integrity": "sha512-cdGef/drWFoydD1JsMzuFf8100nZl+GT+yacc2bEced5f9Rjk4z+WtFUTBu9PhOi9j/jfmBPu0mMEY4wIdAF8A==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.6.0"
+ }
+ },
+ "node_modules/process-nextick-args": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.1.tgz",
+ "integrity": "sha512-3ouUOpQhtgrbOa17J7+uxOTpITYWaGP7/AhoR3+A+/1e9skrzelGi/dXzEYyvbxubEF6Wn2ypscTKiKJFFn1ag==",
+ "dev": true
+ },
+ "node_modules/queue-tick": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/queue-tick/-/queue-tick-1.0.1.tgz",
+ "integrity": "sha512-kJt5qhMxoszgU/62PLP1CJytzd2NKetjSRnyuj31fDd3Rlcz3fzlFdFLD1SItunPwyqEOkca6GbV612BWfaBag==",
+ "dev": true
+ },
+ "node_modules/raf": {
+ "version": "3.4.1",
+ "resolved": "https://registry.npmjs.org/raf/-/raf-3.4.1.tgz",
+ "integrity": "sha512-Sq4CW4QhwOHE8ucn6J34MqtZCeWFP2aQSmrlroYgqAV1PjStIhJXxYuTgUIfkEk7zTLjmIjLmU5q+fbD1NnOJA==",
+ "optional": true,
+ "dependencies": {
+ "performance-now": "^2.1.0"
+ }
+ },
+ "node_modules/readable-stream": {
+ "version": "4.5.2",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-4.5.2.tgz",
+ "integrity": "sha512-yjavECdqeZ3GLXNgRXgeQEdz9fvDDkNKyHnbHRFtOr7/LcfgBcmct7t/ET+HaCTqfh06OzoAxrkN/IfjJBVe+g==",
+ "dev": true,
+ "dependencies": {
+ "abort-controller": "^3.0.0",
+ "buffer": "^6.0.3",
+ "events": "^3.3.0",
+ "process": "^0.11.10",
+ "string_decoder": "^1.3.0"
+ },
+ "engines": {
+ "node": "^12.22.0 || ^14.17.0 || >=16.0.0"
+ }
+ },
+ "node_modules/readdir-glob": {
+ "version": "1.1.3",
+ "resolved": "https://registry.npmjs.org/readdir-glob/-/readdir-glob-1.1.3.tgz",
+ "integrity": "sha512-v05I2k7xN8zXvPD9N+z/uhXPaj0sUFCe2rcWZIpBsqxfP7xXFQ0tipAd/wjj1YxWyWtUS5IDJpOG82JKt2EAVA==",
+ "dev": true,
+ "dependencies": {
+ "minimatch": "^5.1.0"
+ }
+ },
+ "node_modules/readdir-glob/node_modules/minimatch": {
+ "version": "5.1.6",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-5.1.6.tgz",
+ "integrity": "sha512-lKwV/1brpG6mBUFHtb7NUmtABCb2WZZmm2wNiOA5hAb8VdCS4B3dtMWyvcoViccwAW/COERjXLt0zP1zXUN26g==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^2.0.1"
+ },
+ "engines": {
+ "node": ">=10"
+ }
+ },
+ "node_modules/readdirp": {
+ "version": "3.6.0",
+ "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-3.6.0.tgz",
+ "integrity": "sha512-hOS089on8RduqdbhvQ5Z37A0ESjsqz6qnRcffsMU3495FuTdqSm+7bhJ29JvIOsBDEEnan5DPu9t3To9VRlMzA==",
+ "dev": true,
+ "dependencies": {
+ "picomatch": "^2.2.1"
+ },
+ "engines": {
+ "node": ">=8.10.0"
+ }
+ },
+ "node_modules/rechoir": {
+ "version": "0.8.0",
+ "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.8.0.tgz",
+ "integrity": "sha512-/vxpCXddiX8NGfGO/mTafwjq4aFa/71pvamip0++IQk3zG8cbCj0fifNPrjjF1XMXUne91jL9OoxmdykoEtifQ==",
+ "dev": true,
+ "dependencies": {
+ "resolve": "^1.20.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/regenerator-runtime": {
+ "version": "0.14.1",
+ "resolved": "https://registry.npmjs.org/regenerator-runtime/-/regenerator-runtime-0.14.1.tgz",
+ "integrity": "sha512-dYnhHh0nJoMfnkZs6GmmhFknAGRrLznOu5nc9ML+EJxGvrx6H7teuevqVqCuPcPK//3eDrrjQhehXVx9cnkGdw=="
+ },
+ "node_modules/regexp.prototype.flags": {
+ "version": "1.5.2",
+ "resolved": "https://registry.npmjs.org/regexp.prototype.flags/-/regexp.prototype.flags-1.5.2.tgz",
+ "integrity": "sha512-NcDiDkTLuPR+++OCKB0nWafEmhg/Da8aUPLPMQbK+bxKKCm1/S5he+AqYa4PlMCVBalb4/yxIRub6qkEx5yJbw==",
+ "dependencies": {
+ "call-bind": "^1.0.6",
+ "define-properties": "^1.2.1",
+ "es-errors": "^1.3.0",
+ "set-function-name": "^2.0.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/remove-trailing-separator": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz",
+ "integrity": "sha512-/hS+Y0u3aOfIETiaiirUFwDBDzmXPvO+jAfKTitUngIPzdKc6Z0LoFjM/CK5PL4C+eKwHohlHAb6H0VFfmmUsw==",
+ "dev": true
+ },
+ "node_modules/replace-ext": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.1.tgz",
+ "integrity": "sha512-yD5BHCe7quCgBph4rMQ+0KkIRKwWCrHDOX1p1Gp6HwjPM5kVoCdKGNhN7ydqqsX6lJEnQDKZ/tFMiEdQ1dvPEw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/replace-homedir": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-2.0.0.tgz",
+ "integrity": "sha512-bgEuQQ/BHW0XkkJtawzrfzHFSN70f/3cNOiHa2QsYxqrjaC30X1k74FJ6xswVBP0sr0SpGIdVFuPwfrYziVeyw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/require-directory": {
+ "version": "2.1.1",
+ "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz",
+ "integrity": "sha512-fGxEI7+wsG9xrvdjsrlmL22OMTTiHRwAMroiEeMgq8gzoLC/PQr7RsRDSTLUg/bZAZtF+TVIkHc6/4RIKrui+Q==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve": {
+ "version": "1.22.8",
+ "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.22.8.tgz",
+ "integrity": "sha512-oKWePCxqpd6FlLvGV1VU0x7bkPmmCNolxzjMf4NczoDnQcIWrAF+cPtZn5i6n+RfD2d9i0tzpKnG6Yk168yIyw==",
+ "dev": true,
+ "dependencies": {
+ "is-core-module": "^2.13.0",
+ "path-parse": "^1.0.7",
+ "supports-preserve-symlinks-flag": "^1.0.0"
+ },
+ "bin": {
+ "resolve": "bin/resolve"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/resolve-dir": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz",
+ "integrity": "sha512-R7uiTjECzvOsWSfdM0QKFNBVFcK27aHOUwdvK53BcW8zqnGdYp0Fbj82cy54+2A4P2tFM22J5kRfe1R+lM/1yg==",
+ "dev": true,
+ "dependencies": {
+ "expand-tilde": "^2.0.0",
+ "global-modules": "^1.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/resolve-options": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-2.0.0.tgz",
+ "integrity": "sha512-/FopbmmFOQCfsCx77BRFdKOniglTiHumLgwvd6IDPihy1GKkadZbgQJBcTb2lMzSR1pndzd96b1nZrreZ7+9/A==",
+ "dev": true,
+ "dependencies": {
+ "value-or-function": "^4.0.0"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/restructure": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/restructure/-/restructure-2.0.1.tgz",
+ "integrity": "sha512-e0dOpjm5DseomnXx2M5lpdZ5zoHqF1+bqdMJUohoYVVQa7cBdnk7fdmeI6byNWP/kiME72EeTiSypTCVnpLiDg=="
+ },
+ "node_modules/reusify": {
+ "version": "1.0.4",
+ "resolved": "https://registry.npmjs.org/reusify/-/reusify-1.0.4.tgz",
+ "integrity": "sha512-U9nH88a3fc/ekCF1l0/UP1IosiuIjyTh7hBvXVMHYgVcfGvt897Xguj2UOLDeI5BG2m7/uwyaLVT6fbtCwTyzw==",
+ "dev": true,
+ "engines": {
+ "iojs": ">=1.0.0",
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/rev-hash": {
+ "version": "4.1.0",
+ "resolved": "https://registry.npmjs.org/rev-hash/-/rev-hash-4.1.0.tgz",
+ "integrity": "sha512-e0EGnaveLY2IYpYwHNdh43WZ2M84KgW3Z/T4F6+Z/BlZI/T1ZbxTWj36xgYgUPOieGXYo2q225jTeUXn+LWYjw==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rev-path": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/rev-path/-/rev-path-3.0.0.tgz",
+ "integrity": "sha512-2fUuv6IC7Z+Vj+DXEunJYJDZuwSsaJJHeLar3n2PGvHSH7j5+Xpd/Xh7PenekH4WQhxFuHtsGwd1dCh/HvT6Gw==",
+ "dev": true,
+ "dependencies": {
+ "modify-filename": "^2.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/rgbcolor": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/rgbcolor/-/rgbcolor-1.0.1.tgz",
+ "integrity": "sha512-9aZLIrhRaD97sgVhtJOW6ckOEh6/GnvQtdVNfdZ6s67+3/XwLS9lBcQYzEEhYVeUowN7pRzMLsyGhK2i/xvWbw==",
+ "optional": true,
+ "engines": {
+ "node": ">= 0.8.15"
+ }
+ },
+ "node_modules/rimraf": {
+ "version": "2.7.1",
+ "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.7.1.tgz",
+ "integrity": "sha512-uWjbaKIK3T1OSVptzX7Nl6PvQ3qAGtKEtVRjRuazjfL3Bx5eI409VZSqgND+4UNnmzLVdPj9FqFJNPqBZFve4w==",
+ "dev": true,
+ "dependencies": {
+ "glob": "^7.1.3"
+ },
+ "bin": {
+ "rimraf": "bin.js"
+ }
+ },
+ "node_modules/rimraf/node_modules/brace-expansion": {
+ "version": "1.1.11",
+ "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz",
+ "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==",
+ "dev": true,
+ "dependencies": {
+ "balanced-match": "^1.0.0",
+ "concat-map": "0.0.1"
+ }
+ },
+ "node_modules/rimraf/node_modules/glob": {
+ "version": "7.2.3",
+ "resolved": "https://registry.npmjs.org/glob/-/glob-7.2.3.tgz",
+ "integrity": "sha512-nFR0zLpU2YCaRxwoCJvL6UvCH2JFyFVIvwTLsIf21AuHlMskA1hhTdk+LlYJtOlYt9v6dvszD2BGRqBL+iQK9Q==",
+ "dev": true,
+ "dependencies": {
+ "fs.realpath": "^1.0.0",
+ "inflight": "^1.0.4",
+ "inherits": "2",
+ "minimatch": "^3.1.1",
+ "once": "^1.3.0",
+ "path-is-absolute": "^1.0.0"
+ },
+ "engines": {
+ "node": "*"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/isaacs"
+ }
+ },
+ "node_modules/rimraf/node_modules/minimatch": {
+ "version": "3.1.2",
+ "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.1.2.tgz",
+ "integrity": "sha512-J7p63hRiAjw1NDEww1W7i37+ByIrOWO5XQQAzZ3VOcL0PNybwpfmV/N05zFAzwQ9USyEcX6t3UO+K5aqBQOIHw==",
+ "dev": true,
+ "dependencies": {
+ "brace-expansion": "^1.1.7"
+ },
+ "engines": {
+ "node": "*"
+ }
+ },
+ "node_modules/safe-buffer": {
+ "version": "5.2.1",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.2.1.tgz",
+ "integrity": "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ==",
+ "dev": true,
+ "funding": [
+ {
+ "type": "github",
+ "url": "https://github.com/sponsors/feross"
+ },
+ {
+ "type": "patreon",
+ "url": "https://www.patreon.com/feross"
+ },
+ {
+ "type": "consulting",
+ "url": "https://feross.org/support"
+ }
+ ]
+ },
+ "node_modules/safer-buffer": {
+ "version": "2.1.2",
+ "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz",
+ "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="
+ },
+ "node_modules/sax": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/sax/-/sax-1.3.0.tgz",
+ "integrity": "sha512-0s+oAmw9zLl1V1cS9BtZN7JAd0cW5e0QH4W3LWEK6a4LaLEA2OTpGYWDY+6XasBLtz6wkm3u1xRw95mRuJ59WA=="
+ },
+ "node_modules/select": {
+ "version": "1.1.2",
+ "resolved": "https://registry.npmjs.org/select/-/select-1.1.2.tgz",
+ "integrity": "sha512-OwpTSOfy6xSs1+pwcNrv0RBMOzI39Lp3qQKUTPVVPRjCdNa5JH/oPRiqsesIskK8TVgmRiHwO4KXlV2Li9dANA=="
+ },
+ "node_modules/semver-greatest-satisfied-range": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-2.0.0.tgz",
+ "integrity": "sha512-lH3f6kMbwyANB7HuOWRMlLCa2itaCrZJ+SAqqkSZrZKO/cAsk2EOyaKHUtNkVLFyFW9pct22SFesFp3Z7zpA0g==",
+ "dev": true,
+ "dependencies": {
+ "sver": "^1.8.3"
+ },
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/set-function-length": {
+ "version": "1.2.2",
+ "resolved": "https://registry.npmjs.org/set-function-length/-/set-function-length-1.2.2.tgz",
+ "integrity": "sha512-pgRc4hJ4/sNjWCSS9AmnS40x3bNMDTknHgL5UaMBTMyJnU90EgWh1Rz+MC9eFu4BuN/UwZjKQuY/1v3rM7HMfg==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "function-bind": "^1.1.2",
+ "get-intrinsic": "^1.2.4",
+ "gopd": "^1.0.1",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/set-function-name": {
+ "version": "2.0.2",
+ "resolved": "https://registry.npmjs.org/set-function-name/-/set-function-name-2.0.2.tgz",
+ "integrity": "sha512-7PGFlmtwsEADb0WYyvCMa1t+yke6daIG4Wirafur5kcf+MhUnPms1UeR0CKQdTZD81yESwMHbtn+TR+dMviakQ==",
+ "dependencies": {
+ "define-data-property": "^1.1.4",
+ "es-errors": "^1.3.0",
+ "functions-have-names": "^1.2.3",
+ "has-property-descriptors": "^1.0.2"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/side-channel": {
+ "version": "1.0.6",
+ "resolved": "https://registry.npmjs.org/side-channel/-/side-channel-1.0.6.tgz",
+ "integrity": "sha512-fDW/EZ6Q9RiO8eFG8Hj+7u/oW+XrPTIChwCOM2+th2A6OblDtYYIpve9m+KvI9Z4C9qSEXlaGR6bTEYHReuglA==",
+ "dependencies": {
+ "call-bind": "^1.0.7",
+ "es-errors": "^1.3.0",
+ "get-intrinsic": "^1.2.4",
+ "object-inspect": "^1.13.1"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sort-keys": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/sort-keys/-/sort-keys-5.0.0.tgz",
+ "integrity": "sha512-Pdz01AvCAottHTPQGzndktFNdbRA75BgOfeT1hH+AMnJFv8lynkPi42rfeEhpx1saTEI3YNMWxfqu0sFD1G8pw==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-obj": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=12"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/source-map": {
+ "version": "0.6.1",
+ "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz",
+ "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/sparkles": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz",
+ "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/ssf": {
+ "version": "0.11.2",
+ "resolved": "https://registry.npmjs.org/ssf/-/ssf-0.11.2.tgz",
+ "integrity": "sha512-+idbmIXoYET47hH+d7dfm2epdOMUDjqcB4648sTZ+t2JwoyBFL/insLfB/racrDmsKB3diwsDA696pZMieAC5g==",
+ "dependencies": {
+ "frac": "~1.1.2"
+ },
+ "engines": {
+ "node": ">=0.8"
+ }
+ },
+ "node_modules/stackblur-canvas": {
+ "version": "2.7.0",
+ "resolved": "https://registry.npmjs.org/stackblur-canvas/-/stackblur-canvas-2.7.0.tgz",
+ "integrity": "sha512-yf7OENo23AGJhBriGx0QivY5JP6Y1HbrrDI6WLt6C5auYZXlQrheoY8hD4ibekFKz1HOfE48Ww8kMWMnJD/zcQ==",
+ "optional": true,
+ "engines": {
+ "node": ">=0.1.14"
+ }
+ },
+ "node_modules/stop-iteration-iterator": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/stop-iteration-iterator/-/stop-iteration-iterator-1.0.0.tgz",
+ "integrity": "sha512-iCGQj+0l0HOdZ2AEeBADlsRC+vsnDsZsbdSiH1yNSjcfKM7fdpCMfqAL/dwF5BLiw/XhRft/Wax6zQbhq2BcjQ==",
+ "dependencies": {
+ "internal-slot": "^1.0.4"
+ },
+ "engines": {
+ "node": ">= 0.4"
+ }
+ },
+ "node_modules/stream-composer": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/stream-composer/-/stream-composer-1.0.2.tgz",
+ "integrity": "sha512-bnBselmwfX5K10AH6L4c8+S5lgZMWI7ZYrz2rvYjCPB2DIMC4Ig8OpxGpNJSxRZ58oti7y1IcNvjBAz9vW5m4w==",
+ "dev": true,
+ "dependencies": {
+ "streamx": "^2.13.2"
+ }
+ },
+ "node_modules/stream-exhaust": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz",
+ "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==",
+ "dev": true
+ },
+ "node_modules/stream-series": {
+ "version": "0.1.1",
+ "resolved": "https://registry.npmjs.org/stream-series/-/stream-series-0.1.1.tgz",
+ "integrity": "sha512-OrmvvBgH+6PUeVp/hZGycQIrFegjTEbObxsQGXuPPjtFGIJL5E7JTmjHriUcdPOEiTlpc8wWatgnGCZHKVo7zg==",
+ "dev": true,
+ "dependencies": {
+ "pause-stream": "0.0.11"
+ }
+ },
+ "node_modules/stream-to-array": {
+ "version": "2.3.0",
+ "resolved": "https://registry.npmjs.org/stream-to-array/-/stream-to-array-2.3.0.tgz",
+ "integrity": "sha512-UsZtOYEn4tWU2RGLOXr/o/xjRBftZRlG3dEWoaHr8j4GuypJ3isitGbVyjQKAuMu+xbiop8q224TjiZWc4XTZA==",
+ "dev": true,
+ "dependencies": {
+ "any-promise": "^1.1.0"
+ }
+ },
+ "node_modules/streamx": {
+ "version": "2.16.1",
+ "resolved": "https://registry.npmjs.org/streamx/-/streamx-2.16.1.tgz",
+ "integrity": "sha512-m9QYj6WygWyWa3H1YY69amr4nVgy61xfjys7xO7kviL5rfIEc2naf+ewFiOA+aEJD7y0JO3h2GoiUv4TDwEGzQ==",
+ "dev": true,
+ "dependencies": {
+ "fast-fifo": "^1.1.0",
+ "queue-tick": "^1.0.1"
+ },
+ "optionalDependencies": {
+ "bare-events": "^2.2.0"
+ }
+ },
+ "node_modules/string_decoder": {
+ "version": "1.3.0",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.3.0.tgz",
+ "integrity": "sha512-hkRX8U1WjJFd8LsDJ2yQ/wWWxaopEsABU1XfkM8A+j0+85JAGppt16cr1Whg6KIbb4okU6Mql6BOj+uup/wKeA==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.2.0"
+ }
+ },
+ "node_modules/string-width": {
+ "version": "4.2.3",
+ "resolved": "https://registry.npmjs.org/string-width/-/string-width-4.2.3.tgz",
+ "integrity": "sha512-wKyQRQpjJ0sIp62ErSZdGsjMJWsap5oRNihHhu6G7JVO/9jIB6UyevL+tXuOqrng8j/cxKTWyWUwvSTriiZz/g==",
+ "dev": true,
+ "dependencies": {
+ "emoji-regex": "^8.0.0",
+ "is-fullwidth-code-point": "^3.0.0",
+ "strip-ansi": "^6.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/ansi-regex": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-5.0.1.tgz",
+ "integrity": "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ==",
+ "dev": true,
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/string-width/node_modules/strip-ansi": {
+ "version": "6.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-6.0.1.tgz",
+ "integrity": "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A==",
+ "dev": true,
+ "dependencies": {
+ "ansi-regex": "^5.0.1"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/stringify-object": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/stringify-object/-/stringify-object-5.0.0.tgz",
+ "integrity": "sha512-zaJYxz2FtcMb4f+g60KsRNFOpVMUyuJgA51Zi5Z1DOTC3S59+OQiVOzE9GZt0x72uBGWKsQIuBKeF9iusmKFsg==",
+ "dev": true,
+ "dependencies": {
+ "get-own-enumerable-keys": "^1.0.0",
+ "is-obj": "^3.0.0",
+ "is-regexp": "^3.1.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/yeoman/stringify-object?sponsor=1"
+ }
+ },
+ "node_modules/strip-ansi": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz",
+ "integrity": "sha512-VhumSSbBqDTP8p2ZLKj40UjBCV4+v8bUSEpUb4KjRgWk9pbqGF4REFj6KEagidb2f/M6AzC0EmFyDNGaw9OCzg==",
+ "dev": true,
+ "license": "MIT",
+ "dependencies": {
+ "ansi-regex": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/strip-bom-buf": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/strip-bom-buf/-/strip-bom-buf-3.0.1.tgz",
+ "integrity": "sha512-iJaWw2WroigLHzQysdc5WWeUc99p7ea7AEgB6JkY8CMyiO1yTVAA1gIlJJgORElUIR+lcZJkNl1OGChMhvc2Cw==",
+ "dev": true,
+ "dependencies": {
+ "is-utf8": "^0.2.1"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/strip-bom-stream": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/strip-bom-stream/-/strip-bom-stream-5.0.0.tgz",
+ "integrity": "sha512-Yo472mU+3smhzqeKlIxClre4s4pwtYZEvDNQvY/sJpnChdaxmKuwU28UVx/v1ORKNMxkmj1GBuvxJQyBk6wYMQ==",
+ "dev": true,
+ "dependencies": {
+ "first-chunk-stream": "^5.0.0",
+ "strip-bom-buf": "^3.0.0"
+ },
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/supports-color": {
+ "version": "7.2.0",
+ "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-7.2.0.tgz",
+ "integrity": "sha512-qpCAvRl9stuOHveKsn7HncJRvv501qIacKzQlO/+Lwxc9+0q2wLyv4Dfvt80/DPn2pqOBsJdDiogXGR9+OvwRw==",
+ "dev": true,
+ "dependencies": {
+ "has-flag": "^4.0.0"
+ },
+ "engines": {
+ "node": ">=8"
+ }
+ },
+ "node_modules/supports-preserve-symlinks-flag": {
+ "version": "1.0.0",
+ "resolved": "https://registry.npmjs.org/supports-preserve-symlinks-flag/-/supports-preserve-symlinks-flag-1.0.0.tgz",
+ "integrity": "sha512-ot0WnXS9fgdkgIcePe6RHNk1WA8+muPa6cSjeR3V8K27q9BB1rTE3R1p7Hv0z1ZyAc8s6Vvv8DIyWf681MAt0w==",
+ "dev": true,
+ "engines": {
+ "node": ">= 0.4"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/ljharb"
+ }
+ },
+ "node_modules/sver": {
+ "version": "1.8.4",
+ "resolved": "https://registry.npmjs.org/sver/-/sver-1.8.4.tgz",
+ "integrity": "sha512-71o1zfzyawLfIWBOmw8brleKyvnbn73oVHNCsu51uPMz/HWiKkkXsI31JjHW5zqXEqnPYkIiHd8ZmL7FCimLEA==",
+ "dev": true,
+ "optionalDependencies": {
+ "semver": "^6.3.0"
+ }
+ },
+ "node_modules/sver/node_modules/semver": {
+ "version": "6.3.1",
+ "resolved": "https://registry.npmjs.org/semver/-/semver-6.3.1.tgz",
+ "integrity": "sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA==",
+ "dev": true,
+ "optional": true,
+ "bin": {
+ "semver": "bin/semver.js"
+ }
+ },
+ "node_modules/svg-pathdata": {
+ "version": "6.0.3",
+ "resolved": "https://registry.npmjs.org/svg-pathdata/-/svg-pathdata-6.0.3.tgz",
+ "integrity": "sha512-qsjeeq5YjBZ5eMdFuUa4ZosMLxgr5RZ+F+Y1OrDhuOCEInRMA3x74XdBtggJcj9kOeInz0WE+LgCPDkZFlBYJw==",
+ "optional": true,
+ "engines": {
+ "node": ">=12.0.0"
+ }
+ },
+ "node_modules/svg-to-pdfkit": {
+ "version": "0.1.8",
+ "resolved": "https://registry.npmjs.org/svg-to-pdfkit/-/svg-to-pdfkit-0.1.8.tgz",
+ "integrity": "sha512-QItiGZBy5TstGy+q8mjQTMGRlDDOARXLxH+sgVm1n/LYeo0zFcQlcCh8m4zi8QxctrxB9Kue/lStc/RD5iLadQ==",
+ "dependencies": {
+ "pdfkit": ">=0.8.1"
+ }
+ },
+ "node_modules/tableexport.jquery.plugin": {
+ "version": "1.30.0",
+ "resolved": "https://registry.npmjs.org/tableexport.jquery.plugin/-/tableexport.jquery.plugin-1.30.0.tgz",
+ "integrity": "sha512-kMztiFUsGbxsknFVCDph+5j4e9xmqBBV6Na7T9vRYCUGDxtlndrdxMs9qLJDSOXjlgkIqCUv+S/e5iTUNAFF/g==",
+ "dependencies": {
+ "file-saver": ">=2.0.4",
+ "html2canvas": ">=1.0.0",
+ "jquery": ">=3.2.1",
+ "jspdf": ">=2.0.0",
+ "pdfmake": "^0.1.71",
+ "xlsx": ">=0.16.0"
+ }
+ },
+ "node_modules/tar-stream": {
+ "version": "3.1.7",
+ "resolved": "https://registry.npmjs.org/tar-stream/-/tar-stream-3.1.7.tgz",
+ "integrity": "sha512-qJj60CXt7IU1Ffyc3NJMjh6EkuCFej46zUqJ4J7pqYlThyd9bO0XBTmcOIhSzZJVWfsLks0+nle/j538YAW9RQ==",
+ "dev": true,
+ "dependencies": {
+ "b4a": "^1.6.4",
+ "fast-fifo": "^1.2.0",
+ "streamx": "^2.15.0"
+ }
+ },
+ "node_modules/teex": {
+ "version": "1.0.1",
+ "resolved": "https://registry.npmjs.org/teex/-/teex-1.0.1.tgz",
+ "integrity": "sha512-eYE6iEI62Ni1H8oIa7KlDU6uQBtqr4Eajni3wX7rpfXD8ysFx8z0+dri+KWEPWpBsxXfxu58x/0jvTVT1ekOSg==",
+ "dev": true,
+ "dependencies": {
+ "streamx": "^2.12.5"
+ }
+ },
+ "node_modules/text-segmentation": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/text-segmentation/-/text-segmentation-1.0.3.tgz",
+ "integrity": "sha512-iOiPUo/BGnZ6+54OsWxZidGCsdU8YbE4PSpdPinp7DeMtUJNJBoJ/ouUSTJjHkh1KntHaltHl/gDs2FC4i5+Nw==",
+ "dependencies": {
+ "utrie": "^1.0.2"
+ }
+ },
+ "node_modules/through": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz",
+ "integrity": "sha512-w89qg7PI8wAdvX60bMDP+bFoD5Dvhm9oLheFp5O4a2QF0cSBGsBX4qZmadPMvVqlLJBBci+WqGGOAPvcDeNSVg==",
+ "dev": true
+ },
+ "node_modules/through2": {
+ "version": "2.0.5",
+ "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz",
+ "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==",
+ "dev": true,
+ "dependencies": {
+ "readable-stream": "~2.3.6",
+ "xtend": "~4.0.1"
+ }
+ },
+ "node_modules/through2/node_modules/readable-stream": {
+ "version": "2.3.8",
+ "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.8.tgz",
+ "integrity": "sha512-8p0AUk4XODgIewSi0l8Epjs+EVnWiK7NoDIEGU0HhE7+ZyY8D1IMY7odu5lRrFXGg71L15KG8QrPmum45RTtdA==",
+ "dev": true,
+ "dependencies": {
+ "core-util-is": "~1.0.0",
+ "inherits": "~2.0.3",
+ "isarray": "~1.0.0",
+ "process-nextick-args": "~2.0.0",
+ "safe-buffer": "~5.1.1",
+ "string_decoder": "~1.1.1",
+ "util-deprecate": "~1.0.1"
+ }
+ },
+ "node_modules/through2/node_modules/safe-buffer": {
+ "version": "5.1.2",
+ "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz",
+ "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==",
+ "dev": true
+ },
+ "node_modules/through2/node_modules/string_decoder": {
+ "version": "1.1.1",
+ "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz",
+ "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==",
+ "dev": true,
+ "dependencies": {
+ "safe-buffer": "~5.1.0"
+ }
+ },
+ "node_modules/tildify": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/tildify/-/tildify-3.0.0.tgz",
+ "integrity": "sha512-9ZLMl75qnTLr7oSEmWJbKemFS/fP4TMBiF6PFwGwLpgobebU1ehXoGbadJ+7jT8fjaz2G82JgN9G4taz+o1j1w==",
+ "dev": true,
+ "engines": {
+ "node": "^12.20.0 || ^14.13.1 || >=16.0.0"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/time-stamp": {
+ "version": "1.1.0",
+ "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz",
+ "integrity": "sha512-gLCeArryy2yNTRzTGKbZbloctj64jkZ57hj5zdraXue6aFgd6PmvVtEyiUU+hvU0v7q08oVv8r8ev0tRo6bvgw==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/tiny-emitter": {
+ "version": "2.1.0",
+ "resolved": "https://registry.npmjs.org/tiny-emitter/-/tiny-emitter-2.1.0.tgz",
+ "integrity": "sha512-NB6Dk1A9xgQPMoGqC5CVXn123gWyte215ONT5Pp5a0yt4nlEoO1ZWeCwpncaekPHXO60i47ihFnZPiRPjRMq4Q=="
+ },
+ "node_modules/tiny-inflate": {
+ "version": "1.0.3",
+ "resolved": "https://registry.npmjs.org/tiny-inflate/-/tiny-inflate-1.0.3.tgz",
+ "integrity": "sha512-pkY1fj1cKHb2seWDy0B16HeWyczlJA9/WW3u3c4z/NiWDsO3DOU5D7nhTLE9CF0yXv/QZFY7sEJmj24dK+Rrqw=="
+ },
+ "node_modules/to-regex-range": {
+ "version": "5.0.1",
+ "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-5.0.1.tgz",
+ "integrity": "sha512-65P7iz6X5yEr1cwcgvQxbbIw7Uk3gOy5dIdtZ4rDveLqhrdJP+Li/Hx6tyK0NEb+2GCyneCMJiGqrADCSNk8sQ==",
+ "dev": true,
+ "dependencies": {
+ "is-number": "^7.0.0"
+ },
+ "engines": {
+ "node": ">=8.0"
+ }
+ },
+ "node_modules/to-through": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/to-through/-/to-through-3.0.0.tgz",
+ "integrity": "sha512-y8MN937s/HVhEoBU1SxfHC+wxCHkV1a9gW8eAdTadYh/bGyesZIVcbjI+mSpFbSVwQici/XjBjuUyri1dnXwBw==",
+ "dev": true,
+ "dependencies": {
+ "streamx": "^2.12.5"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/tslib": {
+ "version": "2.6.2",
+ "resolved": "https://registry.npmjs.org/tslib/-/tslib-2.6.2.tgz",
+ "integrity": "sha512-AEYxH93jGFPn/a2iVAwW87VuUIkR1FVUKB77NwMF7nBTDkDrrT/Hpt/IrCJ0QXhW27jTBDcf5ZY7w6RiqTMw2Q=="
+ },
+ "node_modules/uglify-js": {
+ "version": "3.17.4",
+ "resolved": "https://registry.npmjs.org/uglify-js/-/uglify-js-3.17.4.tgz",
+ "integrity": "sha512-T9q82TJI9e/C1TAxYvfb16xO120tMVFZrGA3f9/P4424DNu6ypK103y0GPFVa17yotwSyZW5iYXgjYHkGrJW/g==",
+ "dev": true,
+ "bin": {
+ "uglifyjs": "bin/uglifyjs"
+ },
+ "engines": {
+ "node": ">=0.8.0"
+ }
+ },
+ "node_modules/unc-path-regex": {
+ "version": "0.1.2",
+ "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz",
+ "integrity": "sha512-eXL4nmJT7oCpkZsHZUOJo8hcX3GbsiDOa0Qu9F646fi8dT3XuSVopVqAcEiVzSKKH7UoDti23wNX3qGFxcW5Qg==",
+ "dev": true,
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/undertaker": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-2.0.0.tgz",
+ "integrity": "sha512-tO/bf30wBbTsJ7go80j0RzA2rcwX6o7XPBpeFcb+jzoeb4pfMM2zUeSDIkY1AWqeZabWxaQZ/h8N9t35QKDLPQ==",
+ "dev": true,
+ "dependencies": {
+ "bach": "^2.0.1",
+ "fast-levenshtein": "^3.0.0",
+ "last-run": "^2.0.0",
+ "undertaker-registry": "^2.0.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/undertaker-registry": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-2.0.0.tgz",
+ "integrity": "sha512-+hhVICbnp+rlzZMgxXenpvTxpuvA67Bfgtt+O9WOE5jo7w/dyiF1VmoZVIHvP2EkUjsyKyTwYKlLhA+j47m1Ew==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/undici-types": {
+ "version": "5.26.5",
+ "resolved": "https://registry.npmjs.org/undici-types/-/undici-types-5.26.5.tgz",
+ "integrity": "sha512-JlCMO+ehdEIKqlFxk6IfVoAUVmgz7cU7zD/h9XZ0qzeosSHmUJVOzSQvvYSYWXkFXC+IfLKSIffhv0sVZup6pA==",
+ "dev": true
+ },
+ "node_modules/unicode-properties": {
+ "version": "1.4.1",
+ "resolved": "https://registry.npmjs.org/unicode-properties/-/unicode-properties-1.4.1.tgz",
+ "integrity": "sha512-CLjCCLQ6UuMxWnbIylkisbRj31qxHPAurvena/0iwSVbQ2G1VY5/HjV0IRabOEbDHlzZlRdCrD4NhB0JtU40Pg==",
+ "dependencies": {
+ "base64-js": "^1.3.0",
+ "unicode-trie": "^2.0.0"
+ }
+ },
+ "node_modules/unicode-trie": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/unicode-trie/-/unicode-trie-2.0.0.tgz",
+ "integrity": "sha512-x7bc76x0bm4prf1VLg79uhAzKw8DVboClSN5VxJuQ+LKDOVEW9CdH+VY7SP+vX7xCYQqzzgQpFqz15zeLvAtZQ==",
+ "dependencies": {
+ "pako": "^0.2.5",
+ "tiny-inflate": "^1.0.0"
+ }
+ },
+ "node_modules/union-value": {
+ "version": "2.0.1",
+ "resolved": "https://registry.npmjs.org/union-value/-/union-value-2.0.1.tgz",
+ "integrity": "sha512-NmcRHHhUy1qWmp6yYWsaURV2qwfS24TmTtO9S9x0L41wCNNVBQFD3toOzO0cd8SsNrFhbw/O0iYO5uffXGYocw==",
+ "dev": true,
+ "dependencies": {
+ "get-value": "^3.0.1",
+ "set-value": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=6"
+ }
+ },
+ "node_modules/union-value/node_modules/get-value": {
+ "version": "3.0.1",
+ "resolved": "https://registry.npmjs.org/get-value/-/get-value-3.0.1.tgz",
+ "integrity": "sha512-mKZj9JLQrwMBtj5wxi6MH8Z5eSKaERpAwjg43dPtlGI1ZVEgH/qC7T8/6R2OBSUA+zzHBZgICsVJaEIV2tKTDA==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/union-value/node_modules/is-plain-object": {
+ "version": "2.0.4",
+ "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz",
+ "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==",
+ "dev": true,
+ "dependencies": {
+ "isobject": "^3.0.1"
+ },
+ "engines": {
+ "node": ">=0.10.0"
+ }
+ },
+ "node_modules/union-value/node_modules/set-value": {
+ "version": "3.0.3",
+ "resolved": "https://registry.npmjs.org/set-value/-/set-value-3.0.3.tgz",
+ "integrity": "sha512-Xsn/XSatoVOGBbp5hs3UylFDs5Bi9i+ArpVJKdHPniZHoEgRniXTqHWrWrGQ0PbEClVT6WtfnBwR8CAHC9sveg==",
+ "dev": true,
+ "dependencies": {
+ "is-plain-object": "^2.0.4"
+ },
+ "engines": {
+ "node": ">=6.0"
+ }
+ },
+ "node_modules/util-deprecate": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz",
+ "integrity": "sha512-EPD5q1uXyFxJpCrLnCc1nHnq3gOa6DZBocAIiI2TaSCA7VCJ1UJDMagCzIkXNsUYfD1daK//LTEQ8xiIbrHtcw==",
+ "dev": true
+ },
+ "node_modules/utrie": {
+ "version": "1.0.2",
+ "resolved": "https://registry.npmjs.org/utrie/-/utrie-1.0.2.tgz",
+ "integrity": "sha512-1MLa5ouZiOmQzUbjbu9VmjLzn1QLXBhwpUa7kdLUQK+KQ5KA9I1vk5U4YHe/X2Ch7PYnJfWuWT+VbuxbGwljhw==",
+ "dependencies": {
+ "base64-arraybuffer": "^1.0.2"
+ }
+ },
+ "node_modules/v8flags": {
+ "version": "4.0.1",
+ "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-4.0.1.tgz",
+ "integrity": "sha512-fcRLaS4H/hrZk9hYwbdRM35D0U8IYMfEClhXxCivOojl+yTRAZH3Zy2sSy6qVCiGbV9YAtPssP6jaChqC9vPCg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/value-or-function": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-4.0.0.tgz",
+ "integrity": "sha512-aeVK81SIuT6aMJfNo9Vte8Dw0/FZINGBV8BfCraGtqVxIeLAEhJyoWs8SmvRVmXfGss2PmmOwZCuBPbZR+IYWg==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10.13.0"
+ }
+ },
+ "node_modules/vinyl": {
+ "version": "2.2.1",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.1.tgz",
+ "integrity": "sha512-LII3bXRFBZLlezoG5FfZVcXflZgWP/4dCwKtxd5ky9+LOtM4CS3bIRQsmR1KMnMW07jpE8fqR2lcxPZ+8sJIcw==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.1",
+ "clone-buffer": "^1.0.0",
+ "clone-stats": "^1.0.0",
+ "cloneable-readable": "^1.0.0",
+ "remove-trailing-separator": "^1.0.1",
+ "replace-ext": "^1.0.0"
+ },
+ "engines": {
+ "node": ">= 0.10"
+ }
+ },
+ "node_modules/vinyl-contents": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl-contents/-/vinyl-contents-2.0.0.tgz",
+ "integrity": "sha512-cHq6NnGyi2pZ7xwdHSW1v4Jfnho4TEGtxZHw01cmnc8+i7jgR6bRnED/LbrKan/Q7CvVLbnvA5OepnhbpjBZ5Q==",
+ "dev": true,
+ "dependencies": {
+ "bl": "^5.0.0",
+ "vinyl": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/vinyl-contents/node_modules/replace-ext": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
+ "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/vinyl-contents/node_modules/vinyl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
+ "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.2",
+ "clone-stats": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0",
+ "replace-ext": "^2.0.0",
+ "teex": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/vinyl-file": {
+ "version": "5.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl-file/-/vinyl-file-5.0.0.tgz",
+ "integrity": "sha512-MvkPF/yA1EX7c6p+juVIvp9+Lxp70YUfNKzEWeHMKpUNVSnTZh2coaOqLxI0pmOe2V9nB+OkgFaMDkodaJUyGw==",
+ "dev": true,
+ "dependencies": {
+ "@types/vinyl": "^2.0.7",
+ "strip-bom-buf": "^3.0.1",
+ "strip-bom-stream": "^5.0.0",
+ "vinyl": "^3.0.0"
+ },
+ "engines": {
+ "node": ">=14.16"
+ },
+ "funding": {
+ "url": "https://github.com/sponsors/sindresorhus"
+ }
+ },
+ "node_modules/vinyl-file/node_modules/replace-ext": {
+ "version": "2.0.0",
+ "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-2.0.0.tgz",
+ "integrity": "sha512-UszKE5KVK6JvyD92nzMn9cDapSk6w/CaFZ96CnmDMUqH9oowfxF/ZjRITD25H4DnOQClLA4/j7jLGXXLVKxAug==",
+ "dev": true,
+ "engines": {
+ "node": ">= 10"
+ }
+ },
+ "node_modules/vinyl-file/node_modules/vinyl": {
+ "version": "3.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-3.0.0.tgz",
+ "integrity": "sha512-rC2VRfAVVCGEgjnxHUnpIVh3AGuk62rP3tqVrn+yab0YH7UULisC085+NYH+mnqf3Wx4SpSi1RQMwudL89N03g==",
+ "dev": true,
+ "dependencies": {
+ "clone": "^2.1.2",
+ "clone-stats": "^1.0.0",
+ "remove-trailing-separator": "^1.1.0",
+ "replace-ext": "^2.0.0",
+ "teex": "^1.0.1"
+ },
+ "engines": {
+ "node": ">=10.13.0"
+ }
+ },
+ "node_modules/vinyl-fs": {
+ "version": "4.0.0",
+ "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-4.0.0.tgz",
+ "integrity": "sha512-7GbgBnYfaquMk3Qu9g22x000vbYkOex32930rBnc3qByw6HfMEAoELjCjoJv4HuEQxHAurT+nvMHm6MnJllFLw==",
+ "dev": true,
+ "dependencies": {
"fs-mkdirp-stream": "^2.0.1",
"glob-stream": "^8.0.0",
"graceful-fs": "^4.2.11",
diff --git a/package.json b/package.json
index 24670dddb..f3d10cbb6 100644
--- a/package.json
+++ b/package.json
@@ -1,84 +1,84 @@
{
- "name": "@opensourcepos/opensourcepos",
- "version": "3.4.0",
- "description": "Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.",
- "main": "index.php",
- "license": "MIT",
- "authors": [
- "jekkos ",
- "FrancescoUK ",
- "objecttothis ",
- "SteveIreland "
- ],
- "files": [
- "dist/opensourcepos.$version.tgz"
- ],
- "publishConfig": {
- "registry": "https://npm.pkg.github.com/"
- },
- "keywords": [
- "point-of-sale",
- "POS"
- ],
- "repository": {
- "type": "git",
- "url": "https://github.com/opensourcepos/opensourcepos"
- },
- "scripts": {
- "build": "gulp default",
- "gulp": "gulp"
- },
- "type": "module",
- "dependencies": {
- "bootstrap": "^3.4.1",
- "bootstrap-daterangepicker": "^2.1.27",
- "bootstrap-datetime-picker": "2.4.4",
- "bootstrap-notify": "^3.1.3",
- "bootstrap-select": "^1.13.18",
- "bootstrap-table": "^1.23.5",
- "bootstrap-tagsinput-2021": "^0.8.6",
- "bootstrap-toggle": "^2.2.2",
- "bootstrap3-dialog": "github:nakupanda/bootstrap3-dialog#master",
- "bootstrap5": "npm:bootstrap@^5.3.3",
- "bootswatch": "^3.4.1",
- "bootswatch5": "npm:bootswatch@^5.3.3",
- "chartist": "^0.11.4",
- "chartist-plugin-axistitle": "^0.0.7",
- "chartist-plugin-barlabels": "^0.0.5",
- "chartist-plugin-pointlabels": "^0.0.6",
- "chartist-plugin-tooltips": "^0.0.17",
- "clipboard": "^2.0.11",
- "coffeescript": "^2.7.0",
- "es6-promise": "^4.2.8",
- "file-saver": "^2.0.5",
- "html2canvas": "^1.4.1",
- "jasny-bootstrap": "^3.1.3",
- "jquery": "^3.7.1",
- "jquery-form": "^4.3.0",
- "jquery-ui-dist": "^1.12.1",
- "jquery-validation": "^1.19.5",
- "js-cookie": "^2.2.1",
- "jspdf": "^2.5.1",
- "jspdf-autotable": "^3.8.2",
- "tableexport.jquery.plugin": "^1.30.0"
- },
- "devDependencies": {
- "gulp": "^5.0.0",
- "gulp-clean": "^0.4.0",
- "gulp-clean-css": "^4.3.0",
- "gulp-concat": "^2.6.1",
- "gulp-debug": "^5.0.1",
- "gulp-gzip": "^1.4.2",
- "gulp-header": "^2.0.9",
- "gulp-inject": "^5.0.5",
- "gulp-rename": "^2.0.0",
- "gulp-rev": "^10.0.0",
- "gulp-run": "^1.7.1",
- "gulp-tar": "^4.0.0",
- "gulp-uglify": "^3.0.2",
- "gulp-zip": "^6.1.0",
- "npm-check-updates": "^17.1.14",
- "readable-stream": "^4.4.2",
- "stream-series": "^0.1.1"
- }
+ "name": "@opensourcepos/opensourcepos",
+ "version": "3.4.0",
+ "description": "Open Source Point of Sale is a web based point of sale system written in the PHP language. It uses MySQL as the data storage back-end and has a simple user interface.",
+ "main": "index.php",
+ "license": "MIT",
+ "authors": [
+ "jekkos ",
+ "FrancescoUK ",
+ "objecttothis ",
+ "SteveIreland "
+ ],
+ "files": [
+ "dist/opensourcepos.$version.tgz"
+ ],
+ "publishConfig": {
+ "registry": "https://npm.pkg.github.com/"
+ },
+ "keywords": [
+ "point-of-sale",
+ "POS"
+ ],
+ "repository": {
+ "type": "git",
+ "url": "https://github.com/opensourcepos/opensourcepos"
+ },
+ "scripts": {
+ "build": "gulp default",
+ "gulp": "gulp"
+ },
+ "type": "module",
+ "dependencies": {
+ "bootstrap": "^3.4.1",
+ "bootstrap-daterangepicker": "^2.1.27",
+ "bootstrap-datetime-picker": "2.4.4",
+ "bootstrap-notify": "^3.1.3",
+ "bootstrap-select": "^1.13.18",
+ "bootstrap-table": "^1.23.5",
+ "bootstrap-tagsinput-2021": "^0.8.6",
+ "bootstrap-toggle": "^2.2.2",
+ "bootstrap3-dialog": "github:nakupanda/bootstrap3-dialog#master",
+ "bootstrap5": "npm:bootstrap@^5.3.3",
+ "bootswatch": "^3.4.1",
+ "bootswatch5": "npm:bootswatch@^5.3.3",
+ "chartist": "^0.11.4",
+ "chartist-plugin-axistitle": "^0.0.7",
+ "chartist-plugin-barlabels": "^0.0.5",
+ "chartist-plugin-pointlabels": "^0.0.6",
+ "chartist-plugin-tooltips": "^0.0.17",
+ "clipboard": "^2.0.11",
+ "coffeescript": "^2.7.0",
+ "es6-promise": "^4.2.8",
+ "file-saver": "^2.0.5",
+ "html2canvas": "^1.4.1",
+ "jasny-bootstrap": "^3.1.3",
+ "jquery": "^3.7.1",
+ "jquery-form": "^4.3.0",
+ "jquery-ui-dist": "^1.12.1",
+ "jquery-validation": "^1.19.5",
+ "js-cookie": "^2.2.1",
+ "jspdf": "^2.5.1",
+ "jspdf-autotable": "^3.8.2",
+ "tableexport.jquery.plugin": "^1.30.0"
+ },
+ "devDependencies": {
+ "gulp": "^5.0.0",
+ "gulp-clean": "^0.4.0",
+ "gulp-clean-css": "^4.3.0",
+ "gulp-concat": "^2.6.1",
+ "gulp-debug": "^5.0.1",
+ "gulp-gzip": "^1.4.2",
+ "gulp-header": "^2.0.9",
+ "gulp-inject": "^5.0.5",
+ "gulp-rename": "^2.0.0",
+ "gulp-rev": "^10.0.0",
+ "gulp-run": "^1.7.1",
+ "gulp-tar": "^4.0.0",
+ "gulp-uglify": "^3.0.2",
+ "gulp-zip": "^6.1.0",
+ "npm-check-updates": "^17.1.14",
+ "readable-stream": "^4.4.2",
+ "stream-series": "^0.1.1"
+ }
}
diff --git a/public/.htaccess b/public/.htaccess
index f9bfc285b..033ea98d6 100644
--- a/public/.htaccess
+++ b/public/.htaccess
@@ -8,23 +8,23 @@ Options All -Indexes
# Turning on the rewrite engine is necessary for the following rules and features.
# FollowSymLinks must be enabled for this to work.
- Options +SymLinksIfOwnerMatch
- RewriteEngine On
+ Options +SymLinksIfOwnerMatch
+ RewriteEngine On
- # If you installed CodeIgniter in a subfolder, you will need to
- # change the following line to match the subfolder you need.
- # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
- # RewriteBase /
+ # If you installed CodeIgniter in a subfolder, you will need to
+ # change the following line to match the subfolder you need.
+ # http://httpd.apache.org/docs/current/mod/mod_rewrite.html#rewritebase
+ # RewriteBase /
- # Redirect Trailing Slashes...
- # RewriteCond %{REQUEST_FILENAME} !-d
- # RewriteCond %{REQUEST_URI} (.+)/$
- # RewriteRule ^ %1 [L,R=301]
+ # Redirect Trailing Slashes...
+ # RewriteCond %{REQUEST_FILENAME} !-d
+ # RewriteCond %{REQUEST_URI} (.+)/$
+ # RewriteRule ^ %1 [L,R=301]
- # Rewrite "www.example.com -> example.com"
- RewriteCond %{HTTPS} !=on
- RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
- RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
+ # Rewrite "www.example.com -> example.com"
+ RewriteCond %{HTTPS} !=on
+ RewriteCond %{HTTP_HOST} ^www\.(.+)$ [NC]
+ RewriteRule ^ http://%1%{REQUEST_URI} [R=301,L]
# To redirect a subdomain to a subdir because of https not supporting wildcards
# replace values between <> with your values
@@ -32,31 +32,31 @@ Options All -Indexes
# RewriteCond %{HTTP_HOST} ^www\.\.\.com$
# RewriteRule ^/?$ "https\:\/\/www\.\.com\/" [R=301,L]
- # Checks to see if the user is attempting to access a valid file,
- # such as an image or css document, if this isn't true it sends the
- # request to the front controller, index.php
- RewriteCond %{REQUEST_FILENAME} !-f
- RewriteCond %{REQUEST_FILENAME} !-d
+ # Checks to see if the user is attempting to access a valid file,
+ # such as an image or css document, if this isn't true it sends the
+ # request to the front controller, index.php
+ RewriteCond %{REQUEST_FILENAME} !-f
+ RewriteCond %{REQUEST_FILENAME} !-d
- # if in web root
- RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
+ # if in web root
+ RewriteRule ^([\s\S]*)$ index.php/$1 [L,NC,QSA]
# if in subdir comment above line, uncomment the line below and replace with your path
#RewriteRule ^(.*)$ //public/index.php?/$1 [L]
- # Ensure Authorization header is passed along
- RewriteCond %{HTTP:Authorization} .
- RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
+ # Ensure Authorization header is passed along
+ RewriteCond %{HTTP:Authorization} .
+ RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
- # If we don't have mod_rewrite installed, all 404's
- # can be sent to index.php, and everything works as normal.
- ErrorDocument 404 index.php
+ # If we don't have mod_rewrite installed, all 404's
+ # can be sent to index.php, and everything works as normal.
+ ErrorDocument 404 index.php
# Disable server signature start
- ServerSignature Off
+ ServerSignature Off
# Disable server signature end
diff --git a/public/css/barcode_font.css b/public/css/barcode_font.css
index 6c7fffe0b..8bcb99fe0 100644
--- a/public/css/barcode_font.css
+++ b/public/css/barcode_font.css
@@ -1,47 +1,47 @@
-@font-face
+@font-face
{
font-family: 'SansationLight';
- src: url('../fonts/SansationLight.eot');
- src: local('SansationLight'), url('../fonts/SansationLight.woff') format('woff'), url('../fonts/SansationLight.ttf') format('truetype');
+ src: url('../fonts/SansationLight.eot');
+ src: local('SansationLight'), url('../fonts/SansationLight.woff') format('woff'), url('../fonts/SansationLight.ttf') format('truetype');
}
.font_SansationLight
{
- font-family: 'SansationLight' !important;
+ font-family: 'SansationLight' !important;
}
-@font-face
+@font-face
{
font-family:'Arial';
- src: url('../fonts/Arial.eot');
- src: local('Arial'), url('../fonts/Arial.woff') format('woff'), url('../fonts/Arial.ttf') format('truetype');
+ src: url('../fonts/Arial.eot');
+ src: local('Arial'), url('../fonts/Arial.woff') format('woff'), url('../fonts/Arial.ttf') format('truetype');
}
.font_Arial
{
- font-family: 'Arial' !important;
+ font-family: 'Arial' !important;
}
-@font-face
+@font-face
{
font-family: 'JUNEBUG';
- src: url('../fonts/JUNEBUG.eot');
- src: local('JUNEBUG'), url('../fonts/JUNEBUG.woff') format('woff'), url('../fonts/JUNEBUG.ttf') format('truetype');
+ src: url('../fonts/JUNEBUG.eot');
+ src: local('JUNEBUG'), url('../fonts/JUNEBUG.woff') format('woff'), url('../fonts/JUNEBUG.ttf') format('truetype');
}
.font_JUNEBUG
{
- font-family: 'JUNEBUG' !important;
+ font-family: 'JUNEBUG' !important;
}
-@font-face
+@font-face
{
font-family: 'b-de-bonita-shadow';
- src: url('../fonts/b-de-bonita-shadow.eot');
- src: local('JUNEBUG'), url('../fonts/b-de-bonita-shadow.woff') format('woff'), url('../fonts/b-de-bonita-shadow.ttf') format('truetype');
+ src: url('../fonts/b-de-bonita-shadow.eot');
+ src: local('JUNEBUG'), url('../fonts/b-de-bonita-shadow.woff') format('woff'), url('../fonts/b-de-bonita-shadow.ttf') format('truetype');
}
.font_b-de-bonita-shadow
{
- font-family: 'b-de-bonita-shadow' !important;
-}
\ No newline at end of file
+ font-family: 'b-de-bonita-shadow' !important;
+}
diff --git a/public/css/bootstrap.autocomplete.css b/public/css/bootstrap.autocomplete.css
index 5a7dcc6d9..63b37c8e5 100644
--- a/public/css/bootstrap.autocomplete.css
+++ b/public/css/bootstrap.autocomplete.css
@@ -11,7 +11,7 @@
padding: 5px 0;
margin: 2px 0 0 0;
list-style: none;
- font-size: 13px;
+ font-size: 13px;
background-color: #ffffff;
border-color: #cccccc;
border-color: rgba(0, 0, 0, 0.15);
@@ -30,7 +30,7 @@
*border-bottom-width: 2px;
}
-.ui-autocomplete .ui-menu-item > a.ui-corner-all
+.ui-autocomplete .ui-menu-item > a.ui-corner-all
{
display: block;
padding: 3px 15px;
diff --git a/public/css/invoice.css b/public/css/invoice.css
index 57966aca3..7ab1ccc66 100644
--- a/public/css/invoice.css
+++ b/public/css/invoice.css
@@ -1,7 +1,7 @@
/*
- CSS-Tricks Example
- by Chris Coyier
- http://css-tricks.com
+ CSS-Tricks Example
+ by Chris Coyier
+ http://css-tricks.com
*/
/*body { font: 14px/1.4 Georgia, serif; }*/
diff --git a/public/css/invoice_email.css b/public/css/invoice_email.css
index 8e01a6b4d..b82a26e76 100644
--- a/public/css/invoice_email.css
+++ b/public/css/invoice_email.css
@@ -1,7 +1,7 @@
/*
- CSS-Tricks Example
- by Chris Coyier
- http://css-tricks.com
+ CSS-Tricks Example
+ by Chris Coyier
+ http://css-tricks.com
*/
#menubar, #footer { display: none; }
* { margin: 0; padding: 0; }
diff --git a/public/css/ospos.css b/public/css/ospos.css
index d88bc1386..e44524df8 100644
--- a/public/css/ospos.css
+++ b/public/css/ospos.css
@@ -2,198 +2,198 @@
html, body
{
- height: 100%;
+ height: 100%;
}
a.none
{
- text-decoration: none;
+ text-decoration: none;
}
.topbar
{
- color: #eee;
- font-size: 12px;
- background: #182735;
- padding: 0.2em;
+ color: #eee;
+ font-size: 12px;
+ background: #182735;
+ padding: 0.2em;
}
@media (min-width:1300px) {
- .container {
- width: 1400px;
- }
+ .container {
+ width: 1400px;
+ }
}
.navbar
{
- border-radius: 0;
+ border-radius: 0;
}
-.navbar-default .navbar-nav > .active > a,
-.navbar-default .navbar-nav > .active > a:hover,
+.navbar-default .navbar-nav > .active > a,
+.navbar-default .navbar-nav > .active > a:hover,
.navbar-default .navbar-nav > .active > a:focus
{
- color: #2C3E50;
- background-color: #FFFFFF;
+ color: #2C3E50;
+ background-color: #FFFFFF;
}
.jumbotron.push-spaces
{
- margin:0; /*add this*/
+ margin:0; /*add this*/
}
.navbar .menu-icon
{
- text-align: center;
- font-size: 12px;
+ text-align: center;
+ font-size: 12px;
}
.navbar .menu-icon img
{
- width: 24px;
+ width: 24px;
}
.wrapper
{
- font-size: 13px;
+ font-size: 13px;
}
#title_bar
{
- position: relative;
- width: 100%;
- height: 3em;
+ position: relative;
+ width: 100%;
+ height: 3em;
}
#page_title
{
- font-size: 22px;
- font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
- font-weight: 400;
+ font-size: 22px;
+ font-family: "Lato", "Helvetica Neue", Helvetica, Arial, sans-serif;
+ font-weight: 400;
}
#page_subtitle
{
- margin-bottom: 0.5em;
- font-size: 16px;
- font-weight: bold;
- text-align: center;
+ margin-bottom: 0.5em;
+ font-size: 16px;
+ font-weight: bold;
+ text-align: center;
}
#home_module_list, #office_module_list
{
- position: relative;
- padding: 2em 0;
- text-align: center;
+ position: relative;
+ padding: 2em 0;
+ text-align: center;
}
.module_item
{
- min-width: 7em;
- display: inline-block;
- text-align: center;
+ min-width: 7em;
+ display: inline-block;
+ text-align: center;
}
.module_item a
{
- display: block;
+ display: block;
}
#config_wrapper
{
- text-align: center;
+ text-align: center;
}
#config_info
{
- text-align: left;
+ text-align: left;
}
#config_info .wide
{
- width: 30%;
+ width: 30%;
}
#integrations_header
{
- margin:10px 0;
- text-align:center;
- font-size:1.4em;
- font-weight:normal;
- padding:10px 0
+ margin:10px 0;
+ text-align:center;
+ font-size:1.4em;
+ font-weight:normal;
+ padding:10px 0
}
#footer
{
- margin-top: 5em;
- position: relative;
- text-align: center;
- font-size: 11px;
- color: #777777;
- clear: both;
+ margin-top: 5em;
+ position: relative;
+ text-align: center;
+ font-size: 11px;
+ color: #777777;
+ clear: both;
}
a.rollover img
{
- padding: 3px;
+ padding: 3px;
}
#filters.btn-group
{
- vertical-align: none;
+ vertical-align: none;
}
button.btn.dropdown-toggle.btn-sm
{
- background-color: white;
- color: black;
- border: 2px solid #dce4ec;
+ background-color: white;
+ color: black;
+ border: 2px solid #dce4ec;
}
.dropdown-menu
{
- font-size: 13px;
+ font-size: 13px;
}
.bootstrap-tagsinput
{
- background-color: white;
- color: black;
- border: 2px solid #dce4ec;
- box-shadow: none;
+ background-color: white;
+ color: black;
+ border: 2px solid #dce4ec;
+ box-shadow: none;
}
label.required
{
- color:red;
+ color:red;
}
@media (min-width: 768px)
-{
- .navbar-nav > li > a
- {
- padding: 10px 10px 9px;
- }
+{
+ .navbar-nav > li > a
+ {
+ padding: 10px 10px 9px;
+ }
- .modal-dlg .modal-dialog
- {
- width: 500px;
- }
+ .modal-dlg .modal-dialog
+ {
+ width: 500px;
+ }
- .modal-dlg-wide .modal-dialog
- {
- width: 750px;
- }
+ .modal-dlg-wide .modal-dialog
+ {
+ width: 750px;
+ }
}
.modal-body
{
- max-height: calc(100vh - 212px);
- overflow-y: auto;
+ max-height: calc(100vh - 212px);
+ overflow-y: auto;
}
.no-gutter [class*="-1"]
{
- padding-right:0;
- padding-left: 0;
+ padding-right:0;
+ padding-left: 0;
}
diff --git a/public/css/ospos_print.css b/public/css/ospos_print.css
index 91bf87eb0..8d6a2495a 100644
--- a/public/css/ospos_print.css
+++ b/public/css/ospos_print.css
@@ -1,77 +1,77 @@
@media print {
- .no-print, .no-print *
- {
- display: none !important;
- }
+ .no-print, .no-print *
+ {
+ display: none !important;
+ }
- #receipt_wrapper, #table
- {
- /*background-color:#FFFFFF;*/
- font-size:75%;
- }
+ #receipt_wrapper, #table
+ {
+ /*background-color:#FFFFFF;*/
+ font-size:75%;
+ }
- .topbar
- {
- display:none;
- }
+ .topbar
+ {
+ display:none;
+ }
- #menubar, #footer
- {
- display:none;
- }
+ #menubar, #footer
+ {
+ display:none;
+ }
- #sale_return_policy
- {
- width:100%;
- text-align:center;
- }
+ #sale_return_policy
+ {
+ width:100%;
+ text-align:center;
+ }
- /* Hide links in table for printing */
- table.innertable
- {
- display: table;
- }
+ /* Hide links in table for printing */
+ table.innertable
+ {
+ display: table;
+ }
- table.innertable a
- {
- color: #000000;
- text-decoration: none;
- }
+ table.innertable a
+ {
+ color: #000000;
+ text-decoration: none;
+ }
- table.report a.expand
- {
- visibility: hidden;
- }
+ table.report a.expand
+ {
+ visibility: hidden;
+ }
- table.report a
- {
- color: #000000;
- text-decoration: none;
- }
+ table.report a
+ {
+ color: #000000;
+ text-decoration: none;
+ }
- table.innertable thead
- {
- /*display:none;*/
- }
+ table.innertable thead
+ {
+ /*display:none;*/
+ }
- .print_show
- {
- display:block !important;
- }
+ .print_show
+ {
+ display:block !important;
+ }
- .print_hide
- {
- display:none !important;
- }
+ .print_hide
+ {
+ display:none !important;
+ }
- .fixed-table-container
- {
- border: none;
- }
+ .fixed-table-container
+ {
+ border: none;
+ }
- .fixed-table-container thead th .sortable
- {
- padding-right: 10px;
- }
-}
\ No newline at end of file
+ .fixed-table-container thead th .sortable
+ {
+ padding-right: 10px;
+ }
+}
diff --git a/public/css/popupbox.css b/public/css/popupbox.css
index 5716e4392..93d689b81 100644
--- a/public/css/popupbox.css
+++ b/public/css/popupbox.css
@@ -1,85 +1,85 @@
#required_fields_message
{
- width: 100%;
- text-align: center;
- margin-bottom: 3px;
- font-style: italic;
+ width: 100%;
+ text-align: center;
+ margin-bottom: 3px;
+ font-style: italic;
}
.error_message_box
{
- margin-bottom: 7px;
- margin-left: 20px;
- color: red;
- font-weight: bold;
+ margin-bottom: 7px;
+ margin-left: 20px;
+ color: red;
+ font-weight: bold;
}
#customer_basic_info, #item_basic_info, #item_number_info, #supplier_basic_info, #sale_basic_info, #employee_basic_info, #employee_login_info, #employee_permission_info
{
- padding: 5px;
+ padding: 5px;
}
#info_provided_by
{
- display: none;
- font-weight: bold;
+ display: none;
+ font-weight: bold;
}
#permission_list
{
- list-style: none;
+ list-style: none;
}
#permission_list li
{
- padding: 5px;
+ padding: 5px;
}
#permission_list ul li
{
- padding-left: 20px;
- padding-bottom: 0px;
- list-style: none;
+ padding-left: 20px;
+ padding-bottom: 0px;
+ list-style: none;
}
#permission_list input
{
- top: 3px;
+ top: 3px;
}
#employee_permission_info p
{
- font-weight: bold;
+ font-weight: bold;
}
#employee_permission_info span.small
{
- font-style: italic;
- font-size: 80%;
+ font-style: italic;
+ font-size: 80%;
}
#item_kit_items, #items_count_details
{
- font-size: 80%;
+ font-size: 80%;
}
#item_kit_items, #items_count_details, #tax_rates
{
- width: 100%;
+ width: 100%;
}
#item_kit_items thead tr, #items_count_details thead tr, #tax_rates thead tr
{
- background-color: #CCC;
+ background-color: #CCC;
}
#item_kit_items th, #items_count_details th, #tax_rates th
{
- text-align: center;
- font-weight: bold;
+ text-align: center;
+ font-weight: bold;
}
#item_kit_items td, #items_count_details td, #tax_rates td
{
- text-align: center;
+ text-align: center;
}
diff --git a/public/css/receipt.css b/public/css/receipt.css
index e20f8e64c..005d9090c 100644
--- a/public/css/receipt.css
+++ b/public/css/receipt.css
@@ -1,76 +1,76 @@
#receipt_wrapper
{
- width:100%;
+ width:100%;
}
#receipt_header
{
- text-align:center;
+ text-align:center;
}
#company_name
{
- font-size:150%;
- font-weight:bold;
+ font-size:150%;
+ font-weight:bold;
}
#company_name img
{
- max-width: 150px;
- max-height: 150px;
+ max-width: 150px;
+ max-height: 150px;
}
#company_phone
{
- margin-bottom:15px;
+ margin-bottom:15px;
}
#sale_time
{
- margin-bottom:5px;
+ margin-bottom:5px;
}
#receipt_items
{
- position:relative;
- border-collapse:collapse;
- margin-top:15px;
- margin-bottom:15px;
- width:100%;
+ position:relative;
+ border-collapse:collapse;
+ margin-top:15px;
+ margin-bottom:15px;
+ width:100%;
}
#receipt_items td
{
- position:relative;
- padding:3px; margin-bottom:5px;
-
+ position:relative;
+ padding:3px; margin-bottom:5px;
+
}
#receipt_items tr
{
- margin-bottom:5px;
+ margin-bottom:5px;
}
#sale_return_policy
{
- width:80%;
- margin:0 auto;
- text-align:center;
+ width:80%;
+ margin:0 auto;
+ text-align:center;
}
#receipt_wrapper #barcode
{
- margin-top:10px;
- text-align:center;
+ margin-top:10px;
+ text-align:center;
}
-.total-value
+.total-value
{
- text-align: right;
+ text-align: right;
}
.discount
{
- font-weight: bold;
+ font-weight: bold;
}
diff --git a/public/css/register.css b/public/css/register.css
index b5f232c70..2db565f4e 100644
--- a/public/css/register.css
+++ b/public/css/register.css
@@ -1,31 +1,31 @@
#register_wrapper
{
- float: left;
- width: 70%;
- font-size: 13px;
+ float: left;
+ width: 70%;
+ font-size: 13px;
}
#mode_form, #add_item_form
{
- margin: 0;
+ margin: 0;
}
#mode_form .panel-body, #add_item_form .panel-body
{
- padding: 0.7em;
- margin: 0;
+ padding: 0.7em;
+ margin: 0;
}
#mode_form ul, #add_item_form ul
{
- list-style: none;
- padding: 0;
- margin: 0;
+ list-style: none;
+ padding: 0;
+ margin: 0;
}
#mode_form ul li, #add_item_form ul li
{
- margin-left: 1em;
+ margin-left: 1em;
}
.first_li
@@ -35,68 +35,68 @@
#mode_form ul.dropdown-menu.inner, #add_item_form ul.dropdown-menu.inner
{
- margin-left: -1em !important;
+ margin-left: -1em !important;
}
#register
{
- padding: 0;
- border-collapse: collapse;
+ padding: 0;
+ border-collapse: collapse;
}
#register th
-{
- padding: 5px;
- text-align: center;
+{
+ padding: 5px;
+ text-align: center;
}
#register td
{
- padding: 3px;
- text-align: center;
+ padding: 3px;
+ text-align: center;
}
#overall_sale
{
- width: 29%;
- float: left;
- margin-left: 0.1em;
- padding-bottom: 1em;
- padding-top: 1em;
- font-size: 13px;
- text-align: center;
+ width: 29%;
+ float: left;
+ margin-left: 0.1em;
+ padding-bottom: 1em;
+ padding-top: 1em;
+ font-size: 13px;
+ text-align: center;
}
#overall_sale .panel-body
{
- padding-top: 0;
- padding-bottom: 0;
+ padding-top: 0;
+ padding-bottom: 0;
}
#overall_sale .form-group
{
- margin: 0;
+ margin: 0;
}
#overall_sale .btn
{
- margin-top: 0.5em;
- margin-bottom: 0.5em;
+ margin-top: 0.5em;
+ margin-bottom: 0.5em;
}
#payment_details, #buttons_sale, #suspended_sales_table
{
- width: 100%;
+ width: 100%;
}
.sales_table_100
{
- width: 100%;
+ width: 100%;
}
#sale_totals, #payment_totals
{
- border-top: 1px solid #000;
+ border-top: 1px solid #000;
}
input#amount_tendered:disabled
@@ -106,15 +106,15 @@ input#amount_tendered:disabled
#payment_details
{
- float: left;
- border-top: 1px solid #000;
- margin-top: 0.2em;
- padding: 0.5em;
- text-align: left;
- clear: both;
+ float: left;
+ border-top: 1px solid #000;
+ margin-top: 0.2em;
+ padding: 0.5em;
+ text-align: left;
+ clear: both;
}
.alert
{
- margin-bottom: 5px;
+ margin-bottom: 5px;
}
diff --git a/public/css/reports.css b/public/css/reports.css
index e2b6802db..1233cbeb7 100644
--- a/public/css/reports.css
+++ b/public/css/reports.css
@@ -1,12 +1,12 @@
-.report
+.report
{
- font-size: .85em;
+ font-size: .85em;
}
#report_summary
{
- margin: 2em 0 auto;
- text-align: center;
+ margin: 2em 0 auto;
+ text-align: center;
}
#report_summary .summary_row
@@ -15,8 +15,8 @@
#chart_report_summary
{
- text-align: center;
- margin-top: -100px;
+ text-align: center;
+ margin-top: -100px;
}
#chart_report_summary .summary_row
@@ -30,32 +30,32 @@
/* style chart X axis labels to be rotated of 60 degrees */
.ct-label.ct-horizontal
{
- -webkit-transform: rotate(-60deg);
- -moz-transform: rotate(-60deg);
- -ms-transform: rotate(-60deg);
- -o-transform: rotate(-60deg);
- filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
+ -webkit-transform: rotate(-60deg);
+ -moz-transform: rotate(-60deg);
+ -ms-transform: rotate(-60deg);
+ -o-transform: rotate(-60deg);
+ filter: progid:DXImageTransform.Microsoft.BasicImage(rotation=3);
}
/* set all labels to be black with font size 1.2rem */
.ct-label
{
- fill: rgba(0,0,0,1);
- color: rgba(0,0,0,1);
- font-size: 1.2rem;
+ fill: rgba(0,0,0,1);
+ color: rgba(0,0,0,1);
+ font-size: 1.2rem;
}
.ct-tooltip-point
{
- fill-opacity: 1!important;
- stroke-width: 0px;
- stroke: red;
- transition: all 0.2s linear;
+ fill-opacity: 1!important;
+ stroke-width: 0px;
+ stroke: red;
+ transition: all 0.2s linear;
}
.ct-tooltip-point:hover
{
- r: 7;
- stroke-opacity: 0.2;
- stroke-width: 20px;
-}
\ No newline at end of file
+ r: 7;
+ stroke-opacity: 0.2;
+ stroke-width: 20px;
+}
diff --git a/public/js/imgpreview.full.jquery.js b/public/js/imgpreview.full.jquery.js
index eb5fdec1c..bab8af37b 100644
--- a/public/js/imgpreview.full.jquery.js
+++ b/public/js/imgpreview.full.jquery.js
@@ -8,18 +8,18 @@
* @version 0.22
*/
(function($){
-
+
$.expr[':'].linkingToImage = function(elem, index, match){
// This will return true if the specified attribute contains a valid link to an image:
return !! ($(elem).attr(match[3]) && $(elem).attr(match[3]).match(/\.(gif|jpe?g|png|bmp)$/i));
};
-
+
$.fn.imgPreview = function(userDefinedSettings){
-
+
var s = $.extend({
-
+
/* DEFAULTS */
-
+
// CSS to be applied to image:
imgCSS: {},
// Distance between cursor and preview:
@@ -40,24 +40,24 @@
thumbPrefix: '',
// Where to retrieve the image from:
srcAttr: 'href'
-
+
}, userDefinedSettings),
-
+
$container = $('').attr('id', s.containerID)
.append('
').hide()
.css('position','absolute')
.appendTo('body'),
-
+
$img = $('img', $container).css(s.imgCSS),
-
+
// Get all valid elements (linking to images / ATTR with image link):
$collection = this.filter(':linkingToImage(' + s.srcAttr + ')');
-
+
// Re-usable means to add prefix (from setting):
function addPrefix(src) {
return src && src.replace(/(\/?)([^\/]+)$/,'$1' + s.thumbPrefix + '$2');
}
-
+
if (s.preloadImages) {
(function(i){
var tempIMG = new Image(),
@@ -65,25 +65,25 @@
var src = $($collection[i]).attr(s.srcAttr)
if (src)
{
- tempIMG.src = addPrefix(src);
+ tempIMG.src = addPrefix(src);
tempIMG.onload = function(){
$collection[i + 1] && callee(i + 1);
};
}
})(0);
}
-
+
$collection
.mousemove(function(e){
-
+
$container.css({
top: e.pageY + s.distanceFromCursor.top + 'px',
left: e.pageX + s.distanceFromCursor.left + 'px'
});
-
+
})
.hover(function(){
-
+
var link = this;
$container
.addClass(s.containerLoadingClass)
@@ -96,18 +96,18 @@
})
.attr( 'src' , addPrefix($(link).attr(s.srcAttr)) );
s.onShow.call($container[0], link);
-
+
}, function(){
-
+
$container.hide();
$img.unbind('load').attr('src','').hide();
s.onHide.call($container[0], this);
-
+
});
-
+
// Return full selection, not $collection!
return this;
-
+
};
-
-})(jQuery);
\ No newline at end of file
+
+})(jQuery);
diff --git a/public/js/manage_tables.js b/public/js/manage_tables.js
index 746e49916..5a0431f29 100644
--- a/public/js/manage_tables.js
+++ b/public/js/manage_tables.js
@@ -1,375 +1,375 @@
(function(dialog_support, $) {
- var btn_id, dialog_ref;
+ var btn_id, dialog_ref;
- var hide = function() {
- dialog_ref && dialog_ref.close();
- };
+ var hide = function() {
+ dialog_ref && dialog_ref.close();
+ };
- var clicked_id = function() {
- return btn_id;
- };
+ var clicked_id = function() {
+ return btn_id;
+ };
- var submit = function(button_id) {
- return function(dlog_ref) {
- const form = $('form', dlog_ref.$modalBody).first();
- const validator = form.data('validator');
- const submitted = validator && validator.formSubmitted;
+ var submit = function(button_id) {
+ return function(dlog_ref) {
+ const form = $('form', dlog_ref.$modalBody).first();
+ const validator = form.data('validator');
+ const submitted = validator && validator.formSubmitted;
- btn_id = button_id;
- dialog_ref = dlog_ref;
+ btn_id = button_id;
+ dialog_ref = dlog_ref;
- if (button_id == 'submit' && (!submitted && btn_id != "btnNew")) {
- form.submit();
- validator.valid() && $('#submit').prop('disabled', true).css('opacity', 0.5);
- }
- return false;
- }
- };
+ if (button_id == 'submit' && (!submitted && btn_id != "btnNew")) {
+ form.submit();
+ validator.valid() && $('#submit').prop('disabled', true).css('opacity', 0.5);
+ }
+ return false;
+ }
+ };
- var button_class = {
- 'submit' : 'btn-primary',
- 'delete' : 'btn-danger'
- };
+ var button_class = {
+ 'submit' : 'btn-primary',
+ 'delete' : 'btn-danger'
+ };
- var init = function(selector) {
+ var init = function(selector) {
- var buttons = function(event) {
- var buttons = [];
- var dialog_class = 'modal-dlg';
- $.each($(this).attr('class').split(/\s+/), function(classIndex, className) {
- var width_class = className.split("modal-dlg-");
- if (width_class && width_class.length > 1) {
- dialog_class = className;
- }
- });
+ var buttons = function(event) {
+ var buttons = [];
+ var dialog_class = 'modal-dlg';
+ $.each($(this).attr('class').split(/\s+/), function(classIndex, className) {
+ var width_class = className.split("modal-dlg-");
+ if (width_class && width_class.length > 1) {
+ dialog_class = className;
+ }
+ });
- var has_new_btn = "btnNew" in $(this).data();
- $.each($(this).data(), function(name, value) {
- var btn_class = name.split("btn");
- if (btn_class && btn_class.length > 1) {
- var btn_name = btn_class[1].toLowerCase();
- var is_submit = btn_name == 'submit';
- var is_new = btn_name === 'new';
- var is_enter = has_new_btn ? is_new: is_submit;
- buttons.push({
- id: btn_name,
- label: value,
- cssClass: button_class[btn_name],
- hotkey: is_enter ? 13 : undefined, // Enter.
- action: submit(btn_name)
- });
- }
- });
+ var has_new_btn = "btnNew" in $(this).data();
+ $.each($(this).data(), function(name, value) {
+ var btn_class = name.split("btn");
+ if (btn_class && btn_class.length > 1) {
+ var btn_name = btn_class[1].toLowerCase();
+ var is_submit = btn_name == 'submit';
+ var is_new = btn_name === 'new';
+ var is_enter = has_new_btn ? is_new: is_submit;
+ buttons.push({
+ id: btn_name,
+ label: value,
+ cssClass: button_class[btn_name],
+ hotkey: is_enter ? 13 : undefined, // Enter.
+ action: submit(btn_name)
+ });
+ }
+ });
- !buttons.length && buttons.push({
- id: 'close',
- label: lang.line('common_close'),
- cssClass: 'btn-primary',
- action: function(dialog_ref) {
- dialog_ref.close();
- }
- });
- return { buttons: buttons.sort(function(a, b) {
- return ($(b).text()) < ($(a).text()) ? -1 : 1;
- }), cssClass: dialog_class};
- };
+ !buttons.length && buttons.push({
+ id: 'close',
+ label: lang.line('common_close'),
+ cssClass: 'btn-primary',
+ action: function(dialog_ref) {
+ dialog_ref.close();
+ }
+ });
+ return { buttons: buttons.sort(function(a, b) {
+ return ($(b).text()) < ($(a).text()) ? -1 : 1;
+ }), cssClass: dialog_class};
+ };
- $(selector).each(function(index, $element) {
+ $(selector).each(function(index, $element) {
- return $(selector).off('click').on('click', function(event) {
- var $link = $(event.target);
- $link = !$link.is("a, button") ? $link.parents("a, button") : $link ;
- BootstrapDialog.show($.extend({
- title: $link.attr('title'),
- message: (function() {
- var node = $('');
- $.get($link.attr('href') || $link.data('href'), function(data) {
- node.html(data);
- });
- return node;
- })
- }, buttons.call(this, event)));
+ return $(selector).off('click').on('click', function(event) {
+ var $link = $(event.target);
+ $link = !$link.is("a, button") ? $link.parents("a, button") : $link ;
+ BootstrapDialog.show($.extend({
+ title: $link.attr('title'),
+ message: (function() {
+ var node = $('');
+ $.get($link.attr('href') || $link.data('href'), function(data) {
+ node.html(data);
+ });
+ return node;
+ })
+ }, buttons.call(this, event)));
- return false;
- });
- });
- };
+ return false;
+ });
+ });
+ };
- $.extend(dialog_support, {
- init: init,
- submit: submit,
- hide: hide,
- clicked_id: clicked_id
- });
+ $.extend(dialog_support, {
+ init: init,
+ submit: submit,
+ hide: hide,
+ clicked_id: clicked_id
+ });
})(window.dialog_support = window.dialog_support || {}, jQuery);
(function(table_support, $) {
- var enable_actions = function(callback) {
- return function() {
- var selection_empty = selected_rows().length == 0;
- $("#toolbar button:not(.dropdown-toggle)").attr('disabled', selection_empty);
- typeof callback == 'function' && callback();
- }
- };
-
- var table = function() {
- return $("#table").data('bootstrap.table');
- }
-
- var selected_ids = function () {
- return $.map(table().getSelections(), function (element) {
- return element[options.uniqueId || 'id'] !== '-' ? element[options.uniqueId || 'id'] : null;
- });
- };
-
- var selected_rows = function () {
- return $("#table td input:checkbox:checked").parents("tr");
- };
-
- var row_selector = function(id) {
- return "tr[data-uniqueid='" + id + "']";
- };
-
- var rows_selector = function(ids) {
- var selectors = [];
- ids = ids instanceof Array ? ids : ("" + ids).split(":");
- $.each(ids, function(index, element) {
- selectors.push(row_selector(element));
- });
- return selectors;;
- };
-
- var highlight_row = function (id, color) {
- $(rows_selector(id)).each(function(index, element) {
- var original = $(element).css('backgroundColor');
- $(element).find("td").animate({backgroundColor: color || '#e1ffdd'}, "slow", "linear")
- .animate({backgroundColor: color || '#e1ffdd'}, 5000)
- .animate({backgroundColor: original}, "slow", "linear");
- });
- };
-
- var do_action = function(action) {
- return function (url, ids) {
- if (confirm($.fn.bootstrapTable.defaults.formatConfirmAction(action))) {
- $.post((url || options.resource) + '/' + action, {'ids[]': ids || selected_ids()}, function (response) {
- //delete was successful, remove checkbox rows
- if (response.success) {
- var selector = ids ? row_selector(ids) : selected_rows();
- table().collapseAllRows();
- $(selector).each(function (index, element) {
- $(this).find("td").animate({backgroundColor: "green"}, 1200, "linear")
- .end().animate({opacity: 0}, 1200, "linear", function () {
- table().remove({
- field: options.uniqueId,
- values: selected_ids()
- });
- if (index == $(selector).length - 1) {
- refresh();
- enable_actions();
- }
- });
- });
- $.notify(response.message, {type: 'success'});
- } else {
- $.notify(response.message, {type: 'danger'});
- }
- }, "json");
- } else {
- return false;
- }
- };
+ var enable_actions = function(callback) {
+ return function() {
+ var selection_empty = selected_rows().length == 0;
+ $("#toolbar button:not(.dropdown-toggle)").attr('disabled', selection_empty);
+ typeof callback == 'function' && callback();
+ }
};
- var load_success = function(callback) {
- return function(response) {
- typeof options.load_callback == 'function' && options.load_callback();
- options.load_callback = undefined;
- dialog_support.init("a.modal-dlg");
- typeof callback == 'function' && callback.call(this, response);
- }
- };
+ var table = function() {
+ return $("#table").data('bootstrap.table');
+ }
- var options;
+ var selected_ids = function () {
+ return $.map(table().getSelections(), function (element) {
+ return element[options.uniqueId || 'id'] !== '-' ? element[options.uniqueId || 'id'] : null;
+ });
+ };
- var toggle_column_visibility = function() {
- if (localStorage[options.employee_id]) {
- var user_settings = JSON.parse(localStorage[options.employee_id]);
- user_settings[options.resource] && $.each(user_settings[options.resource], function(index, element) {
- element ? table().showColumn(index) : table().hideColumn(index);
- });
- }
- };
+ var selected_rows = function () {
+ return $("#table td input:checkbox:checked").parents("tr");
+ };
- var init = function (_options) {
- options = _options;
- enable_actions = enable_actions(options.enableActions);
- load_success = load_success(options.onLoadSuccess);
- const export_suffix = new Date().toISOString().slice(0, 16).replace(/(-|\s*|T|:)*/g,"");
- $('#table')
- .addClass("table-striped")
- .addClass("table-bordered")
- .bootstrapTable($.extend(options, {
- columns: options.headers,
- stickyHeader: true,
- url: options.resource + '/search',
- sidePagination: 'server',
- selectItemName: 'btSelectItem',
- pageSize: options.pageSize,
- pagination: true,
- search: options.resource || false,
- showColumns: true,
- clickToSelect: true,
- showExport: true,
- exportDataType: 'basic',
- exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel', 'pdf'],
- exportOptions: {
- fileName: options.resource.replace(/.*\/(.*?)$/g, '$1') + "_" + export_suffix
- },
- onPageChange: function(response) {
- load_success(response);
- enable_actions();
- },
- toolbar: '#toolbar',
- uniqueId: options.uniqueId || 'id',
- trimOnSearch: false,
- onCheck: enable_actions,
- onUncheck: enable_actions,
- onCheckAll: enable_actions,
- onUncheckAll: enable_actions,
- onLoadSuccess: function(response) {
- load_success(response);
- enable_actions();
- },
- onColumnSwitch : function(field, checked) {
- var user_settings = localStorage[options.employee_id];
- user_settings = (user_settings && JSON.parse(user_settings)) || {};
- user_settings[options.resource] = user_settings[options.resource] || {};
- user_settings[options.resource][field] = checked;
- localStorage[options.employee_id] = JSON.stringify(user_settings);
- dialog_support.init("a.modal-dlg");
- },
- queryParamsType: 'limit',
- iconSize: 'sm',
- silentSort: true,
- paginationVAlign: 'bottom',
- escape: true
- }));
- enable_actions();
- init_delete();
- init_restore();
- toggle_column_visibility();
- dialog_support.init("button.modal-dlg");
- };
+ var row_selector = function(id) {
+ return "tr[data-uniqueid='" + id + "']";
+ };
- var init_delete = function (confirmMessage) {
- $("#delete").click(function(event) {
- do_action("delete")();
- });
- };
+ var rows_selector = function(ids) {
+ var selectors = [];
+ ids = ids instanceof Array ? ids : ("" + ids).split(":");
+ $.each(ids, function(index, element) {
+ selectors.push(row_selector(element));
+ });
+ return selectors;;
+ };
- var init_restore = function (confirmMessage) {
- $("#restore").click(function(event) {
- do_action("restore")();
- });
- };
+ var highlight_row = function (id, color) {
+ $(rows_selector(id)).each(function(index, element) {
+ var original = $(element).css('backgroundColor');
+ $(element).find("td").animate({backgroundColor: color || '#e1ffdd'}, "slow", "linear")
+ .animate({backgroundColor: color || '#e1ffdd'}, 5000)
+ .animate({backgroundColor: original}, "slow", "linear");
+ });
+ };
- var refresh = function() {
- table().refresh();
- }
+ var do_action = function(action) {
+ return function (url, ids) {
+ if (confirm($.fn.bootstrapTable.defaults.formatConfirmAction(action))) {
+ $.post((url || options.resource) + '/' + action, {'ids[]': ids || selected_ids()}, function (response) {
+ //delete was successful, remove checkbox rows
+ if (response.success) {
+ var selector = ids ? row_selector(ids) : selected_rows();
+ table().collapseAllRows();
+ $(selector).each(function (index, element) {
+ $(this).find("td").animate({backgroundColor: "green"}, 1200, "linear")
+ .end().animate({opacity: 0}, 1200, "linear", function () {
+ table().remove({
+ field: options.uniqueId,
+ values: selected_ids()
+ });
+ if (index == $(selector).length - 1) {
+ refresh();
+ enable_actions();
+ }
+ });
+ });
+ $.notify(response.message, {type: 'success'});
+ } else {
+ $.notify(response.message, {type: 'danger'});
+ }
+ }, "json");
+ } else {
+ return false;
+ }
+ };
+ };
- var submit_handler = function(url) {
- return function (resource, response) {
- var id = response.id !== undefined ? response.id.toString() : "";
- if (!response.success) {
- $.notify($.text(response.message).html(), { type: 'danger' });
- } else {
- var message = response.message;
- var selector = rows_selector(response.id);
- var rows = $(selector.join(",")).length;
- if (rows > 0 && rows < 15) {
- var ids = id.split(":");
- $.get([url || resource + '/row', id].join("/"), {}, function (response) {
- $.each(selector, function (index, element) {
- var id = $(element).data('uniqueid');
- table().updateByUniqueId({id: id, row: response[id] || response});
- });
- dialog_support.init("a.modal-dlg");
- highlight_row(ids);
- }, 'json');
- } else {
- // call hightlight function once after refresh
- options.load_callback = function () {
- enable_actions();
- highlight_row(id);
- };
- refresh();
- }
- $.notify(message, {type: 'success' });
- }
- return false;
- };
- };
+ var load_success = function(callback) {
+ return function(response) {
+ typeof options.load_callback == 'function' && options.load_callback();
+ options.load_callback = undefined;
+ dialog_support.init("a.modal-dlg");
+ typeof callback == 'function' && callback.call(this, response);
+ }
+ };
- var handle_submit = submit_handler();
+ var options;
- $.extend(table_support, {
- submit_handler: function(url) {
- this.handle_submit = submit_handler(url);
- },
- handle_submit: handle_submit,
- init: init,
- do_delete: do_action("delete"),
- do_restore: do_action("restore"),
- refresh : refresh,
- selected_ids : selected_ids,
- });
+ var toggle_column_visibility = function() {
+ if (localStorage[options.employee_id]) {
+ var user_settings = JSON.parse(localStorage[options.employee_id]);
+ user_settings[options.resource] && $.each(user_settings[options.resource], function(index, element) {
+ element ? table().showColumn(index) : table().hideColumn(index);
+ });
+ }
+ };
+
+ var init = function (_options) {
+ options = _options;
+ enable_actions = enable_actions(options.enableActions);
+ load_success = load_success(options.onLoadSuccess);
+ const export_suffix = new Date().toISOString().slice(0, 16).replace(/(-|\s*|T|:)*/g,"");
+ $('#table')
+ .addClass("table-striped")
+ .addClass("table-bordered")
+ .bootstrapTable($.extend(options, {
+ columns: options.headers,
+ stickyHeader: true,
+ url: options.resource + '/search',
+ sidePagination: 'server',
+ selectItemName: 'btSelectItem',
+ pageSize: options.pageSize,
+ pagination: true,
+ search: options.resource || false,
+ showColumns: true,
+ clickToSelect: true,
+ showExport: true,
+ exportDataType: 'basic',
+ exportTypes: ['json', 'xml', 'csv', 'txt', 'sql', 'excel', 'pdf'],
+ exportOptions: {
+ fileName: options.resource.replace(/.*\/(.*?)$/g, '$1') + "_" + export_suffix
+ },
+ onPageChange: function(response) {
+ load_success(response);
+ enable_actions();
+ },
+ toolbar: '#toolbar',
+ uniqueId: options.uniqueId || 'id',
+ trimOnSearch: false,
+ onCheck: enable_actions,
+ onUncheck: enable_actions,
+ onCheckAll: enable_actions,
+ onUncheckAll: enable_actions,
+ onLoadSuccess: function(response) {
+ load_success(response);
+ enable_actions();
+ },
+ onColumnSwitch : function(field, checked) {
+ var user_settings = localStorage[options.employee_id];
+ user_settings = (user_settings && JSON.parse(user_settings)) || {};
+ user_settings[options.resource] = user_settings[options.resource] || {};
+ user_settings[options.resource][field] = checked;
+ localStorage[options.employee_id] = JSON.stringify(user_settings);
+ dialog_support.init("a.modal-dlg");
+ },
+ queryParamsType: 'limit',
+ iconSize: 'sm',
+ silentSort: true,
+ paginationVAlign: 'bottom',
+ escape: true
+ }));
+ enable_actions();
+ init_delete();
+ init_restore();
+ toggle_column_visibility();
+ dialog_support.init("button.modal-dlg");
+ };
+
+ var init_delete = function (confirmMessage) {
+ $("#delete").click(function(event) {
+ do_action("delete")();
+ });
+ };
+
+ var init_restore = function (confirmMessage) {
+ $("#restore").click(function(event) {
+ do_action("restore")();
+ });
+ };
+
+ var refresh = function() {
+ table().refresh();
+ }
+
+ var submit_handler = function(url) {
+ return function (resource, response) {
+ var id = response.id !== undefined ? response.id.toString() : "";
+ if (!response.success) {
+ $.notify($.text(response.message).html(), { type: 'danger' });
+ } else {
+ var message = response.message;
+ var selector = rows_selector(response.id);
+ var rows = $(selector.join(",")).length;
+ if (rows > 0 && rows < 15) {
+ var ids = id.split(":");
+ $.get([url || resource + '/row', id].join("/"), {}, function (response) {
+ $.each(selector, function (index, element) {
+ var id = $(element).data('uniqueid');
+ table().updateByUniqueId({id: id, row: response[id] || response});
+ });
+ dialog_support.init("a.modal-dlg");
+ highlight_row(ids);
+ }, 'json');
+ } else {
+ // call hightlight function once after refresh
+ options.load_callback = function () {
+ enable_actions();
+ highlight_row(id);
+ };
+ refresh();
+ }
+ $.notify(message, {type: 'success' });
+ }
+ return false;
+ };
+ };
+
+ var handle_submit = submit_handler();
+
+ $.extend(table_support, {
+ submit_handler: function(url) {
+ this.handle_submit = submit_handler(url);
+ },
+ handle_submit: handle_submit,
+ init: init,
+ do_delete: do_action("delete"),
+ do_restore: do_action("restore"),
+ refresh : refresh,
+ selected_ids : selected_ids,
+ });
})(window.table_support = window.table_support || {}, jQuery);
(function(form_support, $) {
- form_support.error = {
- errorClass: "has-error",
- errorLabelContainer: "#error_message_box",
- wrapper: "li",
- highlight: function (e) {
- $(e).closest('.form-group').addClass('has-error');
- },
- unhighlight: function (e) {
- $(e).closest('.form-group').removeClass('has-error');
- }
- };
+ form_support.error = {
+ errorClass: "has-error",
+ errorLabelContainer: "#error_message_box",
+ wrapper: "li",
+ highlight: function (e) {
+ $(e).closest('.form-group').addClass('has-error');
+ },
+ unhighlight: function (e) {
+ $(e).closest('.form-group').removeClass('has-error');
+ }
+ };
- form_support.handler = $.extend({
+ form_support.handler = $.extend({
- submitHandler: function(form) {
- $(form).ajaxSubmit({
- success: function(response)
- {
- $.notify(response.message, { type: response.success ? 'success' : 'danger' });
- },
- dataType: 'json'
- });
- },
+ submitHandler: function(form) {
+ $(form).ajaxSubmit({
+ success: function(response)
+ {
+ $.notify(response.message, { type: response.success ? 'success' : 'danger' });
+ },
+ dataType: 'json'
+ });
+ },
- rules:
- {
+ rules:
+ {
- },
+ },
- messages:
- {
+ messages:
+ {
- }
- }, form_support.error);
+ }
+ }, form_support.error);
})(window.form_support = window.form_support || {}, jQuery);
function number_sorter(a, b) {
- a = +a.replace(/[^\-0-9]+/g, '');
- b = +b.replace(/[^\-0-9]+/g, '');
- return a - b;
+ a = +a.replace(/[^\-0-9]+/g, '');
+ b = +b.replace(/[^\-0-9]+/g, '');
+ return a - b;
}
diff --git a/public/js/nominatim.autocomplete.js b/public/js/nominatim.autocomplete.js
index 347d6e1c6..c1a05e529 100644
--- a/public/js/nominatim.autocomplete.js
+++ b/public/js/nominatim.autocomplete.js
@@ -1,133 +1,133 @@
(function($) {
-
- function http_s(url)
- {
- return document.location.protocol + '//' + url;
- }
-
- var url = http_s('nominatim.openstreetmap.org/search');
- var handle_auto_completion = function(fields) {
- return function(event, ui) {
- var results = ui.item.results;
- if (results != null && results.length > 0) {
- // handle auto completion
- for(var i in fields) {
- $("#" + fields[i]).val(results[i]);
- }
- return false;
- }
- return true;
- };
- };
+ function http_s(url)
+ {
+ return document.location.protocol + '//' + url;
+ }
- var create_parser = function(field_name, parse_format)
- {
- var parse_field = function(format, address)
- {
- var fields = [];
- $.each(format.split("|"), function(key, value)
- {
+ var url = http_s('nominatim.openstreetmap.org/search');
+
+ var handle_auto_completion = function(fields) {
+ return function(event, ui) {
+ var results = ui.item.results;
+ if (results != null && results.length > 0) {
+ // handle auto completion
+ for(var i in fields) {
+ $("#" + fields[i]).val(results[i]);
+ }
+ return false;
+ }
+ return true;
+ };
+ };
+
+ var create_parser = function(field_name, parse_format)
+ {
+ var parse_field = function(format, address)
+ {
+ var fields = [];
+ $.each(format.split("|"), function(key, value)
+ {
if (address[value] && fields.length < 2 && $.inArray(address[value], fields) === -1)
{
- fields.push(address[value]);
+ fields.push(address[value]);
}
- });
- return fields[0] + (fields[1] ? ' (' + fields[1] + ')' : '');
- };
+ });
+ return fields[0] + (fields[1] ? ' (' + fields[1] + ')' : '');
+ };
- return function(data)
- {
+ return function(data)
+ {
var parsed = [];
$.each(data, function(index, value)
{
- var row = [];
- var address = value.address;
+ var row = [];
+ var address = value.address;
$.each(parse_format, function(key, format)
{
row.push(parse_field(format, address));
});
parsed[index] = {
- label: row.join(", "),
- results: row,
- value: address[field_name]
+ label: row.join(", "),
+ results: row,
+ value: address[field_name]
};
});
- return parsed;
- };
- };
+ return parsed;
+ };
+ };
- var init = function(options) {
+ var init = function(options) {
- var default_params = function(id, key, language)
- {
- return function() {
- var result = {
- format: 'json',
- limit: 5,
- addressdetails: 1,
- countrycodes: options.country_codes,
- 'accept-language' : language || navigator.language
- };
- result[key || id] = $("#"+id).val();
- return result;
- }
+ var default_params = function(id, key, language)
+ {
+ return function() {
+ var result = {
+ format: 'json',
+ limit: 5,
+ addressdetails: 1,
+ countrycodes: options.country_codes,
+ 'accept-language' : language || navigator.language
+ };
+ result[key || id] = $("#"+id).val();
+ return result;
+ }
- };
+ };
- var unique = function(parsed) {
- var filtered = [];
- $.each(parsed, function(index, element)
- {
- filtered = $.map(filtered, function(el, ind)
- {
- return el.label == element.label ? null : el;
- });
- filtered.push(element);
+ var unique = function(parsed) {
+ var filtered = [];
+ $.each(parsed, function(index, element)
+ {
+ filtered = $.map(filtered, function(el, ind)
+ {
+ return el.label == element.label ? null : el;
+ });
+ filtered.push(element);
- });
- return filtered;
- };
+ });
+ return filtered;
+ };
- $.each(options.fields, function(key, value)
- {
- var handle_field_completion = handle_auto_completion(value.dependencies);
+ $.each(options.fields, function(key, value)
+ {
+ var handle_field_completion = handle_auto_completion(value.dependencies);
- $("#" + key).autocomplete({
- source: function (request, response) {
- var params = default_params(key, value.response && value.response.field, options.language);
- var request_params = {};
- options.extra_params && $.each(options.extra_params, function(key, param) {
- request_params[key] = typeof param == "function" ? param() : param;
- });
+ $("#" + key).autocomplete({
+ source: function (request, response) {
+ var params = default_params(key, value.response && value.response.field, options.language);
+ var request_params = {};
+ options.extra_params && $.each(options.extra_params, function(key, param) {
+ request_params[key] = typeof param == "function" ? param() : param;
+ });
- $.ajax({
- type: "GET",
- url: url,
- dataType: "json",
- data: $.extend(request_params, params()),
- success: function(data) {
- response(unique($.map(data, function(item) {
- return (create_parser(key, (value.response && value.response.format) || value.dependencies))(data)
- })))
- }
- });
- },
- minChars:3,
- delay:1000,
- appendTo: '.modal-content',
- select: handle_field_completion
- });
+ $.ajax({
+ type: "GET",
+ url: url,
+ dataType: "json",
+ data: $.extend(request_params, params()),
+ success: function(data) {
+ response(unique($.map(data, function(item) {
+ return (create_parser(key, (value.response && value.response.format) || value.dependencies))(data)
+ })))
+ }
+ });
+ },
+ minChars:3,
+ delay:1000,
+ appendTo: '.modal-content',
+ select: handle_field_completion
+ });
+
+ });
+ };
+
+ var nominatim = {
+
+ init : init
+
+ };
+
+ window['nominatim'] = nominatim;
- });
- };
-
- var nominatim = {
-
- init : init
-
- };
-
- window['nominatim'] = nominatim;
-
})(jQuery);
diff --git a/tests/.htaccess b/tests/.htaccess
index 3462048ad..f24db0acc 100644
--- a/tests/.htaccess
+++ b/tests/.htaccess
@@ -1,6 +1,6 @@
- Require all denied
+ Require all denied
- Deny from all
+ Deny from all
diff --git a/tests/sanity_check.js b/tests/sanity_check.js
index a36ea40a7..3661b230e 100644
--- a/tests/sanity_check.js
+++ b/tests/sanity_check.js
@@ -2,10 +2,10 @@ var assert = require("assert"); // node.js core module
var wd = require('wd');
describe('A Mocha test run by grunt-mocha-webdriver', function () {
- it('has a browser injected into it', function () {
- assert.ok(this.browser);
- });
- it('has wd injected into it for customizing', function () {
+ it('has a browser injected into it', function () {
+ assert.ok(this.browser);
+ });
+ it('has wd injected into it for customizing', function () {
assert.notEqual(this.wd, undefined);
});
});
diff --git a/writable/.htaccess b/writable/.htaccess
index 3462048ad..f24db0acc 100644
--- a/writable/.htaccess
+++ b/writable/.htaccess
@@ -1,6 +1,6 @@
- Require all denied
+ Require all denied
- Deny from all
+ Deny from all
diff --git a/writable/cache/index.html b/writable/cache/index.html
index b702fbc39..69df4e1df 100644
--- a/writable/cache/index.html
+++ b/writable/cache/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/writable/index.html b/writable/index.html
index b702fbc39..69df4e1df 100644
--- a/writable/index.html
+++ b/writable/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/writable/logs/index.html b/writable/logs/index.html
index b702fbc39..69df4e1df 100644
--- a/writable/logs/index.html
+++ b/writable/logs/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/writable/session/index.html b/writable/session/index.html
index b702fbc39..69df4e1df 100644
--- a/writable/session/index.html
+++ b/writable/session/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden
diff --git a/writable/uploads/index.html b/writable/uploads/index.html
index b702fbc39..69df4e1df 100644
--- a/writable/uploads/index.html
+++ b/writable/uploads/index.html
@@ -1,7 +1,7 @@
- 403 Forbidden
+ 403 Forbidden