mirror of
https://github.com/opensourcepos/opensourcepos.git
synced 2026-05-25 16:54:58 -04:00
Compare commits
1 Commits
WebShells-
...
person_att
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
3fefd34864 |
@@ -246,7 +246,7 @@ class Attributes extends Secure_Controller
|
||||
$data['definition_group'][''] = lang('Common.none_selected_text');
|
||||
$data['definition_info'] = $info;
|
||||
|
||||
$show_all = Attribute::SHOW_IN_ITEMS | Attribute::SHOW_IN_RECEIVINGS | Attribute::SHOW_IN_SALES;
|
||||
$show_all = Attribute::SHOW_IN_ITEMS | Attribute::SHOW_IN_RECEIVINGS | Attribute::SHOW_IN_SALES | Attribute::SHOW_IN_SEARCH | Attribute::SHOW_IN_CUSTOMERS | Attribute::SHOW_IN_EMPLOYEES | Attribute::SHOW_IN_SUPPLIERS;
|
||||
$data['definition_flags'] = $this->get_attributes($show_all);
|
||||
$selected_flags = $info->definition_flags === '' ? $show_all : $info->definition_flags;
|
||||
$data['selected_definition_flags'] = $this->get_attributes($selected_flags);
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Libraries\Mailchimp_lib;
|
||||
|
||||
use App\Models\Attribute;
|
||||
use App\Models\Customer;
|
||||
use App\Models\Customer_rewards;
|
||||
use App\Models\Tax_code;
|
||||
@@ -15,34 +15,31 @@ use stdClass;
|
||||
|
||||
class Customers extends Persons
|
||||
{
|
||||
private string $_list_id;
|
||||
private Mailchimp_lib $mailchimp_lib;
|
||||
private Customer_rewards $customer_rewards;
|
||||
private string $listId;
|
||||
private Mailchimp_lib $mailchimpLib;
|
||||
private Customer_rewards $customerRewards;
|
||||
private Customer $customer;
|
||||
private Tax_code $tax_code;
|
||||
private array $config;
|
||||
private Tax_code $taxCode;
|
||||
private array $appConfig;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('customers');
|
||||
$this->mailchimp_lib = new Mailchimp_lib();
|
||||
$this->customer_rewards = model(Customer_rewards::class);
|
||||
$this->mailchimpLib = new Mailchimp_lib();
|
||||
$this->customerRewards = model(Customer_rewards::class);
|
||||
$this->customer = model(Customer::class);
|
||||
$this->tax_code = model(Tax_code::class);
|
||||
$this->config = config(OSPOS::class)->settings;
|
||||
$this->taxCode = model(Tax_code::class);
|
||||
$this->appConfig = config(OSPOS::class)->settings;
|
||||
|
||||
$encrypter = Services::encrypter();
|
||||
|
||||
if (!empty($this->config['mailchimp_list_id'])) {
|
||||
$this->_list_id = $encrypter->decrypt($this->config['mailchimp_list_id']);
|
||||
if (!empty($this->appConfig['mailchimp_list_id'])) {
|
||||
$this->listId = $encrypter->decrypt($this->appConfig['mailchimp_list_id']);
|
||||
} else {
|
||||
$this->_list_id = '';
|
||||
$this->listId = '';
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex(): string
|
||||
{
|
||||
$data['table_headers'] = get_customer_manage_table_headers();
|
||||
@@ -50,19 +47,13 @@ class Customers extends Persons
|
||||
return view('people/manage', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one row for a customer manage table. This is called using AJAX to update one row.
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getRow(int $row_id): ResponseInterface
|
||||
public function getRow(int $rowId): ResponseInterface
|
||||
{
|
||||
$person = $this->customer->get_info($row_id);
|
||||
$person = $this->customer->get_info($rowId);
|
||||
|
||||
// Retrieve the total amount the customer spent so far together with min, max and average values
|
||||
$stats = $this->customer->get_stats($person->person_id); // TODO: This and the next 11 lines are duplicated in search(). Extract a method.
|
||||
$stats = $this->customer->get_stats($person->person_id);
|
||||
|
||||
if (empty($stats)) {
|
||||
// Create object with empty properties.
|
||||
$stats = new stdClass();
|
||||
$stats->total = 0;
|
||||
$stats->min = 0;
|
||||
@@ -72,17 +63,11 @@ class Customers extends Persons
|
||||
$stats->quantity = 0;
|
||||
}
|
||||
|
||||
$data_row = get_customer_data_row($person, $stats);
|
||||
$dataRow = get_customer_data_row($person, $stats);
|
||||
|
||||
return $this->response->setJSON($data_row);
|
||||
return $this->response->setJSON($dataRow);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Returns customer table data rows. This will be called with AJAX.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('search');
|
||||
@@ -92,15 +77,13 @@ class Customers extends Persons
|
||||
$order = $this->request->getGet('order', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
|
||||
$customers = $this->customer->search($search, $limit, $offset, $sort, $order);
|
||||
$total_rows = $this->customer->get_found_rows($search);
|
||||
$totalRows = $this->customer->get_found_rows($search);
|
||||
|
||||
$data_rows = [];
|
||||
$dataRows = [];
|
||||
|
||||
foreach ($customers->getResult() as $person) {
|
||||
// Retrieve the total amount the customer spent so far together with min, max and average values
|
||||
$stats = $this->customer->get_stats($person->person_id); // TODO: duplicated... see above
|
||||
$stats = $this->customer->get_stats($person->person_id);
|
||||
if (empty($stats)) {
|
||||
// Create object with empty properties.
|
||||
$stats = new stdClass();
|
||||
$stats->total = 0;
|
||||
$stats->min = 0;
|
||||
@@ -110,16 +93,12 @@ class Customers extends Persons
|
||||
$stats->quantity = 0;
|
||||
}
|
||||
|
||||
$data_rows[] = get_customer_data_row($person, $stats);
|
||||
$dataRows[] = get_customer_data_row($person, $stats);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['total' => $total_rows, 'rows' => $data_rows]);
|
||||
return $this->response->setJSON(['total' => $totalRows, 'rows' => $dataRows]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives search suggestions based on what is being searched for
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getSuggest(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('term');
|
||||
@@ -128,10 +107,7 @@ class Customers extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function suggest_search(): ResponseInterface
|
||||
public function suggestSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('term');
|
||||
$suggestions = $this->customer->get_search_suggestions($search, 25, false);
|
||||
@@ -139,16 +115,11 @@ class Customers extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the customer edit form
|
||||
* @return string
|
||||
*/
|
||||
public function getView(int $customer_id = NEW_ENTRY): string
|
||||
public function getView(int $customerId = NEW_ENTRY): string
|
||||
{
|
||||
// Set default values
|
||||
if ($customer_id == null) $customer_id = NEW_ENTRY;
|
||||
if ($customerId == null) $customerId = NEW_ENTRY;
|
||||
|
||||
$info = $this->customer->get_info($customer_id);
|
||||
$info = $this->customer->get_info($customerId);
|
||||
foreach (get_object_vars($info) as $property => $value) {
|
||||
$info->$property = $value;
|
||||
}
|
||||
@@ -159,28 +130,27 @@ class Customers extends Persons
|
||||
$data['person_info']->employee_id = $this->employee->get_logged_in_employee_info()->person_id;
|
||||
}
|
||||
|
||||
$employee_info = $this->employee->get_info($info->employee_id);
|
||||
$data['employee'] = $employee_info->first_name . ' ' . $employee_info->last_name;
|
||||
$employeeInfo = $this->employee->get_info($info->employee_id);
|
||||
$data['employee'] = $employeeInfo->first_name . ' ' . $employeeInfo->last_name;
|
||||
|
||||
$tax_code_info = $this->tax_code->get_info($info->sales_tax_code_id);
|
||||
$taxCodeInfo = $this->taxCode->get_info($info->sales_tax_code_id);
|
||||
|
||||
if ($tax_code_info->tax_code != null) {
|
||||
$data['sales_tax_code_label'] = $tax_code_info->tax_code . ' ' . $tax_code_info->tax_code_name;
|
||||
if ($taxCodeInfo->tax_code != null) {
|
||||
$data['sales_tax_code_label'] = $taxCodeInfo->tax_code . ' ' . $taxCodeInfo->tax_code_name;
|
||||
} else {
|
||||
$data['sales_tax_code_label'] = '';
|
||||
}
|
||||
|
||||
$packages = ['' => lang('Items.none')];
|
||||
foreach ($this->customer_rewards->get_all()->getResultArray() as $row) {
|
||||
foreach ($this->customerRewards->get_all()->getResultArray() as $row) {
|
||||
$packages[$row['package_id']] = $row['package_name'];
|
||||
}
|
||||
$data['packages'] = $packages;
|
||||
$data['selected_package'] = $info->package_id;
|
||||
|
||||
$data['use_destination_based_tax'] = $this->config['use_destination_based_tax'];
|
||||
$data['use_destination_based_tax'] = $this->appConfig['use_destination_based_tax'];
|
||||
|
||||
// Retrieve the total amount the customer spent so far together with min, max and average values
|
||||
$stats = $this->customer->get_stats($customer_id);
|
||||
$stats = $this->customer->get_stats($customerId);
|
||||
if (!empty($stats)) {
|
||||
foreach (get_object_vars($stats) as $property => $value) {
|
||||
$info->$property = $value;
|
||||
@@ -188,14 +158,11 @@ class Customers extends Persons
|
||||
$data['stats'] = $stats;
|
||||
}
|
||||
|
||||
// Retrieve the info from Mailchimp only if there is an email address assigned
|
||||
if (!empty($info->email)) {
|
||||
// Collect Mailchimp customer info
|
||||
if (($mailchimp_info = $this->mailchimp_lib->getMemberInfo($this->_list_id, $info->email)) !== false) {
|
||||
$data['mailchimp_info'] = $mailchimp_info;
|
||||
if (($mailchimpInfo = $this->mailchimpLib->getMemberInfo($this->listId, $info->email)) !== false) {
|
||||
$data['mailchimp_info'] = $mailchimpInfo;
|
||||
|
||||
// Collect customer Mailchimp emails activities (stats)
|
||||
if (($activities = $this->mailchimp_lib->getMemberActivity($this->_list_id, $info->email)) !== false) {
|
||||
if (($activities = $this->mailchimpLib->getMemberActivity($this->listId, $info->email)) !== false) {
|
||||
if (array_key_exists('activity', $activities)) {
|
||||
$open = 0;
|
||||
$unopen = 0;
|
||||
@@ -235,22 +202,25 @@ class Customers extends Persons
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts/updates a customer
|
||||
* @return ResponseInterface
|
||||
* Gets person attributes for a customer (AJAX)
|
||||
*/
|
||||
public function postSave(int $customer_id = NEW_ENTRY): ResponseInterface
|
||||
public function getAttributes(int $customerId = NEW_ENTRY): string
|
||||
{
|
||||
$first_name = $this->request->getPost('first_name');
|
||||
$last_name = $this->request->getPost('last_name');
|
||||
return $this->getPersonAttributes($customerId, Attribute::SHOW_IN_CUSTOMERS);
|
||||
}
|
||||
|
||||
public function postSave(int $customerId = NEW_ENTRY): ResponseInterface
|
||||
{
|
||||
$firstName = $this->request->getPost('first_name');
|
||||
$lastName = $this->request->getPost('last_name');
|
||||
$email = strtolower($this->request->getPost('email', FILTER_SANITIZE_EMAIL));
|
||||
|
||||
// Format first and last name properly
|
||||
$first_name = $this->nameize($first_name);
|
||||
$last_name = $this->nameize($last_name);
|
||||
$firstName = $this->nameize($firstName);
|
||||
$lastName = $this->nameize($lastName);
|
||||
|
||||
$person_data = [
|
||||
'first_name' => $first_name,
|
||||
'last_name' => $last_name,
|
||||
$personData = [
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName,
|
||||
'gender' => $this->request->getPost('gender', FILTER_SANITIZE_NUMBER_INT),
|
||||
'email' => $email,
|
||||
'phone_number' => $this->request->getPost('phone_number'),
|
||||
@@ -263,9 +233,9 @@ class Customers extends Persons
|
||||
'comments' => $this->request->getPost('comments')
|
||||
];
|
||||
|
||||
$date_formatter = date_create_from_format($this->config['dateformat'] . ' ' . $this->config['timeformat'], $this->request->getPost('date'));
|
||||
$dateFormatter = date_create_from_format($this->appConfig['dateformat'] . ' ' . $this->appConfig['timeformat'], $this->request->getPost('date'));
|
||||
|
||||
$customer_data = [
|
||||
$customerData = [
|
||||
'consent' => $this->request->getPost('consent') != null,
|
||||
'account_number' => $this->request->getPost('account_number') == '' ? null : $this->request->getPost('account_number'),
|
||||
'tax_id' => $this->request->getPost('tax_id'),
|
||||
@@ -274,68 +244,57 @@ class Customers extends Persons
|
||||
'discount_type' => $this->request->getPost('discount_type') == null ? PERCENT : $this->request->getPost('discount_type', FILTER_SANITIZE_NUMBER_INT),
|
||||
'package_id' => $this->request->getPost('package_id') == '' ? null : $this->request->getPost('package_id'),
|
||||
'taxable' => $this->request->getPost('taxable') != null,
|
||||
'date' => $date_formatter->format('Y-m-d H:i:s'),
|
||||
'date' => $dateFormatter->format('Y-m-d H:i:s'),
|
||||
'employee_id' => $this->request->getPost('employee_id', FILTER_SANITIZE_NUMBER_INT),
|
||||
'sales_tax_code_id' => $this->request->getPost('sales_tax_code_id') == '' ? null : $this->request->getPost('sales_tax_code_id', FILTER_SANITIZE_NUMBER_INT)
|
||||
];
|
||||
|
||||
if ($this->customer->save_customer($person_data, $customer_data, $customer_id)) {
|
||||
// Save customer to Mailchimp selected list // TODO: addOrUpdateMember should be refactored. Potentially pass an array or object instead of 6 parameters.
|
||||
$mailchimp_status = $this->request->getPost('mailchimp_status');
|
||||
$this->mailchimp_lib->addOrUpdateMember(
|
||||
$this->_list_id,
|
||||
if ($this->customer->save_customer($personData, $customerData, $customerId)) {
|
||||
$personId = $customerId == NEW_ENTRY ? $customerData['person_id'] : $customerId;
|
||||
$this->savePersonAttributes($personId, Attribute::SHOW_IN_CUSTOMERS);
|
||||
|
||||
$mailchimpStatus = $this->request->getPost('mailchimp_status');
|
||||
$this->mailchimpLib->addOrUpdateMember(
|
||||
$this->listId,
|
||||
$email,
|
||||
$first_name,
|
||||
$last_name,
|
||||
$mailchimp_status == null ? "" : $mailchimp_status,
|
||||
$firstName,
|
||||
$lastName,
|
||||
$mailchimpStatus == null ? "" : $mailchimpStatus,
|
||||
['vip' => $this->request->getPost('mailchimp_vip') != null]
|
||||
);
|
||||
|
||||
// New customer
|
||||
if ($customer_id == NEW_ENTRY) {
|
||||
if ($customerId == NEW_ENTRY) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Customers.successful_adding') . ' ' . $first_name . ' ' . $last_name,
|
||||
'id' => $customer_data['person_id']
|
||||
'message' => lang('Customers.successful_adding') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => $customerData['person_id']
|
||||
]);
|
||||
} else { // Existing customer
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Customers.successful_updating') . ' ' . $first_name . ' ' . $last_name,
|
||||
'id' => $customer_id
|
||||
'message' => lang('Customers.successful_updating') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => $customerId
|
||||
]);
|
||||
}
|
||||
} else { // Failure
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Customers.error_adding_updating') . ' ' . $first_name . ' ' . $last_name,
|
||||
'message' => lang('Customers.error_adding_updating') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if an email address already exists. Used in app/Views/customers/form.php
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postCheckEmail(): ResponseInterface
|
||||
{
|
||||
$email = strtolower($this->request->getPost('email', FILTER_SANITIZE_EMAIL));
|
||||
$person_id = $this->request->getPost('person_id', FILTER_SANITIZE_NUMBER_INT);
|
||||
$personId = $this->request->getPost('person_id', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
||||
$exists = $this->customer->check_email_exists($email, $person_id);
|
||||
$exists = $this->customer->check_email_exists($email, $personId);
|
||||
|
||||
return $this->response->setJSON(!$exists ? 'true' : 'false');
|
||||
}
|
||||
|
||||
/**
|
||||
* Verifies if an account number already exists. Used in app/Views/customers/form.php
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postCheckAccountNumber(): ResponseInterface
|
||||
{
|
||||
$exists = $this->customer->check_account_number_exists($this->request->getPost('account_number'), $this->request->getPost('person_id', FILTER_SANITIZE_NUMBER_INT));
|
||||
@@ -343,27 +302,22 @@ class Customers extends Persons
|
||||
return $this->response->setJSON(!$exists ? 'true' : 'false');
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes customers from the customers table
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postDelete(): ResponseInterface
|
||||
{
|
||||
$customers_to_delete = $this->request->getPost('ids');
|
||||
$customers_info = $this->customer->get_multiple_info($customers_to_delete);
|
||||
$customersToDelete = $this->request->getPost('ids');
|
||||
$customersInfo = $this->customer->get_multiple_info($customersToDelete);
|
||||
|
||||
$count = 0;
|
||||
|
||||
foreach ($customers_info->getResult() as $info) {
|
||||
foreach ($customersInfo->getResult() as $info) {
|
||||
if ($this->customer->delete($info->person_id)) {
|
||||
// remove customer from Mailchimp selected list
|
||||
$this->mailchimp_lib->removeMember($this->_list_id, $info->email);
|
||||
$this->mailchimpLib->removeMember($this->listId, $info->email);
|
||||
|
||||
$count++;
|
||||
}
|
||||
}
|
||||
|
||||
if ($count == count($customers_to_delete)) {
|
||||
if ($count == count($customersToDelete)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Customers.successful_deleted') . ' ' . $count . ' ' . lang('Customers.one_or_multiple')
|
||||
@@ -373,12 +327,6 @@ class Customers extends Persons
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Customers import from csv spreadsheet
|
||||
*
|
||||
* @return DownloadResponse The template for Customer CSV imports is returned and download forced.
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getCsv(): DownloadResponse
|
||||
{
|
||||
$name = 'importCustomers.csv';
|
||||
@@ -386,30 +334,17 @@ class Customers extends Persons
|
||||
return $this->response->download($name, $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Displays the customer CSV import modal. Used in app/Views/people/manage.php
|
||||
*
|
||||
* @return string
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getCsvImport(): string
|
||||
{
|
||||
return view('customers/form_csv_import');
|
||||
}
|
||||
|
||||
/**
|
||||
* Imports a CSV file containing customers. Used in app/Views/customers/form_csv_import.php
|
||||
*
|
||||
* @return ResponseInterface
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function postImportCsvFile(): ResponseInterface
|
||||
{
|
||||
if ($_FILES['file_path']['error'] != UPLOAD_ERR_OK) {
|
||||
return $this->response->setJSON(['success' => false, 'message' => lang('Customers.csv_import_failed')]);
|
||||
} else {
|
||||
if (($handle = fopen($_FILES['file_path']['tmp_name'], 'r')) !== false) {
|
||||
// Skip the first row as it's the table description
|
||||
fgetcsv($handle);
|
||||
$i = 1;
|
||||
|
||||
@@ -420,7 +355,7 @@ class Customers extends Persons
|
||||
|
||||
if (sizeof($data) >= 16 && $consent) {
|
||||
$email = strtolower($data[4]);
|
||||
$person_data = [
|
||||
$personData = [
|
||||
'first_name' => $data[0],
|
||||
'last_name' => $data[1],
|
||||
'gender' => $data[2],
|
||||
@@ -435,7 +370,7 @@ class Customers extends Persons
|
||||
'comments' => $data[12]
|
||||
];
|
||||
|
||||
$customer_data = [
|
||||
$customerData = [
|
||||
'consent' => $consent,
|
||||
'company_name' => $data[13],
|
||||
'discount' => $data[15],
|
||||
@@ -444,14 +379,13 @@ class Customers extends Persons
|
||||
'date' => date('Y-m-d H:i:s'),
|
||||
'employee_id' => $this->employee->get_logged_in_employee_info()->person_id
|
||||
];
|
||||
$account_number = $data[14];
|
||||
$accountNumber = $data[14];
|
||||
|
||||
// Don't duplicate people with same email
|
||||
$invalidated = $this->customer->check_email_exists($email);
|
||||
|
||||
if ($account_number != '') {
|
||||
$customer_data['account_number'] = $account_number;
|
||||
$invalidated &= $this->customer->check_account_number_exists($account_number);
|
||||
if ($accountNumber != '') {
|
||||
$customerData['account_number'] = $accountNumber;
|
||||
$invalidated &= $this->customer->check_account_number_exists($accountNumber);
|
||||
}
|
||||
} else {
|
||||
$invalidated = true;
|
||||
@@ -460,9 +394,8 @@ class Customers extends Persons
|
||||
if ($invalidated) {
|
||||
$failCodes[] = $i;
|
||||
log_message('error', "Row $i was not imported: Either email or account number already exist or data was invalid.");
|
||||
} elseif ($this->customer->save_customer($person_data, $customer_data)) {
|
||||
// Save customer to Mailchimp selected list
|
||||
$this->mailchimp_lib->addOrUpdateMember($this->_list_id, $person_data['email'], $person_data['first_name'], '', $person_data['last_name']);
|
||||
} elseif ($this->customer->save_customer($personData, $customerData)) {
|
||||
$this->mailchimpLib->addOrUpdateMember($this->listId, $personData['email'], $personData['first_name'], '', $personData['last_name']);
|
||||
} else {
|
||||
$failCodes[] = $i;
|
||||
}
|
||||
@@ -482,4 +415,4 @@ class Customers extends Persons
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,18 +2,15 @@
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\Attribute;
|
||||
use App\Models\Module;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @property module module
|
||||
*
|
||||
*/
|
||||
class Employees extends Persons
|
||||
{
|
||||
protected Module $module;
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct('employees');
|
||||
@@ -21,35 +18,25 @@ class Employees extends Persons
|
||||
$this->module = model('Module');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns employee table data rows. This will be called with AJAX.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function getSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('search');
|
||||
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
|
||||
$limit = $this->request->getGet('limit', FILTER_SANITIZE_NUMBER_INT);
|
||||
$offset = $this->request->getGet('offset', FILTER_SANITIZE_NUMBER_INT);
|
||||
$sort = $this->sanitizeSortColumn(person_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'people.person_id');
|
||||
$order = $this->request->getGet('order', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$sort = $this->sanitizeSortColumn(person_headers(), $this->request->getGet('sort', FILTER_SANITIZE_FULL_SPECIAL_CHARS), 'people.person_id');
|
||||
$order = $this->request->getGet('order', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
|
||||
$employees = $this->employee->search($search, $limit, $offset, $sort, $order);
|
||||
$total_rows = $this->employee->get_found_rows($search);
|
||||
$totalRows = $this->employee->get_found_rows($search);
|
||||
|
||||
$data_rows = [];
|
||||
$dataRows = [];
|
||||
foreach ($employees->getResult() as $person) {
|
||||
$data_rows[] = get_person_data_row($person);
|
||||
$dataRows[] = get_person_data_row($person);
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['total' => $total_rows, 'rows' => $data_rows]);
|
||||
return $this->response->setJSON(['total' => $totalRows, 'rows' => $dataRows]);
|
||||
}
|
||||
|
||||
/**
|
||||
* AJAX called function gives search suggestions based on what is being searched for.
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getSuggest(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('term');
|
||||
@@ -58,10 +45,7 @@ class Employees extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function suggest_search(): ResponseInterface
|
||||
public function suggestSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getPost('term');
|
||||
$suggestions = $this->employee->get_search_suggestions($search);
|
||||
@@ -69,39 +53,35 @@ class Employees extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the employee edit form
|
||||
* @return string
|
||||
*/
|
||||
public function getView(int $employee_id = NEW_ENTRY): string
|
||||
public function getView(int $employeeId = NEW_ENTRY): string
|
||||
{
|
||||
$person_info = $this->employee->get_info($employee_id);
|
||||
$current_user = $this->employee->get_logged_in_employee_info();
|
||||
$personInfo = $this->employee->get_info($employeeId);
|
||||
$currentUser = $this->employee->get_logged_in_employee_info();
|
||||
|
||||
if ($employee_id != NEW_ENTRY && !$this->employee->canModifyEmployee($person_info->person_id, $current_user->person_id)) {
|
||||
if ($employeeId != NEW_ENTRY && !$this->employee->canModifyEmployee($personInfo->person_id, $currentUser->person_id)) {
|
||||
header('Location: ' . base_url('no_access/employees/employees'));
|
||||
exit();
|
||||
}
|
||||
|
||||
foreach (get_object_vars($person_info) as $property => $value) {
|
||||
$person_info->$property = $value;
|
||||
foreach (get_object_vars($personInfo) as $property => $value) {
|
||||
$personInfo->$property = $value;
|
||||
}
|
||||
$data['person_info'] = $person_info;
|
||||
$data['employee_id'] = $employee_id;
|
||||
$data['person_info'] = $personInfo;
|
||||
$data['employee_id'] = $employeeId;
|
||||
|
||||
$modules = [];
|
||||
foreach ($this->module->get_all_modules()->getResult() as $module) {
|
||||
$module->grant = $this->employee->has_grant($module->module_id, $person_info->person_id);
|
||||
$module->menu_group = $this->employee->get_menu_group($module->module_id, $person_info->person_id);
|
||||
$module->grant = $this->employee->has_grant($module->module_id, $personInfo->person_id);
|
||||
$module->menu_group = $this->employee->get_menu_group($module->module_id, $personInfo->person_id);
|
||||
|
||||
$modules[] = $module;
|
||||
}
|
||||
$data['all_modules'] = $modules;
|
||||
|
||||
$permissions = [];
|
||||
foreach ($this->module->get_all_subpermissions()->getResult() as $permission) { // TODO: subpermissions does not follow naming standards.
|
||||
foreach ($this->module->get_all_subpermissions()->getResult() as $permission) {
|
||||
$permission->permission_id = str_replace(' ', '_', $permission->permission_id);
|
||||
$permission->grant = $this->employee->has_grant($permission->permission_id, $person_info->person_id);
|
||||
$permission->grant = $this->employee->has_grant($permission->permission_id, $personInfo->person_id);
|
||||
|
||||
$permissions[] = $permission;
|
||||
}
|
||||
@@ -110,17 +90,18 @@ class Employees extends Persons
|
||||
return view('employees/form', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts/updates an employee
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postSave(int $employee_id = NEW_ENTRY): ResponseInterface
|
||||
public function getAttributes(int $employeeId = NEW_ENTRY): string
|
||||
{
|
||||
$current_user = $this->employee->get_logged_in_employee_info();
|
||||
return $this->getPersonAttributes($employeeId, Attribute::SHOW_IN_EMPLOYEES);
|
||||
}
|
||||
|
||||
if ($employee_id != NEW_ENTRY) {
|
||||
$target_employee = $this->employee->get_info($employee_id);
|
||||
if (!$this->employee->canModifyEmployee($target_employee->person_id, $current_user->person_id)) {
|
||||
public function postSave(int $employeeId = NEW_ENTRY): ResponseInterface
|
||||
{
|
||||
$currentUser = $this->employee->get_logged_in_employee_info();
|
||||
|
||||
if ($employeeId != NEW_ENTRY) {
|
||||
$targetEmployee = $this->employee->get_info($employeeId);
|
||||
if (!$this->employee->canModifyEmployee($targetEmployee->person_id, $currentUser->person_id)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.error_updating_admin'),
|
||||
@@ -129,17 +110,16 @@ class Employees extends Persons
|
||||
}
|
||||
}
|
||||
|
||||
$first_name = $this->request->getPost('first_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS); // TODO: duplicated code
|
||||
$last_name = $this->request->getPost('last_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$firstName = $this->request->getPost('first_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$lastName = $this->request->getPost('last_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$email = strtolower($this->request->getPost('email', FILTER_SANITIZE_EMAIL));
|
||||
|
||||
// format first and last name properly
|
||||
$first_name = $this->nameize($first_name);
|
||||
$last_name = $this->nameize($last_name);
|
||||
$firstName = $this->nameize($firstName);
|
||||
$lastName = $this->nameize($lastName);
|
||||
|
||||
$person_data = [
|
||||
'first_name' => $first_name,
|
||||
'last_name' => $last_name,
|
||||
$personData = [
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName,
|
||||
'gender' => $this->request->getPost('gender', FILTER_SANITIZE_NUMBER_INT),
|
||||
'email' => $email,
|
||||
'phone_number' => $this->request->getPost('phone_number', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
@@ -152,108 +132,98 @@ class Employees extends Persons
|
||||
'comments' => $this->request->getPost('comments', FILTER_SANITIZE_FULL_SPECIAL_CHARS)
|
||||
];
|
||||
|
||||
$grants_array = [];
|
||||
$isAdmin = $this->employee->isAdmin($current_user->person_id);
|
||||
$grantsArray = [];
|
||||
$isAdmin = $this->employee->isAdmin($currentUser->person_id);
|
||||
|
||||
foreach ($this->module->get_all_permissions()->getResult() as $permission) {
|
||||
$grants = [];
|
||||
$grant = $this->request->getPost('grant_' . $permission->permission_id) != null ? $this->request->getPost('grant_' . $permission->permission_id, FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '';
|
||||
|
||||
if ($grant == $permission->permission_id) {
|
||||
if (!$isAdmin && !$this->employee->has_grant($permission->permission_id, $current_user->person_id)) {
|
||||
if (!$isAdmin && !$this->employee->has_grant($permission->permission_id, $currentUser->person_id)) {
|
||||
continue;
|
||||
}
|
||||
$grants['permission_id'] = $permission->permission_id;
|
||||
$grants['menu_group'] = $this->request->getPost('menu_group_' . $permission->permission_id) != null ? $this->request->getPost('menu_group_' . $permission->permission_id, FILTER_SANITIZE_FULL_SPECIAL_CHARS) : '--';
|
||||
$grants_array[] = $grants;
|
||||
$grantsArray[] = $grants;
|
||||
}
|
||||
}
|
||||
|
||||
// Password has been changed OR first time password set
|
||||
if (!empty($this->request->getPost('password')) && ENVIRONMENT != 'testing') {
|
||||
$exploded = explode(":", $this->request->getPost('language', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
|
||||
$employee_data = [
|
||||
$employeeData = [
|
||||
'username' => $this->request->getPost('username', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'password' => password_hash($this->request->getPost('password'), PASSWORD_DEFAULT),
|
||||
'hash_version' => 2,
|
||||
'language_code' => $exploded[0],
|
||||
'language' => $exploded[1]
|
||||
];
|
||||
} else { // Password not changed
|
||||
} else {
|
||||
$exploded = explode(":", $this->request->getPost('language', FILTER_SANITIZE_FULL_SPECIAL_CHARS));
|
||||
$employee_data = [
|
||||
$employeeData = [
|
||||
'username' => $this->request->getPost('username', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'language_code' => $exploded[0],
|
||||
'language' => $exploded[1]
|
||||
];
|
||||
}
|
||||
|
||||
if ($this->employee->save_employee($person_data, $employee_data, $grants_array, $employee_id)) {
|
||||
// New employee
|
||||
if ($employee_id == NEW_ENTRY) {
|
||||
if ($this->employee->save_employee($personData, $employeeData, $grantsArray, $employeeId)) {
|
||||
$personId = $employeeId == NEW_ENTRY ? $employeeData['person_id'] : $employeeId;
|
||||
$this->savePersonAttributes($personId, Attribute::SHOW_IN_EMPLOYEES);
|
||||
|
||||
if ($employeeId == NEW_ENTRY) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Employees.successful_adding') . ' ' . $first_name . ' ' . $last_name,
|
||||
'id' => $employee_data['person_id']
|
||||
'message' => lang('Employees.successful_adding') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => $employeeData['person_id']
|
||||
]);
|
||||
} else { // Existing employee
|
||||
$logged_in_employee_id = session()->get('person_id');
|
||||
if ($employee_id == $logged_in_employee_id) {
|
||||
session()->set('language_code', $employee_data['language_code']);
|
||||
session()->set('language', $employee_data['language']);
|
||||
} else {
|
||||
$loggedInEmployeeId = session()->get('person_id');
|
||||
if ($employeeId == $loggedInEmployeeId) {
|
||||
session()->set('language_code', $employeeData['language_code']);
|
||||
session()->set('language', $employeeData['language']);
|
||||
}
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Employees.successful_updating') . ' ' . $first_name . ' ' . $last_name,
|
||||
'id' => $employee_id
|
||||
'message' => lang('Employees.successful_updating') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => $employeeId
|
||||
]);
|
||||
}
|
||||
} else { // Failure
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Employees.error_adding_updating') . ' ' . $first_name . ' ' . $last_name,
|
||||
'message' => lang('Employees.error_adding_updating') . ' ' . $firstName . ' ' . $lastName,
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes employees from the employees table
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postDelete(): ResponseInterface
|
||||
{
|
||||
$employees_to_delete = $this->request->getPost('ids', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$current_user = $this->employee->get_logged_in_employee_info();
|
||||
$employeesToDelete = $this->request->getPost('ids', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$currentUser = $this->employee->get_logged_in_employee_info();
|
||||
|
||||
if (!$this->employee->isAdmin($current_user->person_id)) {
|
||||
foreach ($employees_to_delete as $emp_id) {
|
||||
if ($this->employee->isAdmin((int)$emp_id)) {
|
||||
if (!$this->employee->isAdmin($currentUser->person_id)) {
|
||||
foreach ($employeesToDelete as $empId) {
|
||||
if ($this->employee->isAdmin((int)$empId)) {
|
||||
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.error_deleting_admin')]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ($this->employee->delete_list($employees_to_delete)) { // TODO: this is passing a string, but delete_list expects an array
|
||||
if ($this->employee->delete_list($employeesToDelete)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Employees.successful_deleted') . ' ' . count($employees_to_delete) . ' ' . lang('Employees.one_or_multiple')
|
||||
'message' => lang('Employees.successful_deleted') . ' ' . count($employeesToDelete) . ' ' . lang('Employees.one_or_multiple')
|
||||
]);
|
||||
} else {
|
||||
return $this->response->setJSON(['success' => false, 'message' => lang('Employees.cannot_be_deleted')]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks an employee username against the database. Used in app\Views\employees\form.php
|
||||
*
|
||||
* @param $employee_id
|
||||
* @return ResponseInterface
|
||||
* @noinspection PhpUnused
|
||||
*/
|
||||
public function getCheckUsername($employee_id): ResponseInterface
|
||||
public function getCheckUsername($employeeId): ResponseInterface
|
||||
{
|
||||
$exists = $this->employee->username_exists($employee_id, $this->request->getGet('username'));
|
||||
$exists = $this->employee->username_exists($employeeId, $this->request->getGet('username'));
|
||||
return $this->response->setJSON(!$exists ? 'true' : 'false');
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,28 +2,28 @@
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\Attribute;
|
||||
use App\Models\Person;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\OSPOS;
|
||||
use Config\Services;
|
||||
use function Tamtamchik\NameCase\str_name_case;
|
||||
|
||||
abstract class Persons extends Secure_Controller
|
||||
{
|
||||
protected Person $person;
|
||||
protected Attribute $attribute;
|
||||
protected array $appConfig;
|
||||
|
||||
/**
|
||||
* @param string|null $module_id
|
||||
*/
|
||||
public function __construct(?string $module_id = null)
|
||||
public function __construct(?string $moduleId = null)
|
||||
{
|
||||
parent::__construct($module_id);
|
||||
parent::__construct($moduleId);
|
||||
|
||||
$this->person = model(Person::class);
|
||||
$this->attribute = model(Attribute::class);
|
||||
$this->appConfig = config(OSPOS::class)->settings;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex(): string
|
||||
{
|
||||
$data['table_headers'] = get_people_manage_table_headers();
|
||||
@@ -31,10 +31,6 @@ abstract class Persons extends Secure_Controller
|
||||
return view('people/manage', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives search suggestions based on what is being searched for
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getSuggest(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('term');
|
||||
@@ -43,34 +39,88 @@ abstract class Persons extends Secure_Controller
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one row for a person manage table. This is called using AJAX to update one row.
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getRow(int $row_id): ResponseInterface
|
||||
public function getRow(int $rowId): ResponseInterface
|
||||
{
|
||||
$data_row = get_person_data_row($this->person->get_info($row_id));
|
||||
$dataRow = get_person_data_row($this->person->get_info($rowId));
|
||||
|
||||
return $this->response->setJSON($data_row);
|
||||
return $this->response->setJSON($dataRow);
|
||||
}
|
||||
|
||||
protected function getPersonAttributes(int $personId, int $definitionFlags): string
|
||||
{
|
||||
$data['person_id'] = $personId;
|
||||
$data['config'] = $this->appConfig;
|
||||
$definitionIds = json_decode($this->request->getGet('definition_ids') ?? '', true);
|
||||
$data['definition_values'] = $this->attribute->getAttributesByPerson($personId) + $this->attribute->get_values_by_definitions($definitionIds);
|
||||
$data['definition_names'] = $this->attribute->getDefinitionsByType(true, $definitionFlags);
|
||||
|
||||
foreach ($data['definition_values'] as $definitionId => $definitionValue) {
|
||||
$attributeValue = $this->attribute->getPersonAttributeValue($personId, $definitionId);
|
||||
$attributeId = (empty($attributeValue) || empty($attributeValue->attribute_id)) ? null : $attributeValue->attribute_id;
|
||||
$values = &$data['definition_values'][$definitionId];
|
||||
$values['attribute_id'] = $attributeId;
|
||||
$values['attribute_value'] = $attributeValue;
|
||||
$values['selected_value'] = '';
|
||||
|
||||
if ($definitionValue['definition_type'] === DROPDOWN) {
|
||||
$values['values'] = $this->attribute->get_definition_values($definitionId);
|
||||
$linkValue = $this->getPersonLinkValue($personId, $definitionId);
|
||||
$values['selected_value'] = (empty($linkValue)) ? '' : $linkValue->attribute_id;
|
||||
}
|
||||
|
||||
if (!empty($definitionIds[$definitionId])) {
|
||||
$values['selected_value'] = $definitionIds[$definitionId];
|
||||
}
|
||||
|
||||
unset($data['definition_names'][$definitionId]);
|
||||
}
|
||||
|
||||
return view('attributes/person', $data);
|
||||
}
|
||||
|
||||
private function getPersonLinkValue(int $personId, int $definitionId): ?object
|
||||
{
|
||||
$builder = $this->db->table('attribute_links');
|
||||
$builder->where('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
|
||||
return $builder->get()->getRowObject();
|
||||
}
|
||||
|
||||
protected function savePersonAttributes(int $personId, int $definitionFlags): void
|
||||
{
|
||||
$attributeLinks = $this->request->getPost('attribute_links') ?? [];
|
||||
$attributeIds = $this->request->getPost('attribute_ids') ?? [];
|
||||
|
||||
$this->attribute->deletePersonAttributeLinks($personId);
|
||||
|
||||
foreach ($attributeLinks as $definitionId => $attributeId) {
|
||||
$definitionInfo = $this->attribute->getAttributeInfo((int)$definitionId);
|
||||
$definitionType = $definitionInfo->definition_type;
|
||||
|
||||
if ($definitionType !== DROPDOWN) {
|
||||
$attributeId = $this->attribute->savePersonAttributeValue(
|
||||
$attributeId,
|
||||
(int)$definitionId,
|
||||
$personId,
|
||||
$attributeIds[$definitionId] ?? false,
|
||||
$definitionType
|
||||
);
|
||||
}
|
||||
|
||||
$this->attribute->savePersonAttributeLink($personId, (int)$definitionId, (int)$attributeId);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Capitalize segments of a name, and put the rest into lower case.
|
||||
* You can pass the characters you want to use as delimiters as exceptions.
|
||||
* The function supports UTF-8 strings
|
||||
*
|
||||
* Example:
|
||||
* i.e. <?php echo nameize("john o'grady-smith"); ?>
|
||||
*
|
||||
* returns John O'Grady-Smith
|
||||
*/
|
||||
protected function nameize(string $input): string
|
||||
{
|
||||
$adjusted_name = str_name_case($input);
|
||||
$adjustedName = str_name_case($input);
|
||||
|
||||
// TODO: Use preg_replace to match HTML entities and convert them to lowercase. This is a workaround for https://github.com/tamtamchik/namecase/issues/20
|
||||
return preg_replace_callback('/&[a-zA-Z0-9#]+;/', function ($matches) {
|
||||
return strtolower($matches[0]);
|
||||
}, $adjusted_name);
|
||||
}, $adjustedName);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2,6 +2,7 @@
|
||||
|
||||
namespace App\Controllers;
|
||||
|
||||
use App\Models\Attribute;
|
||||
use App\Models\Supplier;
|
||||
use CodeIgniter\HTTP\ResponseInterface;
|
||||
use Config\Services;
|
||||
@@ -17,9 +18,6 @@ class Suppliers extends Persons
|
||||
$this->supplier = model(Supplier::class);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return string
|
||||
*/
|
||||
public function getIndex(): string
|
||||
{
|
||||
$data['table_headers'] = get_suppliers_manage_table_headers();
|
||||
@@ -27,23 +25,14 @@ class Suppliers extends Persons
|
||||
return view('people/manage', $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets one row for a supplier manage table. This is called using AJAX to update one row.
|
||||
* @param $row_id
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function getRow($row_id): ResponseInterface
|
||||
public function getRow($rowId): ResponseInterface
|
||||
{
|
||||
$data_row = get_supplier_data_row($this->supplier->get_info($row_id));
|
||||
$data_row['category'] = $this->supplier->get_category_name($data_row['category']);
|
||||
$dataRow = get_supplier_data_row($this->supplier->get_info($rowId));
|
||||
$dataRow['category'] = $this->supplier->get_category_name($dataRow['category']);
|
||||
|
||||
return $this->response->setJSON($data_row);
|
||||
return $this->response->setJSON($dataRow);
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns Supplier table data rows. This will be called with AJAX.
|
||||
* @return void
|
||||
**/
|
||||
public function getSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('search');
|
||||
@@ -53,23 +42,19 @@ class Suppliers extends Persons
|
||||
$order = $this->request->getGet('order', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
|
||||
$suppliers = $this->supplier->search($search, $limit, $offset, $sort, $order);
|
||||
$total_rows = $this->supplier->get_found_rows($search);
|
||||
$totalRows = $this->supplier->get_found_rows($search);
|
||||
|
||||
$data_rows = [];
|
||||
$dataRows = [];
|
||||
|
||||
foreach ($suppliers->getResult() as $supplier) {
|
||||
$row = get_supplier_data_row($supplier);
|
||||
$row['category'] = $this->supplier->get_category_name($row['category']);
|
||||
$data_rows[] = $row;
|
||||
$dataRows[] = $row;
|
||||
}
|
||||
|
||||
return $this->response->setJSON(['total' => $total_rows, 'rows' => $data_rows]);
|
||||
return $this->response->setJSON(['total' => $totalRows, 'rows' => $dataRows]);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gives search suggestions based on what is being searched for
|
||||
* @return ResponseInterface
|
||||
**/
|
||||
public function getSuggest(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getGet('term');
|
||||
@@ -78,10 +63,7 @@ class Suppliers extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function suggest_search(): ResponseInterface
|
||||
public function suggestSearch(): ResponseInterface
|
||||
{
|
||||
$search = $this->request->getPost('term');
|
||||
$suggestions = $this->supplier->get_search_suggestions($search, false);
|
||||
@@ -89,15 +71,9 @@ class Suppliers extends Persons
|
||||
return $this->response->setJSON($suggestions);
|
||||
}
|
||||
|
||||
/**
|
||||
* Loads the supplier edit form
|
||||
*
|
||||
* @param int $supplier_id
|
||||
* @return string
|
||||
*/
|
||||
public function getView(int $supplier_id = NEW_ENTRY): string
|
||||
public function getView(int $supplierId = NEW_ENTRY): string
|
||||
{
|
||||
$info = $this->supplier->get_info($supplier_id);
|
||||
$info = $this->supplier->get_info($supplierId);
|
||||
foreach (get_object_vars($info) as $property => $value) {
|
||||
$info->$property = $value;
|
||||
}
|
||||
@@ -107,25 +83,23 @@ class Suppliers extends Persons
|
||||
return view("suppliers/form", $data);
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts/updates a supplier
|
||||
*
|
||||
* @param int $supplier_id
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postSave(int $supplier_id = NEW_ENTRY): ResponseInterface
|
||||
public function getAttributes(int $supplierId = NEW_ENTRY): string
|
||||
{
|
||||
$first_name = $this->request->getPost('first_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS); // TODO: Duplicate code
|
||||
$last_name = $this->request->getPost('last_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
return $this->getPersonAttributes($supplierId, Attribute::SHOW_IN_SUPPLIERS);
|
||||
}
|
||||
|
||||
public function postSave(int $supplierId = NEW_ENTRY): ResponseInterface
|
||||
{
|
||||
$firstName = $this->request->getPost('first_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$lastName = $this->request->getPost('last_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS);
|
||||
$email = strtolower($this->request->getPost('email', FILTER_SANITIZE_EMAIL));
|
||||
|
||||
// Format first and last name properly
|
||||
$first_name = $this->nameize($first_name);
|
||||
$last_name = $this->nameize($last_name);
|
||||
$firstName = $this->nameize($firstName);
|
||||
$lastName = $this->nameize($lastName);
|
||||
|
||||
$person_data = [
|
||||
'first_name' => $first_name,
|
||||
'last_name' => $last_name,
|
||||
$personData = [
|
||||
'first_name' => $firstName,
|
||||
'last_name' => $lastName,
|
||||
'gender' => $this->request->getPost('gender'),
|
||||
'email' => $email,
|
||||
'phone_number' => $this->request->getPost('phone_number', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
@@ -138,7 +112,7 @@ class Suppliers extends Persons
|
||||
'comments' => $this->request->getPost('comments', FILTER_SANITIZE_FULL_SPECIAL_CHARS)
|
||||
];
|
||||
|
||||
$supplier_data = [
|
||||
$supplierData = [
|
||||
'company_name' => $this->request->getPost('company_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'agency_name' => $this->request->getPost('agency_name', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
'category' => $this->request->getPost('category', FILTER_SANITIZE_FULL_SPECIAL_CHARS),
|
||||
@@ -146,47 +120,43 @@ class Suppliers extends Persons
|
||||
'tax_id' => $this->request->getPost('tax_id', FILTER_SANITIZE_NUMBER_INT)
|
||||
];
|
||||
|
||||
if ($this->supplier->save_supplier($person_data, $supplier_data, $supplier_id)) {
|
||||
// New supplier
|
||||
if ($supplier_id == NEW_ENTRY) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Suppliers.successful_adding') . ' ' . $supplier_data['company_name'],
|
||||
'id' => $supplier_data['person_id']
|
||||
]);
|
||||
} else { // Existing supplier
|
||||
if ($this->supplier->save_supplier($personData, $supplierData, $supplierId)) {
|
||||
$personId = $supplierId == NEW_ENTRY ? $supplierData['person_id'] : $supplierId;
|
||||
$this->savePersonAttributes($personId, Attribute::SHOW_IN_SUPPLIERS);
|
||||
|
||||
if ($supplierId == NEW_ENTRY) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Suppliers.successful_updating') . ' ' . $supplier_data['company_name'],
|
||||
'id' => $supplier_id
|
||||
'message' => lang('Suppliers.successful_adding') . ' ' . $supplierData['company_name'],
|
||||
'id' => $supplierData['person_id']
|
||||
]);
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Suppliers.successful_updating') . ' ' . $supplierData['company_name'],
|
||||
'id' => $supplierId
|
||||
]);
|
||||
}
|
||||
} else { // Failure
|
||||
} else {
|
||||
return $this->response->setJSON([
|
||||
'success' => false,
|
||||
'message' => lang('Suppliers.error_adding_updating') . ' ' . $supplier_data['company_name'],
|
||||
'message' => lang('Suppliers.error_adding_updating') . ' ' . $supplierData['company_name'],
|
||||
'id' => NEW_ENTRY
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* This deletes suppliers from the suppliers table
|
||||
*
|
||||
* @return ResponseInterface
|
||||
*/
|
||||
public function postDelete(): ResponseInterface
|
||||
{
|
||||
$suppliers_to_delete = $this->request->getPost('ids', FILTER_SANITIZE_NUMBER_INT);
|
||||
$suppliersToDelete = $this->request->getPost('ids', FILTER_SANITIZE_NUMBER_INT);
|
||||
|
||||
if ($this->supplier->delete_list($suppliers_to_delete)) {
|
||||
if ($this->supplier->delete_list($suppliersToDelete)) {
|
||||
return $this->response->setJSON([
|
||||
'success' => true,
|
||||
'message' => lang('Suppliers.successful_deleted') . ' ' . count($suppliers_to_delete) . ' ' . lang('Suppliers.one_or_multiple')
|
||||
'message' => lang('Suppliers.successful_deleted') . ' ' . count($suppliersToDelete) . ' ' . lang('Suppliers.one_or_multiple')
|
||||
]);
|
||||
} else {
|
||||
return $this->response->setJSON(['success' => false, 'message' => lang('Suppliers.cannot_be_deleted')]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,61 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
use Config\Database;
|
||||
|
||||
class AddPersonToAttributeLinks extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
helper('migration');
|
||||
|
||||
// First, modify the generated unique column to include person_id
|
||||
// Drop the existing unique constraint
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP INDEX `attribute_links_uq3`');
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP COLUMN `generated_unique_column`');
|
||||
|
||||
// Add person_id column
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` ADD COLUMN `person_id` INT(10) NULL AFTER `receiving_id`');
|
||||
|
||||
// Add index for person_id
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` ADD KEY `person_id` (`person_id`)');
|
||||
|
||||
// Add foreign key constraint for person_id
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` ADD CONSTRAINT `ospos_attribute_links_ibfk_6` FOREIGN KEY (`person_id`) REFERENCES `ospos_people` (`person_id`) ON DELETE CASCADE');
|
||||
|
||||
// Recreate the generated unique column with person_id support
|
||||
// This ensures uniqueness for both item attributes and person attributes
|
||||
$this->db->query("ALTER TABLE `ospos_attribute_links`
|
||||
ADD COLUMN `generated_unique_column` VARCHAR(255) GENERATED ALWAYS AS (
|
||||
CASE
|
||||
WHEN `sale_id` IS NULL AND `receiving_id` IS NULL AND `item_id` IS NOT NULL THEN CONCAT('item-', `definition_id`, '-', `item_id`)
|
||||
WHEN `sale_id` IS NULL AND `receiving_id` IS NULL AND `item_id` IS NULL AND `person_id` IS NOT NULL THEN CONCAT('person-', `definition_id`, '-', `person_id`)
|
||||
ELSE NULL
|
||||
END
|
||||
) STORED");
|
||||
|
||||
// Re-add unique constraint
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` ADD UNIQUE INDEX `attribute_links_uq3` (`generated_unique_column`)');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
// Drop person_id related constraints and column
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP INDEX `attribute_links_uq3`');
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP COLUMN `generated_unique_column`');
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP FOREIGN KEY `ospos_attribute_links_ibfk_6`');
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` DROP COLUMN `person_id`');
|
||||
|
||||
// Restore original generated column
|
||||
$this->db->query("ALTER TABLE `ospos_attribute_links`
|
||||
ADD COLUMN `generated_unique_column` VARCHAR(255) GENERATED ALWAYS AS (
|
||||
CASE
|
||||
WHEN `sale_id` IS NULL AND `receiving_id` IS NULL AND `item_id` IS NOT NULL THEN CONCAT(`definition_id`, '-', `item_id`)
|
||||
ELSE NULL
|
||||
END
|
||||
) STORED");
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_links` ADD UNIQUE INDEX `attribute_links_uq3` (`generated_unique_column`)');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Database\Migrations;
|
||||
|
||||
use CodeIgniter\Database\Migration;
|
||||
|
||||
class AddPersonAttributeFlag extends Migration
|
||||
{
|
||||
public function up(): void
|
||||
{
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_definitions` ADD COLUMN `person_attribute` TINYINT(1) DEFAULT 0 AFTER `definition_flags`');
|
||||
}
|
||||
|
||||
public function down(): void
|
||||
{
|
||||
$this->db->query('ALTER TABLE `ospos_attribute_definitions` DROP COLUMN `person_attribute`');
|
||||
}
|
||||
}
|
||||
@@ -23,6 +23,10 @@ return [
|
||||
"new" => "New Attribute",
|
||||
"no_attributes_to_display" => "No Attributes to display",
|
||||
"receipt_visibility" => "Receipt",
|
||||
"show_in_customers" => "Show in customers",
|
||||
"show_in_customers_visibility" => "Customers",
|
||||
"show_in_employees" => "Show in employees",
|
||||
"show_in_employees_visibility" => "Employees",
|
||||
"show_in_items" => "Show in items",
|
||||
"show_in_items_visibility" => "Items",
|
||||
"show_in_receipt" => "Show in receipt",
|
||||
@@ -30,5 +34,7 @@ return [
|
||||
"show_in_receivings_visibility" => "Receivings",
|
||||
"show_in_sales" => "Show in sales",
|
||||
"show_in_sales_visibility" => "Sales",
|
||||
"show_in_suppliers" => "Show in suppliers",
|
||||
"show_in_suppliers_visibility" => "Suppliers",
|
||||
"update" => "Update Attribute",
|
||||
];
|
||||
|
||||
@@ -27,12 +27,14 @@ class Attribute extends Model
|
||||
'definition_type',
|
||||
'definition_unit',
|
||||
'definition_flags',
|
||||
'person_attribute',
|
||||
'deleted',
|
||||
'attribute_id',
|
||||
'definition_id',
|
||||
'item_id',
|
||||
'sale_id',
|
||||
'receiving_id',
|
||||
'person_id',
|
||||
'attribute_value',
|
||||
'attribute_date',
|
||||
'attribute_decimal'
|
||||
@@ -41,7 +43,12 @@ class Attribute extends Model
|
||||
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;
|
||||
public function deleteDropdownAttributeValue(string $attribute_value, int $definition_id): bool
|
||||
public const SHOW_IN_SEARCH = 8;
|
||||
public const SHOW_IN_CUSTOMERS = 16;
|
||||
public const SHOW_IN_EMPLOYEES = 32;
|
||||
public const SHOW_IN_SUPPLIERS = 64;
|
||||
|
||||
public function deleteDropdownAttributeValue(string $attributeValue, int $definitionId): bool
|
||||
{
|
||||
$attribute_id = $this->getAttributeIdByValue($attribute_value);
|
||||
$this->deleteAttributeLinksByDefinitionIdAndAttributeId($definition_id, $attribute_id);
|
||||
@@ -269,7 +276,7 @@ class Attribute extends Model
|
||||
public function get_definitions_by_flags(int $definition_flags, bool $include_types = false): 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(new RawSql("definition_flags & $definition_flags"));
|
||||
$builder->where('deleted', 0);
|
||||
$builder->where('definition_type <>', GROUP);
|
||||
$builder->orderBy('definition_id');
|
||||
@@ -291,11 +298,30 @@ class Attribute extends Model
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns an array of attribute definition names and IDs
|
||||
* Gets attribute definitions filtered by type (person or item)
|
||||
*
|
||||
* @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.
|
||||
* @param bool $isPersonAttribute True for person attributes, false for item attributes
|
||||
* @param int $definitionFlags Optional visibility flags to further filter
|
||||
* @return array
|
||||
*/
|
||||
public function getDefinitionsByType(bool $isPersonAttribute, int $definitionFlags = 0): array
|
||||
{
|
||||
$builder = $this->db->table('attribute_definitions');
|
||||
$builder->where('person_attribute', $isPersonAttribute ? 1 : 0);
|
||||
$builder->where('deleted', 0);
|
||||
$builder->where('definition_type <>', GROUP);
|
||||
|
||||
if ($definitionFlags > 0) {
|
||||
$builder->where(new RawSql("definition_flags & $definitionFlags"));
|
||||
}
|
||||
|
||||
$builder->orderBy('definition_name', 'ASC');
|
||||
|
||||
$results = $builder->get()->getResultArray();
|
||||
|
||||
return $this->to_array($results, 'definition_id', 'definition_name');
|
||||
}
|
||||
|
||||
public function get_definition_names(bool $groups = true): array
|
||||
{
|
||||
$builder = $this->db->table('attribute_definitions');
|
||||
@@ -1227,4 +1253,227 @@ class Attribute extends Model
|
||||
$itemsBuilder->update();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets all attributes connected to a person given the person_id
|
||||
*
|
||||
* @param int $personId Person to retrieve attributes for.
|
||||
* @return array Attributes for the person.
|
||||
*/
|
||||
public function getAttributesByPerson(int $personId): array
|
||||
{
|
||||
$builder = $this->db->table('attribute_definitions');
|
||||
$builder->join('attribute_links', 'attribute_links.definition_id = attribute_definitions.definition_id');
|
||||
$builder->where('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$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');
|
||||
}
|
||||
|
||||
/**
|
||||
* Returns whether an attribute_link row exists given a person_id and optionally a definition_id
|
||||
*
|
||||
* @param int $personId ID of the person to check for an associated attribute.
|
||||
* @param int|bool $definitionId Attribute definition ID to check.
|
||||
* @return bool Returns true if at least one attribute_link exists or false if no attributes exist for that person and attribute.
|
||||
*/
|
||||
public function personAttributeLinkExists(int $personId, int|bool $definitionId = false): bool
|
||||
{
|
||||
$builder = $this->db->table('attribute_links');
|
||||
$builder->where('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
|
||||
if ($definitionId) {
|
||||
$builder->where('definition_id', $definitionId);
|
||||
} else {
|
||||
$builder->where('definition_id IS NOT NULL');
|
||||
$builder->where('attribute_id', null);
|
||||
}
|
||||
$results = $builder->countAllResults();
|
||||
return $results > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Inserts or updates an attribute link for a person
|
||||
*
|
||||
* @param int $personId
|
||||
* @param int $definitionId
|
||||
* @param int $attributeId
|
||||
* @return bool True if the attribute link was saved successfully, false otherwise.
|
||||
*/
|
||||
public function savePersonAttributeLink(int $personId, int $definitionId, int $attributeId): bool
|
||||
{
|
||||
$this->db->transStart();
|
||||
|
||||
$builder = $this->db->table('attribute_links');
|
||||
|
||||
if ($this->personAttributeLinkExists($personId, $definitionId)) {
|
||||
$builder->set(['attribute_id' => $attributeId]);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
$builder->where('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->update();
|
||||
} else {
|
||||
$data = [
|
||||
'attribute_id' => $attributeId,
|
||||
'person_id' => $personId,
|
||||
'definition_id' => $definitionId
|
||||
];
|
||||
$builder->insert($data);
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
return $this->db->transStatus();
|
||||
}
|
||||
|
||||
/**
|
||||
* Deletes attribute links for a person
|
||||
*
|
||||
* @param int $personId
|
||||
* @param int|bool $definitionId
|
||||
* @return bool
|
||||
*/
|
||||
public function deletePersonAttributeLinks(int $personId, int|bool $definitionId = false): bool
|
||||
{
|
||||
$deleteData = ['person_id' => $personId];
|
||||
|
||||
$builder = $this->db->table('attribute_links');
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
|
||||
if (!empty($definitionId)) {
|
||||
$deleteData['definition_id'] = $definitionId;
|
||||
}
|
||||
|
||||
return $builder->delete($deleteData);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the attribute value for a person and definition
|
||||
*
|
||||
* @param int $personId
|
||||
* @param int $definitionId
|
||||
* @return object|null
|
||||
*/
|
||||
public function getPersonAttributeValue(int $personId, int $definitionId): ?object
|
||||
{
|
||||
$builder = $this->db->table('attribute_values');
|
||||
$builder->join('attribute_links', 'attribute_links.attribute_id = attribute_values.attribute_id');
|
||||
$builder->where('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->where('definition_id', $definitionId);
|
||||
$query = $builder->get();
|
||||
|
||||
if ($query->getNumRows() == 1) {
|
||||
return $query->getRow();
|
||||
}
|
||||
|
||||
return $this->getEmptyObject('attribute_values');
|
||||
}
|
||||
|
||||
/**
|
||||
* Saves an attribute value for a person
|
||||
*
|
||||
* @param string $attributeValue
|
||||
* @param int $definitionId
|
||||
* @param int $personId
|
||||
* @param int|bool $attributeId
|
||||
* @param string $definitionType
|
||||
* @return int
|
||||
*/
|
||||
public function savePersonAttributeValue(string $attributeValue, int $definitionId, int $personId, int|bool $attributeId = false, string $definitionType = DROPDOWN): int
|
||||
{
|
||||
$config = config(OSPOS::class)->settings;
|
||||
|
||||
$this->db->transStart();
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
// New Attribute
|
||||
if (empty($attributeId) || empty($personId) || $attributeId == -1) {
|
||||
$attributeId = $this->attributeValueExists($attributeValue, $definitionType);
|
||||
|
||||
if (!$attributeId) {
|
||||
$builder = $this->db->table('attribute_values');
|
||||
$builder->set(["attribute_$dataType" => $attributeValue]);
|
||||
$builder->insert();
|
||||
|
||||
$attributeId = $this->db->insertID();
|
||||
}
|
||||
|
||||
$data = [
|
||||
'attribute_id' => empty($attributeId) ? null : $attributeId,
|
||||
'person_id' => $personId,
|
||||
'definition_id' => $definitionId
|
||||
];
|
||||
|
||||
$builder = $this->db->table('attribute_links');
|
||||
$builder->set($data);
|
||||
$builder->insert();
|
||||
}
|
||||
// Existing Attribute
|
||||
else {
|
||||
$builder = $this->db->table('attribute_values');
|
||||
$builder->set(["attribute_$dataType" => $attributeValue]);
|
||||
$builder->where('attribute_id', $attributeId);
|
||||
$builder->update();
|
||||
}
|
||||
|
||||
$this->db->transComplete();
|
||||
|
||||
return $attributeId;
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets link values for a person given the person_id and visibility flags
|
||||
*
|
||||
* @param int $personId
|
||||
* @param int $definitionFlags
|
||||
* @return ResultInterface
|
||||
*/
|
||||
public function getPersonLinkValues(int $personId, int $definitionFlags): 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('person_id', $personId);
|
||||
$builder->where('item_id', null);
|
||||
$builder->where('sale_id', null);
|
||||
$builder->where('receiving_id', null);
|
||||
$builder->where(new RawSql("definition_flags & $definitionFlags"));
|
||||
|
||||
return $builder->get();
|
||||
}
|
||||
}
|
||||
|
||||
169
app/Views/attributes/person.php
Normal file
169
app/Views/attributes/person.php
Normal file
@@ -0,0 +1,169 @@
|
||||
<?php
|
||||
/**
|
||||
* @var array $definition_names
|
||||
* @var array $definition_values
|
||||
* @var int $person_id
|
||||
* @var array $config
|
||||
*/
|
||||
|
||||
use App\Models\Attribute;
|
||||
?>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Attributes.definition_name'), 'definition_name_label', ['class' => 'control-label col-xs-3']) ?>
|
||||
<div class="col-xs-8">
|
||||
<?= form_dropdown([
|
||||
'name' => 'definition_name',
|
||||
'options' => $definition_names,
|
||||
'selected' => -1,
|
||||
'class' => 'form-control',
|
||||
'id' => 'definition_name'
|
||||
]) ?>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php foreach ($definition_values as $definitionId => $definitionValue) { ?>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(esc($definitionValue['definition_name']), esc($definitionValue['definition_name']), ['class' => 'control-label col-xs-3']) ?>
|
||||
<div class="col-xs-8">
|
||||
<div class="input-group">
|
||||
<?php
|
||||
echo form_hidden("attribute_ids[$definitionId]", strval($definitionValue['attribute_id']));
|
||||
$attributeValue = $definitionValue['attribute_value'];
|
||||
|
||||
switch ($definitionValue['definition_type']) {
|
||||
case DATE:
|
||||
$value = (empty($attributeValue) || empty($attributeValue->attribute_date)) ? NOW : strtotime($attributeValue->attribute_date);
|
||||
echo form_input([
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'value' => to_date($value),
|
||||
'class' => 'form-control input-sm datetime',
|
||||
'data-definition-id' => $definitionId,
|
||||
'readonly' => 'true'
|
||||
]);
|
||||
break;
|
||||
case DROPDOWN:
|
||||
$selectedValue = $definitionValue['selected_value'];
|
||||
echo form_dropdown([
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'options' => $definitionValue['values'],
|
||||
'selected' => $selectedValue,
|
||||
'class' => 'form-control',
|
||||
'data-definition-id' => $definitionId
|
||||
]);
|
||||
break;
|
||||
case TEXT:
|
||||
$value = (empty($attributeValue) || empty($attributeValue->attribute_value)) ? $definitionValue['selected_value'] : $attributeValue->attribute_value;
|
||||
echo form_input([
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'value' => esc($value),
|
||||
'class' => 'form-control valid_chars',
|
||||
'data-definition-id' => $definitionId
|
||||
]);
|
||||
break;
|
||||
case DECIMAL:
|
||||
$value = (empty($attributeValue) || empty($attributeValue->attribute_decimal)) ? $definitionValue['selected_value'] : $attributeValue->attribute_decimal;
|
||||
echo form_input([
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'value' => to_decimals((float)$value),
|
||||
'class' => 'form-control valid_chars',
|
||||
'data-definition-id' => $definitionId
|
||||
]);
|
||||
break;
|
||||
case CHECKBOX:
|
||||
$value = (empty($attributeValue) || empty($attributeValue->attribute_value)) ? $definitionValue['selected_value'] : $attributeValue->attribute_value;
|
||||
|
||||
// Sends 0 if the box is unchecked instead of not sending anything.
|
||||
echo form_input([
|
||||
'type' => 'hidden',
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'id' => "attribute_links[$definitionId]",
|
||||
'value' => 0,
|
||||
'data-definition-id' => $definitionId
|
||||
]);
|
||||
echo form_checkbox([
|
||||
'name' => "attribute_links[$definitionId]",
|
||||
'id' => "attribute_links[$definitionId]",
|
||||
'value' => 1,
|
||||
'checked' => $value == 1,
|
||||
'class' => 'checkbox-inline',
|
||||
'data-definition-id' => $definitionId
|
||||
]);
|
||||
break;
|
||||
}
|
||||
?>
|
||||
<span class="input-group-addon input-sm btn btn-default remove_attribute_btn">
|
||||
<span class="glyphicon glyphicon-trash"></span>
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<?php } ?>
|
||||
|
||||
<script type="text/javascript">
|
||||
(function() {
|
||||
<?= view('partial/datepicker_locale', ['format' => dateformat_bootstrap($config['dateformat'])]) ?>
|
||||
|
||||
var enableDelete = function() {
|
||||
$('.remove_attribute_btn').click(function() {
|
||||
$(this).parents('.form-group').remove();
|
||||
});
|
||||
};
|
||||
|
||||
enableDelete();
|
||||
|
||||
$("input[name*='attribute_links']").change(function() {
|
||||
var definitionId = $(this).data('definition-id');
|
||||
$("input[name='attribute_ids[" + definitionId + "]']").val('');
|
||||
}).autocomplete({
|
||||
source: function(request, response) {
|
||||
$.get('<?= 'attributes/suggestAttribute/' ?>' + this.element.data('definition-id') + '?term=' + request.term, function(data) {
|
||||
return response(data);
|
||||
}, 'json');
|
||||
},
|
||||
appendTo: '.modal-content',
|
||||
select: function(event, ui) {
|
||||
event.preventDefault();
|
||||
$(this).val(ui.item.label);
|
||||
},
|
||||
delay: 10
|
||||
});
|
||||
|
||||
var getDefinitionValues = function() {
|
||||
var result = {};
|
||||
$("[name*='attribute_links']").each(function() {
|
||||
var definitionId = $(this).data('definition-id');
|
||||
var element = $(this);
|
||||
|
||||
// For checkboxes, use the visible checkbox, not the hidden input
|
||||
if (element.attr('type') === 'hidden' && element.siblings('input[type="checkbox"]').length > 0) {
|
||||
// Skip hidden inputs that have a corresponding checkbox
|
||||
return;
|
||||
}
|
||||
|
||||
// For checkboxes, get the checked state
|
||||
if (element.attr('type') === 'checkbox') {
|
||||
result[definitionId] = element.prop('checked') ? '1' : '0';
|
||||
} else {
|
||||
result[definitionId] = element.val();
|
||||
}
|
||||
});
|
||||
return result;
|
||||
};
|
||||
|
||||
var refresh = function() {
|
||||
var definitionId = $("#definition_name option:selected").val();
|
||||
var attributeValues = getDefinitionValues();
|
||||
attributeValues[definitionId] = '';
|
||||
$('#person_attributes').load(window.location.href, {
|
||||
'definition_ids': JSON.stringify(attributeValues)
|
||||
}, enableDelete);
|
||||
};
|
||||
|
||||
$('#definition_name').change(function() {
|
||||
refresh();
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
@@ -44,6 +44,12 @@
|
||||
|
||||
<?= view('people/form_basic_info') ?>
|
||||
|
||||
<div id="person_attributes">
|
||||
<script type="text/javascript">
|
||||
$('#person_attributes').load('<?= "customers/attributes/$person_info->person_id" ?>');
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Customers.discount_type'), 'discount_type', ['class' => 'control-label col-xs-3']) ?>
|
||||
<div class="col-xs-8">
|
||||
|
||||
@@ -29,6 +29,12 @@
|
||||
<div class="tab-pane fade in active" id="employee_basic_info">
|
||||
<fieldset>
|
||||
<?= view('people/form_basic_info') ?>
|
||||
|
||||
<div id="person_attributes">
|
||||
<script type="text/javascript">
|
||||
$('#person_attributes').load('<?= "employees/attributes/$person_info->person_id" ?>');
|
||||
</script>
|
||||
</div>
|
||||
</fieldset>
|
||||
</div>
|
||||
|
||||
|
||||
@@ -45,6 +45,12 @@
|
||||
|
||||
<?= view('people/form_basic_info') ?>
|
||||
|
||||
<div id="person_attributes">
|
||||
<script type="text/javascript">
|
||||
$('#person_attributes').load('<?= "suppliers/attributes/$person_info->person_id" ?>');
|
||||
</script>
|
||||
</div>
|
||||
|
||||
<div class="form-group form-group-sm">
|
||||
<?= form_label(lang('Suppliers.account_number'), 'account_number', ['class' => 'control-label col-xs-3']) ?>
|
||||
<div class="col-xs-8">
|
||||
|
||||
Reference in New Issue
Block a user