Files
api/services/nginx/app/objects/users_o.php
T
Jepp9350 a92781cceb Add user email and phone support with security routes
Introduced support for user email and phone management, including phone country code and email validation. Added API endpoints for email change and password validation to enhance account security features. Updated Stripe processor logic for better external ID handling.
2025-04-23 10:52:13 +02:00

1048 lines
38 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;
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();
}
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;
// Create the array with the object properties
$array = [
'id' => (int)$this->id,
'customer_number' => (int)$this->customer_number->value(),
'customer_name' => $this->getCustomerName($this->customer_number->value()),
'display_name' => $this->display_name->value(),
'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;
}
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;
}
public function addAttribute(string $attribute, int $user_id = null): void
{
global $db;
if ($user_id === null) {
$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;
}
/**
* 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();
}
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 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);
}
}