Files
api/services/nginx/app/objects/users_o.php
T

1179 lines
43 KiB
PHP

<?php
namespace objects;
use classes\db;
use classes\language_packs;
use classes\object_property;
use classes\response;
use customers\economic_customer_mo;
use customers\economicCustomers;
use Exception;
use languages\language_pack_en_us;
use traits\db_object_t;
class users_o extends db
{
use db_object_t;
public object_property $customer_number;
public object_property $display_name;
public object_property $group_id;
public economic_customer_mo $economic_customer;
public object_property $created_at;
public object_property $updated_at;
public array $permissions;
public array $attributes;
public array $discounts;
public array $orders_not_invoiced;
public array $all_keys;
public customer_codes_o $customer_codes;
public user_key_value_pairs_o $keys;
public user_price_overrides_o $price_overrides;
public language_pack_en_us $language_pack;
protected object_property $password;
protected object_property $phone_country_code;
protected object_property $phone;
protected object_property $email;
protected array $wash_subscription_transactions;
public function structure(): void
{
$this->setTable('users');
}
public function edit(int $id, string $customer_number, string|null $role, string|null $password, string|null $display_name): void
{
global $db;
$this->id = $id;
// Avoid SQL injection
$customer_number = $db->escape_string($customer_number);
if ($password !== null) {
// Hash the password
$password = password_hash($password, PASSWORD_DEFAULT);
$password = $db->escape_string($password);
}
if ($role !== null) {
$role = $db->escape_string($role);
}
if ($display_name !== null) {
$display_name = $db->escape_string($display_name);
}
// Update the record in the database
$sql = "UPDATE $this->table SET customer_number = '$customer_number'";
if ($password !== null) {
$sql .= ", password = '$password'";
}
if ($role !== null) {
$sql .= ", group_id = '$role'";
}
if ($display_name !== null) {
$sql .= ", display_name = '$display_name'";
}
$sql .= " WHERE id = $this->id";
$db->query($sql);
// Set the values of the object properties
$this->getObjectProperties();
}
public function getObjectProperties(): void
{
$this->customer_number = new object_property($this->table, $this->id, 'customer_number', 'string', true);
$this->display_name = new object_property($this->table, $this->id, 'display_name', 'string', false);
$this->password = new object_property($this->table, $this->id, 'password', 'string', true);
$this->group_id = new object_property($this->table, $this->id, 'group_id', 'int', true);
$this->phone_country_code = new object_property($this->table, $this->id, 'phone_country_code', 'int', false);
$this->phone = new object_property($this->table, $this->id, 'phone', 'int', false);
$this->email = new object_property($this->table, $this->id, 'email', 'string', false);
$this->created_at = new object_property($this->table, $this->id, 'created_at', 'string', false);
$this->updated_at = new object_property($this->table, $this->id, 'updated_at', 'string', false);
$this->keys = (new user_key_value_pairs_o())->setUser($this->id);
$this->price_overrides = (new user_price_overrides_o())->setUser($this->id);
$this->renderLanguagePack();
}
/**
* Render the language pack of the user
* @return self
*/
private function renderLanguagePack(): self
{
global /** @var response $response */
$response;
// Check if the user has a key called 'language_pack'
if ($this->keys->getValue('language_pack') !== null) {
// Get the language pack of the user
$language_pack = $this->keys->getValue('language_pack');
$this->language_pack = (new language_packs())->getLanguagePack($language_pack);
} else {
// Get the default language pack
$this->language_pack = (new language_packs())->getDefaultLanguagePack();
//$response->add_debug(['message' => 'No language pack found for user, using default language pack']);
};
//$response->add_meta('language_pack', $this->language_pack);
return $this;
}
public function getLanguagePack(): object
{
// Get the language pack of the user
return new $this->language_pack();
}
public function getCustomerByIdOrCustomerNumber(int $idOrCustomerNumber): users_o
{
global $db;
// Get the record from the database
$sql = "SELECT * FROM $this->table WHERE id = $idOrCustomerNumber OR customer_number = '$idOrCustomerNumber'";
$result = $db->query($sql);
if ($result->num_rows > 0) {
$this->id = $result->fetch_assoc()['id'];
$this->getObjectProperties();
} else {
// Import the customer
$this->importCustomerFromExternalSource($idOrCustomerNumber);
}
return $this;
}
private function importCustomerFromExternalSource(int $customer_number): object|bool
{
global $db;
// Get the customer data from the external source
$economic = new economicCustomers();
$customer_data = $economic->getCustomerId($customer_number);
// DEBUG: Return the customer data
// Check if the customer exists
if ($customer_data) {
// Avoid SQL injection
$customer_number = $db->escape_string($customer_data->customerNumber);
// Double check if the customer exists
$sql = "SELECT * FROM $this->table WHERE customer_number = '$customer_number'";
$result = $db->query($sql);
if ($result->num_rows > 0) {
$this->id = $result->fetch_assoc()['id'];
$this->getObjectProperties();
} else {
// Import the customer
$this->add($customer_number, '', 0);
// Nullify the password
$this->password->nullify();
}
}
// Else return false
return false;
}
public function add(string $customer_number, mixed $password, int $role = 0): void
{
global $db;
// Avoid SQL injection
$customer_number = $db->escape_string($customer_number);
$role = $db->escape_string($role);
// Hash the password
$password = password_hash($password, PASSWORD_DEFAULT);
$password = $db->escape_string($password);
// Create a new record in the database
$sql = "INSERT INTO $this->table (customer_number, password, group_id) VALUES ('$customer_number', '$password', $role)";
$db->query($sql);
// Get the id of the new record
$this->id = $db->insert_id();
// Set the values of the object properties
$this->getObjectProperties();
// Set the default attributes
$this->addAttribute('invoiceAllOrdersIndividually');
$this->addAttribute('restrictTankCleaning');
}
/**
* Add an attribute to the user
* @param string $attribute The attribute to add
* @param int|null $user_id The user id to add the attribute to
* @throws Exception If the user is not selected, and the user_id is null
*/
public function addAttribute(string $attribute, int $user_id = null): void
{
global $db;
if ($user_id === null) {
self::requireSelected();
$user_id = $this->id;
}
$attribute = $db->escape_string($attribute);
// To prevent two attributes with the same name for the same user, we will delete the old one if it exists
$this->deleteAttribute($attribute, $user_id);
$sql = "INSERT INTO customer_attributes (user_id, attribute) VALUES ($user_id, '$attribute')";
$db->query($sql);
}
public function deleteAttribute(string $attribute, int $user_id = null): void
{
global $db;
if ($user_id === null) {
$user_id = $this->id;
}
$attribute = $db->escape_string($attribute);
// Make sure the attribute exists
if (!$this->doesUserHaveAttribute((string)$attribute, (int)$user_id)) {
return;
}
// If the attribute exists, delete it, if it does not exist, nothing will happen
$sql = "DELETE FROM customer_attributes WHERE user_id = $user_id AND attribute = '$attribute' LIMIT 1";
$db->query($sql);
}
public function doesUserHaveAttribute(string $attribute, int $user_id = null): bool
{
global $db;
if ($user_id === null) {
$user_id = $this->id;
}
$attribute = $db->escape_string($attribute);
$sql = "SELECT * FROM customer_attributes WHERE user_id = $user_id AND attribute = '$attribute' LIMIT 1";
$result = $db->query($sql);
if ($result->num_rows > 0) {
return true;
}
return false;
}
public function automaticGetTargetUserFromRequest(): users_o
{
// Get the data from the request
if ($_SERVER['REQUEST_METHOD'] === 'GET' || $_SERVER['REQUEST_METHOD'] === 'DELETE') {
$data = $_GET;
} else {
$data = json_decode(file_get_contents('php://input'), true);
}
// Check if the user id is set in the request
if (isset($data['user_id'])) {
return $this->getUserById((int)$data['user_id']);
} elseif (isset($data['customer_number'])) {
return $this->getUserByCustomerNumber($data['customer_number']);
} else {
return $this;
}
}
public function getUserById(int $id): users_o
{
global $db;
// Get the record from the database
$sql = "SELECT * FROM $this->table WHERE id = $id";
$result = $db->query($sql);
if ($result->num_rows > 0) {
$this->id = $id;
$this->getObjectProperties();
}
return $this;
}
public function getUserByCustomerNumber(int $customer_number): users_o
{
global $db;
// Get the record from the database
$sql = "SELECT * FROM $this->table WHERE customer_number = '$customer_number'";
$result = $db->query($sql);
if ($result->num_rows > 0) {
$this->id = $result->fetch_assoc()['id'];
$this->getObjectProperties();
} else {
// Import the customer
$this->importCustomerFromExternalSource($customer_number);
}
return $this;
}
public function asArray(): array
{
$phone_country_code = $this->phone_country_code->value();
$phone_country_code = $phone_country_code === null ? null : (int)$phone_country_code;
$phone = $this->phone->value();
$phone = $phone === null ? null : (int)$phone;
$display_name = $this->display_name->value();
$customer_number = (int)$this->customer_number->value();
$customer_name = $this->getCustomerName($customer_number);
// Create the array with the object properties
$array = [
'id' => (int)$this->id,
'customer_number' => $customer_number,
'customer_name' => $customer_name,
'display_name' => $display_name === 'Unnamed' ? $customer_name : $display_name,
'group_id' => (int)$this->group_id->value(),
'phone' => [
'country_code' => $phone_country_code,
'number' => $phone,
],
'email' => $this->email->value(),
'created_at' => $this->created_at->value(),
'updated_at' => $this->updated_at->value(),
];
// If the economic customer data is set, add it to the array
if (isset($this->economic_customer)) {
$array['economic_customer'] = $this->economic_customer->asArray();
}
// If the permissions are set, add them to the array
if (isset($this->permissions)) {
$array['permissions'] = $this->permissions;
}
// If the attributes are set, add them to the array
if (isset($this->attributes)) {
$array['attributes'] = $this->attributes;
}
// If the discounts are set, add them to the array
if (isset($this->discounts)) {
$array['discounts'] = $this->discounts;
}
// If the orders not invoiced are set, add them to the array
if (isset($this->orders_not_invoiced)) {
$array['orders_not_invoiced'] = $this->orders_not_invoiced;
}
// If the keys are set, add them to the array
if (isset($this->all_keys)) {
$array['keys'] = $this->all_keys;
}
// If the wash subscription transactions are set, add them to the array
if (isset($this->wash_subscription_transactions)) {
$array['wash_subscription_transactions'] = $this->wash_subscription_transactions;
}
return $array;
}
public function getCustomerName(int $customer_number): string|null
{
// Get the customer from the customer object
if ($customer_number === 0) {
return null;
}
// Create a temporary user object
$tmp_user = new users_o();
$tmp_user->getUserByCustomerNumber($customer_number);
// Get the customer name (Check cache first)
$cached = $tmp_user->getCached('economic_customer');
if (!$cached) {
$tmp_user->getCustomerEcocomicData($customer_number);
$cached = $tmp_user->getCached('economic_customer');
}
if ($cached) {
return $cached->name;
}
return null;
}
public function getCustomerEcocomicData(int $customer_number = null): users_o
{
// Get the customer data from the external source
$economic = new economicCustomers();
// Check if the customer number is set
if (!isset($this->customer_number) && $customer_number === null) {
return $this;
}
$customer_number = $customer_number ?? $this->customer_number->value();
$this->economic_customer = (new economic_customer_mo())->getCustomerByCustomerNumber($customer_number);
return $this;
}
public function getNotes(): array
{
global $db;
// Create the customer notes object
$customer_notes = new customer_notes_o();
// Get the customer notes
return $customer_notes->getCustomerNotesAsArray($this->id);
}
public function addNote($customer_id, $note, $cashier_id): void
{
global $db;
// Create the customer notes object
$customer_notes = new customer_notes_o();
// Add the note
$customer_notes->add($customer_id, $note, $cashier_id);
}
public function deleteNote(int $note_id): void
{
global $db;
// Create the customer notes object
$customer_notes = new customer_notes_o();
// Delete the note
$customer_notes->delete($note_id);
}
public function getOrImportCustomerByCustomerNumber(int $customer_number): object|bool
{
global $db;
// Check if the customer exists
$sql = "SELECT * FROM $this->table WHERE customer_number = $customer_number";
$result = $db->query($sql);
if ($result->num_rows > 0) {
$this->id = $result->fetch_assoc()['id'];
$this->getObjectProperties();
} else {
// Import the customer
return $this->importCustomerFromExternalSource($customer_number);
}
return $this;
}
/**
* If the customer requires a reference number for each order
* @return bool
*/
public function requiresReference(): bool
{
return $this->doesUserHaveAttribute('requiresReferenceNumber');
}
/**
* If the customer is NOT allowed to purchase spot free washes
* @return bool
*/
public function restrictSpotFree(): bool
{
return $this->doesUserHaveAttribute('restrictSpotFree');
}
/**
* If the customer is NOT allowed to purchase interior cleaning
* @return bool
*/
public function restrictInteriorCleaning(): bool
{
return $this->doesUserHaveAttribute('restrictInteriorCleaning');
}
/**
* If the customer is NOT allowed to purchase tank cleaning
* @return bool
*/
public function restrictTankCleaning(): bool
{
return $this->doesUserHaveAttribute('restrictTankCleaning');
}
public function includeIncludes(array $includes = []): users_o
{
global /** @var response $response */
$response;
$includeEverything = $response->getRequestParameter('include_all') === 'true' || in_array('all', $includes);
/**
* economicCustomer
*/
if ($includeEverything || $response->getRequestParameter('includeEconomicCustomer') === 'true' || in_array('economicCustomer', $includes)) {
$this->getCustomerEcocomicData();
}
/**
* permissions
*/
if ($includeEverything || $response->getRequestParameter('includePermissions') === 'true' || in_array('permissions', $includes)) {
$this->getPermissions();
}
/**
* Attributes
*/
if ($includeEverything || $response->getRequestParameter('includeAttributes') === 'true' || in_array('attributes', $includes)) {
$this->getUserAttributes();
}
/**
* Discounts
*/
if ($includeEverything || $response->getRequestParameter('includeDiscounts') === 'true' || in_array('discounts', $includes)) {
$this->getAllDiscounts();
}
/**
* OrdersNotInvoiced
*/
if ($includeEverything || $response->getRequestParameter('includeOrdersNotInvoiced') === 'true' || in_array('ordersNotInvoiced', $includes)) {
$this->getUserOrdersNotInvoiced();
}
/**
* Key value pairs
*/
if ($includeEverything || $response->getRequestParameter('includeKeys') === 'true' || in_array('keys', $includes)) {
$this->getAllKeys();
}
/**
* Wash subscription transactions
*/
if ($includeEverything || $response->getRequestParameter('includeWashSubscriptionTransactions') === 'true' || in_array('washSubscriptionTransactions', $includes)) {
$this->getWashSubscriptionTransactions();
}
return $this;
}
private function getPermissions(): void
{
global $db;
$sql = "SELECT permission FROM groups_permissions WHERE group_id = " . $this->group_id->value();
$result = $db->query($sql);
$perms = [];
while ($row = $result->fetch_assoc()) {
$perms[] = $row['permission'];
}
$this->permissions = $perms;
}
public function getUserAttributes(int $user_id = null): array
{
global $db;
if ($user_id === null) {
$user_id = $this->id;
}
$sql = "SELECT * FROM customer_attributes WHERE user_id = $user_id";
$result = $db->query($sql);
$array = $db->fetch_all($result);
$this->attributes = $array;
return $this->attributes;
}
/**
* Get all discounts for the user (Include)
* @return void
*/
public function getAllDiscounts(): void
{
// Get all discounts (key = 'custom_price')
$this->discounts = $this->price_overrides->setUser($this->id)->getAllPrices();
}
public function getUserOrdersNotInvoiced(): void
{
global $db;
// $sql = "SELECT * FROM $this->table WHERE deleted_at IS NULL AND id NOT IN (SELECT id FROM economic_module_orders WHERE invoice_draft_id IS NOT NULL OR invoice_id IS NOT NULL)";
$sql = "SELECT id FROM orders WHERE customer_id = " . $this->customer_number->value() . " AND deleted_at IS NULL AND id NOT IN (SELECT id FROM economic_module_orders WHERE invoice_draft_id IS NOT NULL OR invoice_id IS NOT NULL)";
$result = $db->query($sql);
$this->orders_not_invoiced = $db->fetch_all($result);
}
public function getAllKeys(): void
{
// Get all keys (key = 'key_value_pair')
$this->all_keys = $this->keys->setUser($this->id)->getAllKeys();
}
/**
* Get the wash subscription transactions for the user
* @throws Exception If the user is not selected
*/
private function getWashSubscriptionTransactions(): void
{
self::requireSelected();
$orders_o = new orders_o();
$wash_subscription_transactions = $orders_o->getWashSubscriptionTransactions((int)$this->customer_number->value());
$this->wash_subscription_transactions = $wash_subscription_transactions;
}
/**
* Get the group of the user
* @throws Exception If the user is not selected
*/
public function getGroup(): groups_o
{
self::requireSelected();
// Get the group of the user
$group = new groups_o();
$group->select($this->group_id->value());
return $group;
}
public function getCode(): string|null
{
// Get the customer code
$this->customer_codes = new customer_codes_o();
$this->customer_codes->getCode($this->id);
return $this->customer_codes->code->value();
}
public function setCode(mixed $code): customer_codes_o
{
// Set the customer code
$this->customer_codes = new customer_codes_o();
return $this->customer_codes->setCode($this->id, $code);
}
/**
* Check if the user has access to the order
* @param int $order_id
* @return bool
*/
public function hasAccessToOrder(int $order_id): bool
{
global $db;
// Check if the user has access to all orders
if ($this->hasPermission('fetch_all_orders')) {
return true;
}
// Get the record from the database
$sql = "SELECT * FROM orders WHERE id = $order_id AND customer_id = " . $this->customer_number->value();
$result = $db->query($sql);
if ($result->num_rows > 0) {
return true;
}
return false;
}
public function hasPermission(string $permission): bool
{
global $db;
// Get the user's group id
$group_id = $this->group_id->value();
// If the users is an admin, they have all permissions
if ((int)$group_id === 1) {
return true;
}
// Get the record from the database
$sql = "SELECT * FROM groups_permissions WHERE group_id = $group_id AND permission = '$permission'";
$result = $db->query($sql);
if ($result->num_rows > 0) {
return true;
}
return false;
}
public function setOpenInvoiceDraft(int $draftInvoiceNumber): void
{
// Set the open invoice draft (key = 'open_invoice_draft')
$this->keys->setUser($this->id)->setValue('open_invoice_draft', $draftInvoiceNumber);
}
public function deleteOpenInvoiceDraft(): void
{
// Check if the user has an open invoice draft
if ($this->hasOpenInvoiceDraft()) {
// Remove all links to the draft invoice
$order = new economic_module_orders();
$order->unlinkAllOrdersFromDraft($this->getOpenInvoiceDraft());
// Unset the open invoice draft
$this->unsetOpenInvoiceDraft();
}
}
public function hasOpenInvoiceDraft(): bool
{
// Check if the user has an open invoice draft (key = 'open_invoice_draft')
return $this->keys->setUser($this->id)->getValue('open_invoice_draft') !== null;
}
public function getOpenInvoiceDraft(): int|null
{
// Get the open invoice draft (key = 'open_invoice_draft')
return (int)$this->keys->setUser($this->id)->getValue('open_invoice_draft');
}
public function unsetOpenInvoiceDraft(): void
{
// Unset the open invoice draft (key = 'open_invoice_draft')
$this->keys->setUser($this->id)->deleteValue('open_invoice_draft');
}
/**
* Get the custom price (DISCOUNT) for the user
* @param int $object_id The ID of the object
* @param bool $is_category If the object is a category
* @return int|null The discount percentage
*/
public function getCustomPrice(int $object_id, bool $is_category = false): int|null
{
// Get the custom price for the product
$discount = $this->price_overrides->setUser($this->id)->getPrice($is_category, $object_id);
// If the is_category is false, check if there is a custom price for the category that the product belongs to
if ($discount === 0 && !$is_category) {
$product = new products_o();
// Get the product by ID
$product->getProductById($object_id);
// Check if the product allows category inheritance of discounts
if ($product->apply_category_discount->value()) {
// Get the custom price for the category
$discount = $this->price_overrides->setUser($this->id)->getPrice(true, $product->category->value());
}
}
return $discount;
}
/**
* Get all custom prices (DISCOUNT) for the user
* @return array The custom prices
*/
public function getCustomPrices(): array
{
// Get the custom prices (key = 'custom_price')
return $this->price_overrides->setUser($this->id)->getAllPrices();
}
/**
* Get all users in a group
* @param int $group_id
* @return array
*/
public function getUsersInGroup(int $group_id): array
{
global $db;
$sql = "SELECT id FROM $this->table WHERE group_id = $group_id";
$result = $db->query($sql);
// Create an array of user objects
$users = [];
while ($row = $result->fetch_assoc()) {
$user = new users_o();
$user->id = $row['id'];
$user->getObjectProperties();
$users[] = $user;
}
return $users;
}
/**
* Get the employee data, that's public to the customers
* @return array
*/
public function listPublicEmployeeData(): array
{
return [
'id' => (int)$this->id,
'display_name' => $this->display_name->value(),
];
}
public function getUsersWithPermission(string $permission): array
{
global $db;
$sql = "SELECT id FROM $this->table WHERE group_id IN (SELECT group_id FROM groups_permissions WHERE permission = '$permission')";
$result = $db->query($sql);
// Create an array of user objects
$users = [];
while ($row = $result->fetch_assoc()) {
$user = new users_o();
$user->id = $row['id'];
$user->getObjectProperties();
$users[] = $user;
}
return $users;
}
/**
* Does the user have access to the booking?
* @param int $id
* @return bool
*/
public function hasAccessToBooking(int $id): bool
{
global $db;
// Check if the user has access to all bookings
if ($this->hasPermission('list_bookings')) {
return true;
}
// Get the record from the database
$sql = "SELECT * FROM bookings WHERE id = $id AND customer_number = " . $this->customer_number->value();
$result = $db->query($sql);
if ($result->num_rows > 0) {
return true;
}
return false;
}
public function parseUsers(array $listObjectsWithPaginationIfSet, $variables = []): array
{
$tmp = self::parseCustomerNumbers($listObjectsWithPaginationIfSet);
// Check if the user has a password, and change it to a boolean instead of a string
foreach ( $tmp as $key => $value ) {
if ($value['password'] === '' || $value['password'] === null) {
$tmp[$key]['password'] = false;
} else {
$tmp[$key]['password'] = true;
}
}
return $tmp;
}
public function parseCustomerNumbers(array $listObjectsWithPaginationIfSet): array
{
foreach ( $listObjectsWithPaginationIfSet as $key => $value ) {
$listObjectsWithPaginationIfSet[$key]['customer_name'] = $this->getCustomerNameById($value['id']);
}
return $listObjectsWithPaginationIfSet;
}
private function getCustomerNameById(int $id): ?string
{
// Check if the name is cached
$cached_name = $this->getCached('economic_customer', $id);
if (!$cached_name) {
// No cached name, get the name from the external source
// Get the name from the external source
$tmp_user = new users_o();
$tmp_user->getUserById($id);
$tmp_user->getCustomerEcocomicData();
$cached_name = $tmp_user->getCached('economic_customer');
if (!$cached_name) {
// Cache the NULL value
$this->cache('economic_customer', 'NULL_OR_EMPTY', $id);
return null;
}
}
return $cached_name->name ?? null;
}
public function hasPassword(): bool
{
return $this->password->value() !== null;
}
public function getPassword(): string|null
{
return $this->password->value();
}
/**
* Set the password for the user
* @throws Exception If the user is not selected
*/
public function setPassword(string $password = null): void
{
self::requireSelected();
global $db;
// Hash the password
$password = password_hash($password, PASSWORD_DEFAULT);
$password = $db->escape_string($password);
// Update the password in the database
$this->password->set(
$password,
);
// The object has changed, so we need to update the database
self::objectChanged();
}
public function objectChanged(): void
{
// Since the user object is not cached, there is no need to invalidate the cache
}
public function clearAllUsersEconomicCustomerDiscountsFromCache(): void
{
// Get all the cached results matching the pattern 'users_*_economic_customer_discount_percentage'
$cached_results = redis->get_keys('users_*_economic_customer_discount_percentage');
// Loop through the cached results
foreach ( $cached_results as $key ) {
// Clear the cached discount percentage
redis->delete($key);
}
}
public function clearAllUsersEconomicCustomerDetailsFromCache(): void
{
// Get all the cached results matching the pattern 'users_*_economic_customer'
$cached_results = redis->get_keys('users_*_economic_customer');
// Loop through the cached results
foreach ( $cached_results as $key ) {
// Clear the cached economic customer details
redis->delete($key);
}
}
public function getEconomicCustomerDiscountPercentage(): int
{
// Check if the discount percentage is cached
$cached_discount_percentage = redis->get_economic_customer_discount_percentage($this->id);
if ($cached_discount_percentage !== null) {
return $cached_discount_percentage;
}
// Get the discount percentage from the external source
$economic = new economicCustomers();
$discount_percentage = $economic->getCustomerDiscountPercentage($this->customer_number->value());
// Cache the discount percentage
redis->cache_economic_customer_discount_percentage($this->id, $discount_percentage);
return $discount_percentage;
}
/**
* Set a custom price (DISCOUNT) for the user
* @param int $user_id
* @param int $object_id The ID of the object
* @param int $discount_percentage The discount percentage
* @param bool $is_category If the object is a category
* @return void
*/
public function setCustomPrice(int $user_id, int|string $object_id, int $discount_percentage, bool $is_category = false): void
{
$this->id = $user_id;
// Get the user object properties
$this->getObjectProperties();
// Set the custom price (key = 'custom_price')
$this->price_overrides->setUser($this->id)->setPrice($is_category, $object_id, $discount_percentage);
}
public function syncAllUsersEconomicCustomerDetails(): void
{
// Get all users
$users = $this->getFields(['id', 'customer_number']);
// Loop through the users
foreach ( $users as $user ) {
// Check if the customer number is set (Or if it is 0)
if ($user['customer_number'] === 0) {
continue;
}
// Get the customer data from the external source
$this->getCustomerEcocomicData($user['customer_number']);
}
}
public function isImportedFromEconomic($customerNumber): bool
{
// Check if the user is imported from the external source
if (self::countRowsWhere(['customer_number' => $customerNumber]) > 0) {
return true;
}
return false;
}
public function getUserIdFromEconomic($customerNumber): int
{
// Get the user id from the external source
$user = self::getFieldsWhere(['customer_number' => $customerNumber], ['id']);
return $user[0]['id'];
}
/**
* Get the invoice collection ID, where the new order should be added to.
* This is based on the user's settings. (If the user has the attribute 'invoiceAllOrdersIndividually', the new order should be added to a new invoice collection)
* @return int The ID of the order invoice collection the new order should be added to.
* @throws Exception
*/
public function getNewOrderInvoiceCollectionId(): int
{
// Check if the user has the attribute 'invoiceAllOrdersIndividually'
$invoice_collection = new collected_order_invoices_o();
if ($this->invoicePerOrder() || !self::hasOpenInvoiceCollection()) {
// Require the user to have a customer number above 0
if (is_null($this->customer_number->value()) || $this->customer_number->value() === 0) {
throw new Exception('The user does not have a customer number');
}
// The user has the attribute 'invoiceAllOrdersIndividually', create a new invoice collection
$invoice_collection->add((int)$this->customer_number->value());
return $invoice_collection->id;
}
// The user does not have the attribute 'invoiceAllOrdersIndividually', get the ID of the last invoice collection
return self::getOpenInvoiceCollection()->id;
}
/**
* If the customer should have an invoice per order (Otherwise, they will have a monthly invoice for all orders)
* @return bool
*/
public function invoicePerOrder(): bool
{
return $this->doesUserHaveAttribute('invoiceAllOrdersIndividually');
}
/**
* Check if the user has an open invoice collection
* @return bool
*/
public function hasOpenInvoiceCollection(): bool
{
// Check if the user has an open invoice collection
$invoice_collection = new collected_order_invoices_o();
return $invoice_collection->hasOpenInvoiceCollection($this->customer_number->value());
}
/**
* Get the open invoice collection of the user
* @return collected_order_invoices_o
* @throws Exception If the user does not have an open invoice collection
* @throws Exception If the user does not have a customer number
*/
public function getOpenInvoiceCollection(): collected_order_invoices_o
{
// Require the user to have a customer number above 0
if (is_null($this->customer_number->value()) || $this->customer_number->value() === 0) {
throw new Exception('The user does not have a customer number');
}
self::requireSelected();
// Get the open invoice collection of the user
$invoice_collection = new collected_order_invoices_o();
return $invoice_collection->getLatestOpenInvoiceCollection($this->customer_number->value());
}
/**
* Get all customers with the given attributes
* @notation Retrieve all customers with ALL the given attributes
* @param array $attributes The attributes to search for (e.g. ['attribute1', 'attribute2'])
* @return array The e-conomic customer numbers with the given attributes (e.g. [123456, 654321])
*/
public function getCustomerNumbersWithAttributes(array $attributes): array
{
global $db;
// Create an array to store the customer numbers
$user_ids = [];
$customer_numbers = [];
// Loop through the attributes
foreach ( $attributes as $attribute ) {
// Get the customer numbers with the attribute
$sql = "SELECT user_id FROM customer_attributes WHERE attribute = '$attribute'";
$result = $db->query($sql);
// Loop through the results
while ($row = $result->fetch_assoc()) {
// Add the customer number to the array
$user_ids[] = (int)$row['user_id'];
}
}
// Remove duplicates from the array
$user_ids = array_unique($user_ids);
// Get the customer numbers from the user IDs
foreach ( $user_ids as $user_id ) {
// Get the customer number from the user ID
$sql = "SELECT customer_number FROM $this->table WHERE id = $user_id";
$result = $db->query($sql);
// Loop through the results
while ($row = $result->fetch_assoc()) {
// Add the customer number to the array
$customer_numbers[] = (int)$row['customer_number'];
}
}
// Remove duplicates from the array
// Return the customer numbers
return array_unique($customer_numbers);
}
/**
* Check if the password matches the hashed password
* @param string $password_to_check_against The password (plain text) to check against the hashed password
* @return bool True if the password matches, false otherwise
* @throws Exception If the user is not selected
* @throws Exception If the user does not have a password
*/
public function passwordMatches(string $password_to_check_against): bool
{
// Require the user to be selected
self::requireSelected();
// Check if the user has a password
if (empty($this->password->value())) {
throw new Exception('The user does not have a password, unable to check if the password matches');
}
// Check if the password matches
return password_verify(
(string)$password_to_check_against,
(string)$this->password->value()
);
}
/**
* Set the email for the user
* @param string $email The email address to set
* @throws Exception If the user is not selected
* @throws Exception If the email address is invalid
* @throws Exception If the email address is already in use
*/
public function setEmail(string $email): void
{
self::requireSelected();
// Check if the email is valid
if (!filter_var($email, FILTER_VALIDATE_EMAIL)) {
throw new Exception('Invalid email address');
}
// Check if the email is already in use
if (self::countRowsWhere(['email' => $email]) > 0) {
throw new Exception('Email address already in use');
}
// Set the email
$this->email->set($email);
}
public function isCustomerBarred(int $customer_number): bool
{
if ($customer_number === 0) {
return false;
}
// Create a temporary user object
$tmp_user = new users_o();
$tmp_user->getUserByCustomerNumber($customer_number);
// Get the customer name (Check cache first)
$cached = $tmp_user->getCached('economic_customer');
if (!$cached) {
$tmp_user->getCustomerEcocomicData($customer_number);
$cached = $tmp_user->getCached('economic_customer');
}
if ($cached) {
return (isset($cached->barred) && $cached->barred);
}
return false;
}
/**
* @throws Exception
*/
public function doesUserHaveDefaultDepartment(): bool
{
// Check if the user has a default department set
self::requireSelected();
return (new customer_default_department_o())->doesUserHaveDefaultDepartment((int)$this->customer_number->value());
}
/**
* @throws Exception
*/
public function getDefaultDepartment(): int
{
// Get the default department for the user
self::requireSelected();
return (new customer_default_department_o())->getDefaultDepartment((int)$this->customer_number->value());
}
public function getCustomersWithVehicleSubscriptions(): array
{
global $db;
// Get all customers with vehicle subscriptions
$sql = "SELECT DISTINCT customer_id FROM customer_vehicles WHERE wash_subscription = 1";
$result = $db->query($sql);
$customer_numbers = [];
while ($row = $result->fetch_assoc()) {
$customer_numbers[] = (int)$row['customer_id'];
}
return $customer_numbers;
}
public function getCustomersWithFixedPricing(): array
{
global $db;
// Get all customers with fixed pricing
$sql = "SELECT DISTINCT customer_number FROM customer_fixed_pricing";
$result = $db->query($sql);
$customer_numbers = [];
while ($row = $result->fetch_assoc()) {
$customer_numbers[] = (int)$row['customer_number'];
}
return $customer_numbers;
}
public function getCustomersWithTankCleaning(): array
{
global $db;
// Get all customers with tank cleaning
$sql = "SELECT DISTINCT user_id FROM customer_attributes WHERE attribute = 'onlyTankCleaning'";
$result = $db->query($sql);
$customer_numbers = [];
while ($row = $result->fetch_assoc()) {
$customer_numbers[] = (int)$row['user_id'];
}
// Get the customer numbers from the user IDs
$customer_numbers = array_unique($customer_numbers);
// Convert user IDs to customer numbers
return self::getCustomerNumbersFromUserIds($customer_numbers);
}
private static function getCustomerNumbersFromUserIds(array $user_ids): array
{
global $db;
$customer_numbers = (new users_o)->getFieldsWhere(
['id' => $user_ids],
['customer_number']
);
return array_map(function ($user) {
return (int)$user['customer_number'];
}, $customer_numbers);
}
}