Add support for custom fields on customers (#1133)
This commit is contained in:
parent
aa10b57b3a
commit
e6b3ffd66b
47 changed files with 769 additions and 434 deletions
|
@ -43,6 +43,7 @@ developers to maintain and readjust their custom modifications on the main proje
|
|||
- Create new layout structure for the markup, so that common HTML markup is being reused (#1152)
|
||||
- Have an option to hide customer data fields during booking (#1081)
|
||||
- Add a SECURITY.md file to the repository (#1122)
|
||||
- Add support for custom fields on customers (#1133)
|
||||
|
||||
### Changed
|
||||
|
||||
|
|
|
@ -18,7 +18,8 @@
|
|||
*
|
||||
* @package Controllers
|
||||
*/
|
||||
class Customers extends EA_Controller {
|
||||
class Customers extends EA_Controller
|
||||
{
|
||||
/**
|
||||
* Customers constructor.
|
||||
*/
|
||||
|
@ -49,10 +50,8 @@ class Customers extends EA_Controller {
|
|||
|
||||
$user_id = session('user_id');
|
||||
|
||||
if (cannot('view', PRIV_CUSTOMERS))
|
||||
{
|
||||
if ($user_id)
|
||||
{
|
||||
if (cannot('view', PRIV_CUSTOMERS)) {
|
||||
if ($user_id) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -75,8 +74,7 @@ class Customers extends EA_Controller {
|
|||
|
||||
$secretary_providers = [];
|
||||
|
||||
if ($role_slug === DB_SLUG_SECRETARY)
|
||||
{
|
||||
if ($role_slug === DB_SLUG_SECRETARY) {
|
||||
$secretary = $this->secretaries_model->find($user_id);
|
||||
|
||||
$secretary_providers = $secretary['providers'];
|
||||
|
@ -88,7 +86,7 @@ class Customers extends EA_Controller {
|
|||
'date_format' => $date_format,
|
||||
'time_format' => $time_format,
|
||||
'timezones' => $this->timezones->to_array(),
|
||||
'secretary_providers' => $secretary_providers,
|
||||
'secretary_providers' => $secretary_providers
|
||||
]);
|
||||
|
||||
html_vars([
|
||||
|
@ -105,21 +103,45 @@ class Customers extends EA_Controller {
|
|||
'require_address' => $require_address,
|
||||
'require_city' => $require_city,
|
||||
'require_zip_code' => $require_zip_code,
|
||||
'available_languages' => config('available_languages'),
|
||||
'available_languages' => config('available_languages')
|
||||
]);
|
||||
|
||||
$this->load->view('pages/customers');
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a customer.
|
||||
*/
|
||||
public function find()
|
||||
{
|
||||
try {
|
||||
if (cannot('view', PRIV_CUSTOMERS)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$user_id = session('user_id');
|
||||
|
||||
$customer_id = request('customer_id');
|
||||
|
||||
if (!$this->permissions->has_customer_access($user_id, $customer_id)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$customer = $this->customers_model->find($customer_id);
|
||||
|
||||
json_response($customer);
|
||||
} catch (Throwable $e) {
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Filter customers by the provided keyword.
|
||||
*/
|
||||
public function search()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('view', PRIV_CUSTOMERS))
|
||||
{
|
||||
try {
|
||||
if (cannot('view', PRIV_CUSTOMERS)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -135,10 +157,8 @@ class Customers extends EA_Controller {
|
|||
|
||||
$user_id = session('user_id');
|
||||
|
||||
foreach ($customers as $index => &$customer)
|
||||
{
|
||||
if ( ! $this->permissions->has_customer_access($user_id, $customer['id']))
|
||||
{
|
||||
foreach ($customers as $index => &$customer) {
|
||||
if (!$this->permissions->has_customer_access($user_id, $customer['id'])) {
|
||||
unset($customers[$index]);
|
||||
|
||||
continue;
|
||||
|
@ -146,21 +166,15 @@ class Customers extends EA_Controller {
|
|||
|
||||
$appointments = $this->appointments_model->get(['id_users_customer' => $customer['id']]);
|
||||
|
||||
foreach ($appointments as &$appointment)
|
||||
{
|
||||
$this->appointments_model->load($appointment, [
|
||||
'service',
|
||||
'provider',
|
||||
]);
|
||||
foreach ($appointments as &$appointment) {
|
||||
$this->appointments_model->load($appointment, ['service', 'provider']);
|
||||
}
|
||||
|
||||
$customer['appointments'] = $appointments;
|
||||
}
|
||||
|
||||
json_response(array_values($customers));
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
} catch (Throwable $e) {
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
@ -170,15 +184,12 @@ class Customers extends EA_Controller {
|
|||
*/
|
||||
public function store()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('add', PRIV_CUSTOMERS))
|
||||
{
|
||||
try {
|
||||
if (cannot('add', PRIV_CUSTOMERS)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
if (session('role_slug') !== DB_SLUG_ADMIN && setting('limit_customer_visibility'))
|
||||
{
|
||||
if (session('role_slug') !== DB_SLUG_ADMIN && setting('limit_customer_visibility')) {
|
||||
abort(403);
|
||||
}
|
||||
|
||||
|
@ -196,6 +207,11 @@ class Customers extends EA_Controller {
|
|||
'notes',
|
||||
'timezone',
|
||||
'language',
|
||||
'custom_field_1',
|
||||
'custom_field_2',
|
||||
'custom_field_3',
|
||||
'custom_field_4',
|
||||
'custom_field_5'
|
||||
]);
|
||||
|
||||
$customer_id = $this->customers_model->save($customer);
|
||||
|
@ -205,12 +221,10 @@ class Customers extends EA_Controller {
|
|||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_SAVE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'success' => true,
|
||||
'id' => $customer_id
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
} catch (Throwable $e) {
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
@ -220,10 +234,8 @@ class Customers extends EA_Controller {
|
|||
*/
|
||||
public function update()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('edit', PRIV_CUSTOMERS))
|
||||
{
|
||||
try {
|
||||
if (cannot('edit', PRIV_CUSTOMERS)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -231,8 +243,7 @@ class Customers extends EA_Controller {
|
|||
|
||||
$customer = request('customer');
|
||||
|
||||
if ( ! $this->permissions->has_customer_access($user_id, $customer['id']))
|
||||
{
|
||||
if (!$this->permissions->has_customer_access($user_id, $customer['id'])) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -249,6 +260,11 @@ class Customers extends EA_Controller {
|
|||
'notes',
|
||||
'timezone',
|
||||
'language',
|
||||
'custom_field_1',
|
||||
'custom_field_2',
|
||||
'custom_field_3',
|
||||
'custom_field_4',
|
||||
'custom_field_5'
|
||||
]);
|
||||
|
||||
$customer_id = $this->customers_model->save($customer);
|
||||
|
@ -258,12 +274,10 @@ class Customers extends EA_Controller {
|
|||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_SAVE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'success' => true,
|
||||
'id' => $customer_id
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
} catch (Throwable $e) {
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
@ -273,10 +287,8 @@ class Customers extends EA_Controller {
|
|||
*/
|
||||
public function destroy()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('delete', PRIV_CUSTOMERS))
|
||||
{
|
||||
try {
|
||||
if (cannot('delete', PRIV_CUSTOMERS)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -284,8 +296,7 @@ class Customers extends EA_Controller {
|
|||
|
||||
$customer_id = request('customer_id');
|
||||
|
||||
if ( ! $this->permissions->has_customer_access($user_id, $customer_id))
|
||||
{
|
||||
if (!$this->permissions->has_customer_access($user_id, $customer_id)) {
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
|
@ -296,42 +307,9 @@ class Customers extends EA_Controller {
|
|||
$this->webhooks_client->trigger(WEBHOOK_CUSTOMER_DELETE, $customer);
|
||||
|
||||
json_response([
|
||||
'success' => TRUE,
|
||||
'success' => true
|
||||
]);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Find a customer.
|
||||
*/
|
||||
public function find()
|
||||
{
|
||||
try
|
||||
{
|
||||
if (cannot('view', PRIV_CUSTOMERS))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$user_id = session('user_id');
|
||||
|
||||
$customer_id = request('customer_id');
|
||||
|
||||
if ( ! $this->permissions->has_customer_access($user_id, $customer_id))
|
||||
{
|
||||
abort(403, 'Forbidden');
|
||||
}
|
||||
|
||||
$customer = $this->customers_model->find($customer_id);
|
||||
|
||||
json_response($customer);
|
||||
}
|
||||
catch (Throwable $e)
|
||||
{
|
||||
} catch (Throwable $e) {
|
||||
json_exception($e);
|
||||
}
|
||||
}
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -446,5 +446,7 @@ $lang['blocked_periods'] = 'Blocked Periods';
|
|||
$lang['blocked_period_save'] = 'Blocked Period Save';
|
||||
$lang['blocked_period_delete'] = 'Blocked Period Delete';
|
||||
$lang['blocked_periods_hint'] = 'Define periods of time where public bookings will be disabled for all providers (e.g. closed dates, holidays etc.).';
|
||||
$lang['auxiliary_field'] = 'Auxiliary Field';
|
||||
$lang['custom_field'] = 'Custom Field';
|
||||
$lang['custom_fields'] = 'Custom Fields';
|
||||
$lang['label'] = 'Label';
|
||||
// End
|
||||
|
|
|
@ -0,0 +1,56 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.4.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
class Migration_Add_custom_fields_columns_to_users_table extends EA_Migration
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private const FIELD_NUMBER = 5;
|
||||
|
||||
/**
|
||||
* Upgrade method.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
for ($i = self::FIELD_NUMBER; $i > 0; $i--) {
|
||||
$field_name = 'custom_field_' . $i;
|
||||
|
||||
if (!$this->db->field_exists($field_name, 'users')) {
|
||||
$fields = [
|
||||
$field_name => [
|
||||
'type' => 'TEXT',
|
||||
'null' => true,
|
||||
'after' => 'language'
|
||||
]
|
||||
];
|
||||
|
||||
$this->dbforge->add_column('users', $fields);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade method.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
for ($i = self::FIELD_NUMBER; $i > 0; $i--) {
|
||||
$field_name = 'custom_fields_' . $i;
|
||||
|
||||
if ($this->db->field_exists($field_name, 'users')) {
|
||||
$this->dbforge->drop_column('users', $field_name);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -0,0 +1,65 @@
|
|||
<?php defined('BASEPATH') or exit('No direct script access allowed');
|
||||
|
||||
/* ----------------------------------------------------------------------------
|
||||
* Easy!Appointments - Online Appointment Scheduler
|
||||
*
|
||||
* @package EasyAppointments
|
||||
* @author A.Tselegidis <alextselegidis@gmail.com>
|
||||
* @copyright Copyright (c) Alex Tselegidis
|
||||
* @license https://opensource.org/licenses/GPL-3.0 - GPLv3
|
||||
* @link https://easyappointments.org
|
||||
* @since v1.4.0
|
||||
* ---------------------------------------------------------------------------- */
|
||||
|
||||
class Migration_Insert_custom_field_rows_to_settings_table extends EA_Migration
|
||||
{
|
||||
/**
|
||||
* @var int
|
||||
*/
|
||||
private const FIELD_NUMBER = 5;
|
||||
|
||||
private const SETTINGS = [
|
||||
'display' => '0',
|
||||
'require' => '0',
|
||||
'label' => ''
|
||||
];
|
||||
|
||||
/**
|
||||
* Upgrade method.
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
for ($i = 1; $i <= self::FIELD_NUMBER; $i++) {
|
||||
$field_name = 'custom_field_' . $i;
|
||||
|
||||
foreach (self::SETTINGS as $name => $default_value) {
|
||||
$setting_name = $name . '_' . $field_name;
|
||||
|
||||
if (!$this->db->get_where('settings', ['name' => $setting_name])->num_rows()) {
|
||||
$this->db->insert('settings', [
|
||||
'name' => $setting_name,
|
||||
'value' => $default_value
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Downgrade method.
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
for ($i = 1; $i >= self::FIELD_NUMBER; $i++) {
|
||||
$field_name = 'custom_field_' . $i;
|
||||
|
||||
foreach (self::SETTINGS as $name => $default_value) {
|
||||
$setting_name = $name . '_' . $field_name;
|
||||
|
||||
if ($this->db->get_where('settings', ['name' => $setting_name])->num_rows()) {
|
||||
$this->db->delete('settings', ['name' => $setting_name]);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
|
@ -18,13 +18,14 @@
|
|||
*
|
||||
* @package Models
|
||||
*/
|
||||
class Customers_model extends EA_Model {
|
||||
class Customers_model extends EA_Model
|
||||
{
|
||||
/**
|
||||
* @var array
|
||||
*/
|
||||
protected array $casts = [
|
||||
'id' => 'integer',
|
||||
'id_roles' => 'integer',
|
||||
'id_roles' => 'integer'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -42,7 +43,12 @@ class Customers_model extends EA_Model {
|
|||
'zip' => 'zip_code',
|
||||
'timezone' => 'timezone',
|
||||
'language' => 'language',
|
||||
'notes' => 'notes',
|
||||
'customField1' => 'custom_field_1',
|
||||
'customField2' => 'custom_field_2',
|
||||
'customField3' => 'custom_field_3',
|
||||
'customField4' => 'custom_field_4',
|
||||
'customField5' => 'custom_field_5',
|
||||
'notes' => 'notes'
|
||||
];
|
||||
|
||||
/**
|
||||
|
@ -58,17 +64,13 @@ class Customers_model extends EA_Model {
|
|||
{
|
||||
$this->validate($customer);
|
||||
|
||||
if ($this->exists($customer) && empty($customer['id']))
|
||||
{
|
||||
if ($this->exists($customer) && empty($customer['id'])) {
|
||||
$customer['id'] = $this->find_record_id($customer);
|
||||
}
|
||||
|
||||
if (empty($customer['id']))
|
||||
{
|
||||
if (empty($customer['id'])) {
|
||||
return $this->insert($customer);
|
||||
}
|
||||
else
|
||||
{
|
||||
} else {
|
||||
return $this->update($customer);
|
||||
}
|
||||
}
|
||||
|
@ -83,13 +85,13 @@ class Customers_model extends EA_Model {
|
|||
public function validate(array $customer)
|
||||
{
|
||||
// If a customer ID is provided then check whether the record really exists in the database.
|
||||
if ( ! empty($customer['id']))
|
||||
{
|
||||
if (!empty($customer['id'])) {
|
||||
$count = $this->db->get_where('users', ['id' => $customer['id']])->num_rows();
|
||||
|
||||
if ( ! $count)
|
||||
{
|
||||
throw new InvalidArgumentException('The provided customer ID does not exist in the database: ' . $customer['id']);
|
||||
if (!$count) {
|
||||
throw new InvalidArgumentException(
|
||||
'The provided customer ID does not exist in the database: ' . $customer['id']
|
||||
);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -103,31 +105,27 @@ class Customers_model extends EA_Model {
|
|||
$require_zip_code = filter_var(setting('require_zip_code'), FILTER_VALIDATE_BOOLEAN);
|
||||
|
||||
if (
|
||||
(empty($customer['first_name']) && $require_first_name)
|
||||
|| (empty($customer['last_name']) && $require_last_name)
|
||||
|| (empty($customer['email']) && $require_email)
|
||||
|| (empty($customer['phone_number']) && $require_phone_number)
|
||||
|| (empty($customer['address']) && $require_address)
|
||||
|| (empty($customer['city']) && $require_city)
|
||||
|| (empty($customer['zip_code']) && $require_zip_code)
|
||||
)
|
||||
{
|
||||
throw new InvalidArgumentException('Not all required fields are provided: ' . print_r($customer, TRUE));
|
||||
(empty($customer['first_name']) && $require_first_name) ||
|
||||
(empty($customer['last_name']) && $require_last_name) ||
|
||||
(empty($customer['email']) && $require_email) ||
|
||||
(empty($customer['phone_number']) && $require_phone_number) ||
|
||||
(empty($customer['address']) && $require_address) ||
|
||||
(empty($customer['city']) && $require_city) ||
|
||||
(empty($customer['zip_code']) && $require_zip_code)
|
||||
) {
|
||||
throw new InvalidArgumentException('Not all required fields are provided: ' . print_r($customer, true));
|
||||
}
|
||||
|
||||
if ( ! empty($customer['email']))
|
||||
{
|
||||
if (!empty($customer['email'])) {
|
||||
// Validate the email address.
|
||||
if ( ! filter_var($customer['email'], FILTER_VALIDATE_EMAIL))
|
||||
{
|
||||
if (!filter_var($customer['email'], FILTER_VALIDATE_EMAIL)) {
|
||||
throw new InvalidArgumentException('Invalid email address provided: ' . $customer['email']);
|
||||
}
|
||||
|
||||
// Make sure the email address is unique.
|
||||
$customer_id = $customer['id'] ?? NULL;
|
||||
$customer_id = $customer['id'] ?? null;
|
||||
|
||||
$count = $this
|
||||
->db
|
||||
$count = $this->db
|
||||
->select()
|
||||
->from('users')
|
||||
->join('roles', 'roles.id = users.id_roles', 'inner')
|
||||
|
@ -137,11 +135,121 @@ class Customers_model extends EA_Model {
|
|||
->get()
|
||||
->num_rows();
|
||||
|
||||
if ($count > 0)
|
||||
if ($count > 0) {
|
||||
throw new InvalidArgumentException(
|
||||
'The provided email address is already in use, please use a different one.'
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all customers that match the provided criteria.
|
||||
*
|
||||
* @param array|string|null $where Where conditions.
|
||||
* @param int|null $limit Record limit.
|
||||
* @param int|null $offset Record offset.
|
||||
* @param string|null $order_by Order by.
|
||||
*
|
||||
* @return array Returns an array of customers.
|
||||
*/
|
||||
public function get(
|
||||
array|string $where = null,
|
||||
int $limit = null,
|
||||
int $offset = null,
|
||||
string $order_by = null
|
||||
): array {
|
||||
$role_id = $this->get_customer_role_id();
|
||||
|
||||
if ($where !== null) {
|
||||
$this->db->where($where);
|
||||
}
|
||||
|
||||
if ($order_by !== null) {
|
||||
$this->db->order_by($order_by);
|
||||
}
|
||||
|
||||
$customers = $this->db->get_where('users', ['id_roles' => $role_id], $limit, $offset)->result_array();
|
||||
|
||||
foreach ($customers as &$customer) {
|
||||
$this->cast($customer);
|
||||
}
|
||||
|
||||
return $customers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer role ID.
|
||||
*
|
||||
* @return int Returns the role ID.
|
||||
*/
|
||||
public function get_customer_role_id(): int
|
||||
{
|
||||
throw new InvalidArgumentException('The provided email address is already in use, please use a different one.');
|
||||
$role = $this->db->get_where('roles', ['slug' => DB_SLUG_CUSTOMER])->row_array();
|
||||
|
||||
if (empty($role)) {
|
||||
throw new RuntimeException('The customer role was not found in the database.');
|
||||
}
|
||||
|
||||
return $role['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a particular customer record already exists in the database.
|
||||
*
|
||||
* @param array $customer Associative array with the customer data.
|
||||
*
|
||||
* @return bool Returns whether there is a record matching the provided one or not.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function exists(array $customer): bool
|
||||
{
|
||||
if (empty($customer['email'])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
$count = $this->db
|
||||
->select()
|
||||
->from('users')
|
||||
->join('roles', 'roles.id = users.id_roles', 'inner')
|
||||
->where('users.email', $customer['email'])
|
||||
->where('roles.slug', DB_SLUG_CUSTOMER)
|
||||
->get()
|
||||
->num_rows();
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the record ID of a customer.
|
||||
*
|
||||
* @param array $customer Associative array with the customer data.
|
||||
*
|
||||
* @return int Returns the ID of the record that matches the provided argument.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function find_record_id(array $customer): int
|
||||
{
|
||||
if (empty($customer['email'])) {
|
||||
throw new InvalidArgumentException('The customer email was not provided: ' . print_r($customer, true));
|
||||
}
|
||||
|
||||
$customer = $this->db
|
||||
->select('users.id')
|
||||
->from('users')
|
||||
->join('roles', 'roles.id = users.id_roles', 'inner')
|
||||
->where('users.email', $customer['email'])
|
||||
->where('roles.slug', DB_SLUG_CUSTOMER)
|
||||
->get()
|
||||
->row_array();
|
||||
|
||||
if (empty($customer)) {
|
||||
throw new InvalidArgumentException('Could not find customer record id.');
|
||||
}
|
||||
|
||||
return (int) $customer['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -159,8 +267,7 @@ class Customers_model extends EA_Model {
|
|||
$customer['update_datetime'] = date('Y-m-d H:i:s');
|
||||
$customer['id_roles'] = $this->get_customer_role_id();
|
||||
|
||||
if ( ! $this->db->insert('users', $customer))
|
||||
{
|
||||
if (!$this->db->insert('users', $customer)) {
|
||||
throw new RuntimeException('Could not insert customer.');
|
||||
}
|
||||
|
||||
|
@ -180,8 +287,7 @@ class Customers_model extends EA_Model {
|
|||
{
|
||||
$customer['update_datetime'] = date('Y-m-d H:i:s');
|
||||
|
||||
if ( ! $this->db->update('users', $customer, ['id' => $customer['id']]))
|
||||
{
|
||||
if (!$this->db->update('users', $customer, ['id' => $customer['id']])) {
|
||||
throw new RuntimeException('Could not update customer.');
|
||||
}
|
||||
|
||||
|
@ -211,9 +317,10 @@ class Customers_model extends EA_Model {
|
|||
{
|
||||
$customer = $this->db->get_where('users', ['id' => $customer_id])->row_array();
|
||||
|
||||
if ( ! $customer)
|
||||
{
|
||||
throw new InvalidArgumentException('The provided customer ID was not found in the database: ' . $customer_id);
|
||||
if (!$customer) {
|
||||
throw new InvalidArgumentException(
|
||||
'The provided customer ID was not found in the database: ' . $customer_id
|
||||
);
|
||||
}
|
||||
|
||||
$this->cast($customer);
|
||||
|
@ -233,22 +340,21 @@ class Customers_model extends EA_Model {
|
|||
*/
|
||||
public function value(int $customer_id, string $field): mixed
|
||||
{
|
||||
if (empty($field))
|
||||
{
|
||||
if (empty($field)) {
|
||||
throw new InvalidArgumentException('The field argument is cannot be empty.');
|
||||
}
|
||||
|
||||
if (empty($customer_id))
|
||||
{
|
||||
if (empty($customer_id)) {
|
||||
throw new InvalidArgumentException('The customer ID argument cannot be empty.');
|
||||
}
|
||||
|
||||
// Check whether the customer exists.
|
||||
$query = $this->db->get_where('users', ['id' => $customer_id]);
|
||||
|
||||
if ( ! $query->num_rows())
|
||||
{
|
||||
throw new InvalidArgumentException('The provided customer ID was not found in the database: ' . $customer_id);
|
||||
if (!$query->num_rows()) {
|
||||
throw new InvalidArgumentException(
|
||||
'The provided customer ID was not found in the database: ' . $customer_id
|
||||
);
|
||||
}
|
||||
|
||||
// Check if the required field is part of the customer data.
|
||||
|
@ -256,128 +362,13 @@ class Customers_model extends EA_Model {
|
|||
|
||||
$this->cast($customer);
|
||||
|
||||
if ( ! array_key_exists($field, $customer))
|
||||
{
|
||||
if (!array_key_exists($field, $customer)) {
|
||||
throw new InvalidArgumentException('The requested field was not found in the customer data: ' . $field);
|
||||
}
|
||||
|
||||
return $customer[$field];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get all customers that match the provided criteria.
|
||||
*
|
||||
* @param array|string|null $where Where conditions.
|
||||
* @param int|null $limit Record limit.
|
||||
* @param int|null $offset Record offset.
|
||||
* @param string|null $order_by Order by.
|
||||
*
|
||||
* @return array Returns an array of customers.
|
||||
*/
|
||||
public function get(array|string $where = NULL, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array
|
||||
{
|
||||
$role_id = $this->get_customer_role_id();
|
||||
|
||||
if ($where !== NULL)
|
||||
{
|
||||
$this->db->where($where);
|
||||
}
|
||||
|
||||
if ($order_by !== NULL)
|
||||
{
|
||||
$this->db->order_by($order_by);
|
||||
}
|
||||
|
||||
$customers = $this->db->get_where('users', ['id_roles' => $role_id], $limit, $offset)->result_array();
|
||||
|
||||
foreach ($customers as &$customer)
|
||||
{
|
||||
$this->cast($customer);
|
||||
}
|
||||
|
||||
return $customers;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the customer role ID.
|
||||
*
|
||||
* @return int Returns the role ID.
|
||||
*/
|
||||
public function get_customer_role_id(): int
|
||||
{
|
||||
$role = $this->db->get_where('roles', ['slug' => DB_SLUG_CUSTOMER])->row_array();
|
||||
|
||||
if (empty($role))
|
||||
{
|
||||
throw new RuntimeException('The customer role was not found in the database.');
|
||||
}
|
||||
|
||||
return $role['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Check if a particular customer record already exists in the database.
|
||||
*
|
||||
* @param array $customer Associative array with the customer data.
|
||||
*
|
||||
* @return bool Returns whether there is a record matching the provided one or not.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function exists(array $customer): bool
|
||||
{
|
||||
if (empty($customer['email']))
|
||||
{
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
$count = $this
|
||||
->db
|
||||
->select()
|
||||
->from('users')
|
||||
->join('roles', 'roles.id = users.id_roles', 'inner')
|
||||
->where('users.email', $customer['email'])
|
||||
->where('roles.slug', DB_SLUG_CUSTOMER)
|
||||
->get()
|
||||
->num_rows();
|
||||
|
||||
return $count > 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* Find the record ID of a customer.
|
||||
*
|
||||
* @param array $customer Associative array with the customer data.
|
||||
*
|
||||
* @return int Returns the ID of the record that matches the provided argument.
|
||||
*
|
||||
* @throws InvalidArgumentException
|
||||
*/
|
||||
public function find_record_id(array $customer): int
|
||||
{
|
||||
if (empty($customer['email']))
|
||||
{
|
||||
throw new InvalidArgumentException('The customer email was not provided: ' . print_r($customer, TRUE));
|
||||
}
|
||||
|
||||
$customer = $this
|
||||
->db
|
||||
->select('users.id')
|
||||
->from('users')
|
||||
->join('roles', 'roles.id = users.id_roles', 'inner')
|
||||
->where('users.email', $customer['email'])
|
||||
->where('roles.slug', DB_SLUG_CUSTOMER)
|
||||
->get()
|
||||
->row_array();
|
||||
|
||||
if (empty($customer))
|
||||
{
|
||||
throw new InvalidArgumentException('Could not find customer record id.');
|
||||
}
|
||||
|
||||
return (int)$customer['id'];
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the query builder interface, configured for use with the users (customer-filtered) table.
|
||||
*
|
||||
|
@ -400,12 +391,11 @@ class Customers_model extends EA_Model {
|
|||
*
|
||||
* @return array Returns an array of customers.
|
||||
*/
|
||||
public function search(string $keyword, int $limit = NULL, int $offset = NULL, string $order_by = NULL): array
|
||||
public function search(string $keyword, int $limit = null, int $offset = null, string $order_by = null): array
|
||||
{
|
||||
$role_id = $this->get_customer_role_id();
|
||||
|
||||
$customers = $this
|
||||
->db
|
||||
$customers = $this->db
|
||||
->select()
|
||||
->from('users')
|
||||
->where('id_roles', $role_id)
|
||||
|
@ -428,8 +418,7 @@ class Customers_model extends EA_Model {
|
|||
->get()
|
||||
->result_array();
|
||||
|
||||
foreach ($customers as &$customer)
|
||||
{
|
||||
foreach ($customers as &$customer) {
|
||||
$this->cast($customer);
|
||||
}
|
||||
|
||||
|
@ -457,7 +446,7 @@ class Customers_model extends EA_Model {
|
|||
public function api_encode(array &$customer)
|
||||
{
|
||||
$encoded_resource = [
|
||||
'id' => array_key_exists('id', $customer) ? (int)$customer['id'] : NULL,
|
||||
'id' => array_key_exists('id', $customer) ? (int) $customer['id'] : null,
|
||||
'firstName' => $customer['first_name'],
|
||||
'lastName' => $customer['last_name'],
|
||||
'email' => $customer['email'],
|
||||
|
@ -467,6 +456,11 @@ class Customers_model extends EA_Model {
|
|||
'zip' => $customer['zip_code'],
|
||||
'notes' => $customer['notes'],
|
||||
'timezone' => $customer['timezone'],
|
||||
'customField1' => $customer['custom_field_1'],
|
||||
'customField2' => $customer['custom_field_2'],
|
||||
'customField3' => $customer['custom_field_3'],
|
||||
'customField4' => $customer['custom_field_4'],
|
||||
'customField5' => $customer['custom_field_5']
|
||||
];
|
||||
|
||||
$customer = $encoded_resource;
|
||||
|
@ -478,52 +472,67 @@ class Customers_model extends EA_Model {
|
|||
* @param array $customer API resource.
|
||||
* @param array|null $base Base customer data to be overwritten with the provided values (useful for updates).
|
||||
*/
|
||||
public function api_decode(array &$customer, array $base = NULL)
|
||||
public function api_decode(array &$customer, array $base = null)
|
||||
{
|
||||
$decoded_resource = $base ?: [];
|
||||
|
||||
if (array_key_exists('id', $customer))
|
||||
{
|
||||
if (array_key_exists('id', $customer)) {
|
||||
$decoded_resource['id'] = $customer['id'];
|
||||
}
|
||||
|
||||
if (array_key_exists('firstName', $customer))
|
||||
{
|
||||
if (array_key_exists('firstName', $customer)) {
|
||||
$decoded_resource['first_name'] = $customer['firstName'];
|
||||
}
|
||||
|
||||
if (array_key_exists('lastName', $customer))
|
||||
{
|
||||
if (array_key_exists('lastName', $customer)) {
|
||||
$decoded_resource['last_name'] = $customer['lastName'];
|
||||
}
|
||||
|
||||
if (array_key_exists('email', $customer))
|
||||
{
|
||||
if (array_key_exists('email', $customer)) {
|
||||
$decoded_resource['email'] = $customer['email'];
|
||||
}
|
||||
|
||||
if (array_key_exists('phone', $customer))
|
||||
{
|
||||
if (array_key_exists('phone', $customer)) {
|
||||
$decoded_resource['phone_number'] = $customer['phone'];
|
||||
}
|
||||
|
||||
if (array_key_exists('address', $customer))
|
||||
{
|
||||
if (array_key_exists('address', $customer)) {
|
||||
$decoded_resource['address'] = $customer['address'];
|
||||
}
|
||||
|
||||
if (array_key_exists('city', $customer))
|
||||
{
|
||||
if (array_key_exists('city', $customer)) {
|
||||
$decoded_resource['city'] = $customer['city'];
|
||||
}
|
||||
|
||||
if (array_key_exists('zip', $customer))
|
||||
{
|
||||
if (array_key_exists('zip', $customer)) {
|
||||
$decoded_resource['zip_code'] = $customer['zip'];
|
||||
}
|
||||
|
||||
if (array_key_exists('notes', $customer))
|
||||
{
|
||||
if (array_key_exists('language', $customer)) {
|
||||
$decoded_resource['language'] = $customer['language'];
|
||||
}
|
||||
|
||||
if (array_key_exists('customField1', $customer)) {
|
||||
$decoded_resource['custom_field_1'] = $customer['customField1'];
|
||||
}
|
||||
|
||||
if (array_key_exists('customField2', $customer)) {
|
||||
$decoded_resource['custom_field_2'] = $customer['customField2'];
|
||||
}
|
||||
|
||||
if (array_key_exists('customField3', $customer)) {
|
||||
$decoded_resource['custom_field_3'] = $customer['customField3'];
|
||||
}
|
||||
|
||||
if (array_key_exists('customField4', $customer)) {
|
||||
$decoded_resource['custom_field_4'] = $customer['customField4'];
|
||||
}
|
||||
|
||||
if (array_key_exists('customField5', $customer)) {
|
||||
$decoded_resource['custom_field_5'] = $customer['customField5'];
|
||||
}
|
||||
|
||||
if (array_key_exists('notes', $customer)) {
|
||||
$decoded_resource['notes'] = $customer['notes'];
|
||||
}
|
||||
|
||||
|
|
|
@ -43,27 +43,21 @@
|
|||
<?php
|
||||
// Group services by category, only if there is at least one service
|
||||
// with a parent category.
|
||||
$has_category = FALSE;
|
||||
$has_category = false;
|
||||
|
||||
foreach ($available_services as $service)
|
||||
{
|
||||
if ( ! empty($service['category_id']))
|
||||
{
|
||||
$has_category = TRUE;
|
||||
foreach ($available_services as $service) {
|
||||
if (!empty($service['category_id'])) {
|
||||
$has_category = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if ($has_category)
|
||||
{
|
||||
if ($has_category) {
|
||||
$grouped_services = [];
|
||||
|
||||
foreach ($available_services as $service)
|
||||
{
|
||||
if ( ! empty($service['category_id']))
|
||||
{
|
||||
if ( ! isset($grouped_services[$service['category_name']]))
|
||||
{
|
||||
foreach ($available_services as $service) {
|
||||
if (!empty($service['category_id'])) {
|
||||
if (!isset($grouped_services[$service['category_name']])) {
|
||||
$grouped_services[$service['category_name']] = [];
|
||||
}
|
||||
|
||||
|
@ -75,40 +69,39 @@
|
|||
// another iteration only for the uncategorized services.
|
||||
$grouped_services['uncategorized'] = [];
|
||||
|
||||
foreach ($available_services as $service)
|
||||
{
|
||||
if ($service['category_id'] == NULL)
|
||||
{
|
||||
foreach ($available_services as $service) {
|
||||
if ($service['category_id'] == null) {
|
||||
$grouped_services['uncategorized'][] = $service;
|
||||
}
|
||||
}
|
||||
|
||||
foreach ($grouped_services as $key => $group)
|
||||
{
|
||||
$group_label = $key !== 'uncategorized'
|
||||
foreach ($grouped_services as $key => $group) {
|
||||
$group_label =
|
||||
$key !== 'uncategorized'
|
||||
? e($group[0]['category_name'])
|
||||
: 'Uncategorized';
|
||||
|
||||
if (count($group) > 0)
|
||||
{
|
||||
if (count($group) > 0) {
|
||||
echo '<optgroup label="' . $group_label . '">';
|
||||
|
||||
foreach ($group as $service)
|
||||
{
|
||||
echo '<option value="' . $service['id'] . '">'
|
||||
. e($service['name']) . '</option>';
|
||||
foreach ($group as $service) {
|
||||
echo '<option value="' .
|
||||
$service['id'] .
|
||||
'">' .
|
||||
e($service['name']) .
|
||||
'</option>';
|
||||
}
|
||||
|
||||
echo '</optgroup>';
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
foreach ($available_services as $service)
|
||||
{
|
||||
echo '<option value="' . $service['id'] . '">'
|
||||
. e($service['name']) . '</option>';
|
||||
} else {
|
||||
foreach ($available_services as $service) {
|
||||
echo '<option value="' .
|
||||
$service['id'] .
|
||||
'">' .
|
||||
e($service['name']) .
|
||||
'</option>';
|
||||
}
|
||||
}
|
||||
?>
|
||||
|
@ -124,7 +117,7 @@
|
|||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<?php component('color_selection', ['attributes' => 'id="appointment-color"']) ?>
|
||||
<?php component('color_selection', ['attributes' => 'id="appointment-color"']); ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
|
@ -143,7 +136,7 @@
|
|||
<option value="<?= e($appointment_status_option) ?>">
|
||||
<?= e($appointment_status_option) ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -228,7 +221,7 @@
|
|||
<?= lang('first_name') ?>
|
||||
<?php if ($require_first_name): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="first-name"
|
||||
class="<?= $require_first_name ? 'required' : '' ?> form-control"
|
||||
|
@ -240,7 +233,7 @@
|
|||
<?= lang('last_name') ?>
|
||||
<?php if ($require_last_name): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="last-name"
|
||||
class="<?= $require_last_name ? 'required' : '' ?> form-control"
|
||||
|
@ -252,7 +245,7 @@
|
|||
<?= lang('email') ?>
|
||||
<?php if ($require_email): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="email"
|
||||
class="<?= $require_email ? 'required' : '' ?> form-control"
|
||||
|
@ -264,7 +257,7 @@
|
|||
<?= lang('phone_number') ?>
|
||||
<?php if ($require_phone_number): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="phone-number" maxlength="60"
|
||||
class="<?= $require_phone_number ? 'required' : '' ?> form-control"/>
|
||||
|
@ -280,7 +273,7 @@
|
|||
<option value="<?= $available_language ?>">
|
||||
<?= ucfirst($available_language) ?>
|
||||
</option>
|
||||
<?php endforeach ?>
|
||||
<?php endforeach; ?>
|
||||
</select>
|
||||
</div>
|
||||
</div>
|
||||
|
@ -290,7 +283,7 @@
|
|||
<?= lang('address') ?>
|
||||
<?php if ($require_address): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="address"
|
||||
class="<?= $require_address ? 'required' : '' ?> form-control"
|
||||
|
@ -302,7 +295,7 @@
|
|||
<?= lang('city') ?>
|
||||
<?php if ($require_city): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="city"
|
||||
class="<?= $require_city ? 'required' : '' ?> form-control"
|
||||
|
@ -314,7 +307,7 @@
|
|||
<?= lang('zip_code') ?>
|
||||
<?php if ($require_zip_code): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="zip-code"
|
||||
class="<?= $require_zip_code ? 'required' : '' ?> form-control"
|
||||
|
@ -329,7 +322,7 @@
|
|||
<?php component('timezone_dropdown', [
|
||||
'attributes' => 'id="timezone" class="form-control required"',
|
||||
'grouped_timezones' => vars('grouped_timezones')
|
||||
]) ?>
|
||||
]); ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
|
@ -337,12 +330,16 @@
|
|||
<?= lang('notes') ?>
|
||||
<?php if ($require_notes): ?>
|
||||
<span class="text-danger">*</span>
|
||||
<?php endif ?>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<textarea id="customer-notes" rows="2"
|
||||
class="<?= $require_notes ? 'required' : '' ?> form-control"></textarea>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<?php component('custom_fields'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</fieldset>
|
||||
</form>
|
||||
|
@ -361,8 +358,8 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<?php section('scripts') ?>
|
||||
<?php section('scripts'); ?>
|
||||
|
||||
<script src="<?= asset_url('assets/js/components/appointments_modal.js') ?>"></script>
|
||||
|
||||
<?php end_section('scripts') ?>
|
||||
<?php end_section('scripts'); ?>
|
||||
|
|
|
@ -131,6 +131,10 @@
|
|||
</div>
|
||||
<?php endif; ?>
|
||||
</div>
|
||||
|
||||
<div class="mb-3">
|
||||
<?php component('custom_fields'); ?>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
|
24
application/views/components/custom_fields.php
Normal file
24
application/views/components/custom_fields.php
Normal file
|
@ -0,0 +1,24 @@
|
|||
<?php
|
||||
/**
|
||||
* Local variables.
|
||||
*
|
||||
* @var bool $disabled (false)
|
||||
*/
|
||||
|
||||
$disabled = $disabled ?? false; ?>
|
||||
|
||||
<?php for ($i = 1; $i <= 5; $i++): ?>
|
||||
<?php if (setting('display_custom_field_' . $i)): ?>
|
||||
<div class="mb-3">
|
||||
<label for="custom-field-<?= $i ?>" class="form-label">
|
||||
<?= setting('label_custom_field_' . $i) ?: lang('custom_field') . ' #' . $i ?>
|
||||
<?php if (vars('require_custom_field_' . $i)): ?>
|
||||
<span class="text-danger" hidden>*</span>
|
||||
<?php endif; ?>
|
||||
</label>
|
||||
<input type="text" id="custom-field-<?= $i ?>"
|
||||
class="<?= vars('require_custom_field_' . $i) ? 'required' : '' ?> form-control"
|
||||
maxlength="120" <?= $disabled ? 'disabled' : '' ?>/>
|
||||
</div>
|
||||
<?php endif; ?>
|
||||
<?php endfor; ?>
|
|
@ -246,6 +246,50 @@
|
|||
</div>
|
||||
</div>
|
||||
|
||||
<h5 class="text-black-50 mb-3 fw-light">
|
||||
<?= lang('custom_fields') ?>
|
||||
</h5>
|
||||
|
||||
<div class="row mb-5 fields-row">
|
||||
<?php for ($i = 1; $i <= 5; $i++): ?>
|
||||
<div class="col-sm-6">
|
||||
<div class="form-group mb-5">
|
||||
<label for="first-name" class="form-label">
|
||||
<?= lang('custom_field') ?> #<?= $i ?>
|
||||
<span class="text-danger">*</span>
|
||||
</label>
|
||||
|
||||
<input type="text" id="custom-field-<?= $i ?>" class="form-control mb-2"
|
||||
placeholder="<?= lang('label') ?>"
|
||||
data-field="label_custom_field_<?= $i ?>"
|
||||
aria-label="label"
|
||||
/>
|
||||
|
||||
<div class="d-flex">
|
||||
<div class="form-check form-switch me-4">
|
||||
<input class="form-check-input display-switch" type="checkbox"
|
||||
id="display-custom-field-<?= $i ?>"
|
||||
data-field="display_custom_field_<?= $i ?>">
|
||||
<label class="form-check-label" for="display-custom-field-<?= $i ?>">
|
||||
<?= lang('display') ?>
|
||||
</label>
|
||||
</div>
|
||||
|
||||
<div class="form-check form-switch">
|
||||
<input class="form-check-input require-switch" type="checkbox"
|
||||
id="require-custom-field-<?= $i ?>"
|
||||
data-field="require_custom_field_<?= $i ?>">
|
||||
<label class="form-check-label" for="require-custom-field-<?= $i ?>">
|
||||
<?= lang('require') ?>
|
||||
</label>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<?php endfor; ?>
|
||||
</div>
|
||||
|
||||
|
||||
<h5 class="text-black-50 mb-3 fw-light">
|
||||
<?= lang('options') ?>
|
||||
</h5>
|
||||
|
|
|
@ -181,7 +181,9 @@
|
|||
]); ?>
|
||||
</div>
|
||||
|
||||
<?php component('auxiliary_fields'); ?>
|
||||
<?php component('custom_fields', [
|
||||
'disabled' => true
|
||||
]); ?>
|
||||
|
||||
<div class="mb-3">
|
||||
<label class="form-label" for="notes">
|
||||
|
|
|
@ -46,6 +46,11 @@ App.Components.AppointmentsModal = (function () {
|
|||
const $insertAppointment = $('#insert-appointment');
|
||||
const $existingCustomersList = $('#existing-customers-list');
|
||||
const $newCustomer = $('#new-customer');
|
||||
const $customField1 = $('#custom-field-1');
|
||||
const $customField2 = $('#custom-field-2');
|
||||
const $customField3 = $('#custom-field-3');
|
||||
const $customField4 = $('#custom-field-4');
|
||||
const $customField5 = $('#custom-field-5');
|
||||
|
||||
/**
|
||||
* Update the displayed timezone.
|
||||
|
@ -110,7 +115,12 @@ App.Components.AppointmentsModal = (function () {
|
|||
zip_code: $zipCode.val(),
|
||||
language: $language.val(),
|
||||
timezone: $timezone.val(),
|
||||
notes: $customerNotes.val()
|
||||
notes: $customerNotes.val(),
|
||||
custom_field_1: $customField1.val(),
|
||||
custom_field_2: $customField2.val(),
|
||||
custom_field_3: $customField3.val(),
|
||||
custom_field_4: $customField4.val(),
|
||||
custom_field_5: $customField5.val()
|
||||
};
|
||||
|
||||
if ($customerId.val() !== '') {
|
||||
|
@ -217,7 +227,8 @@ App.Components.AppointmentsModal = (function () {
|
|||
vars('customers').forEach((customer) => {
|
||||
$('<div/>', {
|
||||
'data-id': customer.id,
|
||||
'text': (customer.first_name || '[No First Name]') + ' ' + (customer.last_name || '[No Last Name]')
|
||||
'text':
|
||||
(customer.first_name || '[No First Name]') + ' ' + (customer.last_name || '[No Last Name]')
|
||||
}).appendTo($existingCustomersList);
|
||||
});
|
||||
} else {
|
||||
|
@ -249,6 +260,11 @@ App.Components.AppointmentsModal = (function () {
|
|||
$language.val(customer.language);
|
||||
$timezone.val(customer.timezone);
|
||||
$customerNotes.val(customer.notes);
|
||||
$customField1.val(customer.custom_field_1);
|
||||
$customField2.val(customer.custom_field_2);
|
||||
$customField3.val(customer.custom_field_3);
|
||||
$customField4.val(customer.custom_field_4);
|
||||
$customField5.val(customer.custom_field_5);
|
||||
}
|
||||
|
||||
$selectCustomer.trigger('click'); // Hide the list.
|
||||
|
@ -278,7 +294,10 @@ App.Components.AppointmentsModal = (function () {
|
|||
response.forEach((customer) => {
|
||||
$('<div/>', {
|
||||
'data-id': customer.id,
|
||||
'text': (customer.first_name || '[No First Name]') + ' ' + (customer.last_name || '[No Last Name]')
|
||||
'text':
|
||||
(customer.first_name || '[No First Name]') +
|
||||
' ' +
|
||||
(customer.last_name || '[No Last Name]')
|
||||
}).appendTo($existingCustomersList);
|
||||
|
||||
// Verify if this customer is on the old customer list.
|
||||
|
@ -309,7 +328,10 @@ App.Components.AppointmentsModal = (function () {
|
|||
) {
|
||||
$('<div/>', {
|
||||
'data-id': customer.id,
|
||||
'text': (customer.first_name || '[No First Name]') + ' ' + (customer.last_name || '[No Last Name]')
|
||||
'text':
|
||||
(customer.first_name || '[No First Name]') +
|
||||
' ' +
|
||||
(customer.last_name || '[No Last Name]')
|
||||
}).appendTo($existingCustomersList);
|
||||
}
|
||||
});
|
||||
|
@ -395,6 +417,11 @@ App.Components.AppointmentsModal = (function () {
|
|||
$language.val('english');
|
||||
$timezone.val('UTC');
|
||||
$customerNotes.val('');
|
||||
$customField1.val('');
|
||||
$customField2.val('');
|
||||
$customField3.val('');
|
||||
$customField4.val('');
|
||||
$customField5.val('');
|
||||
});
|
||||
}
|
||||
|
||||
|
@ -502,7 +529,10 @@ App.Components.AppointmentsModal = (function () {
|
|||
}
|
||||
|
||||
// Check email address.
|
||||
if ($appointmentsModal.find('#email').val() && !App.Utils.Validation.email($appointmentsModal.find('#email').val())) {
|
||||
if (
|
||||
$appointmentsModal.find('#email').val() &&
|
||||
!App.Utils.Validation.email($appointmentsModal.find('#email').val())
|
||||
) {
|
||||
$appointmentsModal.find('#email').addClass('is-invalid');
|
||||
throw new Error(lang('invalid_email'));
|
||||
}
|
||||
|
|
|
@ -27,9 +27,15 @@ App.Pages.Customers = (function () {
|
|||
const $zipCode = $('#zip-code');
|
||||
const $timezone = $('#timezone');
|
||||
const $language = $('#language');
|
||||
const $customField1 = $('#custom-field-1');
|
||||
const $customField2 = $('#custom-field-2');
|
||||
const $customField3 = $('#custom-field-3');
|
||||
const $customField4 = $('#custom-field-4');
|
||||
const $customField5 = $('#custom-field-5');
|
||||
const $notes = $('#notes');
|
||||
const $formMessage = $('#form-message');
|
||||
const $customerAppointments = $('#customer-appointments');
|
||||
|
||||
let filterResults = {};
|
||||
let filterLimit = 20;
|
||||
|
||||
|
@ -124,7 +130,12 @@ App.Pages.Customers = (function () {
|
|||
zip_code: $zipCode.val(),
|
||||
notes: $notes.val(),
|
||||
timezone: $timezone.val(),
|
||||
language: $language.val() || 'english'
|
||||
language: $language.val() || 'english',
|
||||
custom_field_1: $customField1.val(),
|
||||
custom_field_2: $customField2.val(),
|
||||
custom_field_3: $customField3.val(),
|
||||
custom_field_4: $customField4.val(),
|
||||
custom_field_5: $customField5.val()
|
||||
};
|
||||
|
||||
if ($id.val()) {
|
||||
|
@ -276,6 +287,11 @@ App.Pages.Customers = (function () {
|
|||
$notes.val(customer.notes);
|
||||
$timezone.val(customer.timezone);
|
||||
$language.val(customer.language || 'english');
|
||||
$customField1.val(customer.custom_field_1);
|
||||
$customField2.val(customer.custom_field_2);
|
||||
$customField3.val(customer.custom_field_3);
|
||||
$customField4.val(customer.custom_field_4);
|
||||
$customField5.val(customer.custom_field_5);
|
||||
|
||||
$customerAppointments.empty();
|
||||
|
||||
|
|
|
@ -158,6 +158,11 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
$appointmentsModal.find('#appointment-status').val(appointment.status);
|
||||
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
|
||||
$appointmentsModal.find('#customer-notes').val(customer.notes);
|
||||
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
|
||||
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
|
||||
$appointmentsModal.find('#custom-field-3').val(customer.custom_field_3);
|
||||
$appointmentsModal.find('#custom-field-4').val(customer.custom_field_4);
|
||||
$appointmentsModal.find('#custom-field-5').val(customer.custom_field_5);
|
||||
|
||||
App.Components.ColorSelection.setColor(
|
||||
$appointmentsModal.find('#appointment-color'),
|
||||
|
@ -287,7 +292,10 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
*/
|
||||
$selectFilterItem.on('change', () => {
|
||||
// If current value is service, then the sync buttons must be disabled.
|
||||
if ($selectFilterItem.find('option:selected').attr('type') === FILTER_TYPE_SERVICE || $selectFilterItem.val() === 'all') {
|
||||
if (
|
||||
$selectFilterItem.find('option:selected').attr('type') === FILTER_TYPE_SERVICE ||
|
||||
$selectFilterItem.val() === 'all'
|
||||
) {
|
||||
$('#google-sync, #enable-sync, #insert-appointment, #insert-dropdown').prop('disabled', true);
|
||||
fullCalendar.setOption('selectable', false);
|
||||
fullCalendar.setOption('editable', false);
|
||||
|
@ -317,7 +325,9 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
$('#google-sync').prop('disabled', true);
|
||||
}
|
||||
|
||||
$('#insert-working-plan-exception').toggle(providerId !== App.Utils.CalendarDefaultView.FILTER_TYPE_ALL);
|
||||
$('#insert-working-plan-exception').toggle(
|
||||
providerId !== App.Utils.CalendarDefaultView.FILTER_TYPE_ALL
|
||||
);
|
||||
}
|
||||
|
||||
$reloadAppointments.trigger('click');
|
||||
|
@ -496,11 +506,14 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
'text': lang('start')
|
||||
}),
|
||||
$('<span/>', {
|
||||
'text': startTime ? App.Utils.Date.format(`${date} ${startTime}`,
|
||||
'text': startTime
|
||||
? App.Utils.Date.format(
|
||||
`${date} ${startTime}`,
|
||||
vars('date_format'),
|
||||
vars('time_format'),
|
||||
true
|
||||
) : '-'
|
||||
)
|
||||
: '-'
|
||||
}),
|
||||
$('<br/>'),
|
||||
|
||||
|
@ -509,11 +522,14 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
'text': lang('end')
|
||||
}),
|
||||
$('<span/>', {
|
||||
'text': endTime ? App.Utils.Date.format(`${date} ${endTime}`,
|
||||
'text': endTime
|
||||
? App.Utils.Date.format(
|
||||
`${date} ${endTime}`,
|
||||
vars('date_format'),
|
||||
vars('time_format'),
|
||||
true
|
||||
) : '-'
|
||||
)
|
||||
: '-'
|
||||
}),
|
||||
$('<br/>'),
|
||||
|
||||
|
@ -626,7 +642,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
'text': lang('status')
|
||||
}),
|
||||
$('<span/>', {
|
||||
'text': info.event.extendedProps.data.status || '-',
|
||||
'text': info.event.extendedProps.data.status || '-'
|
||||
}),
|
||||
$('<br/>'),
|
||||
|
||||
|
@ -1025,8 +1041,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
return;
|
||||
}
|
||||
|
||||
const isProviderDisplayed =
|
||||
$selectFilterItem.find('option:selected').attr('type') === FILTER_TYPE_PROVIDER;
|
||||
const isProviderDisplayed = $selectFilterItem.find('option:selected').attr('type') === FILTER_TYPE_PROVIDER;
|
||||
|
||||
const buttons = [
|
||||
{
|
||||
|
@ -1059,8 +1074,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
|
||||
if (isProviderDisplayed) {
|
||||
const provider = vars('available_providers').find(
|
||||
(availableProvider) =>
|
||||
Number(availableProvider.id) === Number($selectFilterItem.val())
|
||||
(availableProvider) => Number(availableProvider.id) === Number($selectFilterItem.val())
|
||||
);
|
||||
|
||||
if (provider) {
|
||||
|
@ -1090,8 +1104,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
$appointmentsModal.find('#select-provider').trigger('change');
|
||||
} else {
|
||||
service = vars('available_services').find(
|
||||
(availableService) =>
|
||||
Number(availableService.id) === Number($selectFilterItem.val())
|
||||
(availableService) => Number(availableService.id) === Number($selectFilterItem.val())
|
||||
);
|
||||
|
||||
if (service) {
|
||||
|
@ -1182,9 +1195,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
|
||||
// Add appointments to calendar.
|
||||
response.appointments.forEach((appointment) => {
|
||||
const title = [
|
||||
appointment.service.name
|
||||
];
|
||||
const title = [appointment.service.name];
|
||||
|
||||
const customerInfo = [];
|
||||
|
||||
|
@ -1236,7 +1247,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
calendarEventSource.push(unavailabilityEvent);
|
||||
});
|
||||
|
||||
response.blocked_periods.forEach(blockedPeriod => {
|
||||
response.blocked_periods.forEach((blockedPeriod) => {
|
||||
const blockedPeriodEvent = {
|
||||
title: blockedPeriod.name,
|
||||
start: moment(blockedPeriod.start_datetime).toDate(),
|
||||
|
@ -1263,7 +1274,9 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
(availableProvider) => Number(availableProvider.id) === Number(recordId)
|
||||
);
|
||||
|
||||
const workingPlan = JSON.parse(provider ? provider.settings.working_plan : vars('company_working_plan'));
|
||||
const workingPlan = JSON.parse(
|
||||
provider ? provider.settings.working_plan : vars('company_working_plan')
|
||||
);
|
||||
const workingPlanExceptions = JSON.parse(provider ? provider.settings.working_plan_exceptions : '{}');
|
||||
let unavailabilityEvent;
|
||||
let breakStart;
|
||||
|
@ -1304,9 +1317,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
workingPlanExceptionEvent = {
|
||||
title: lang('working_plan_exception'),
|
||||
start: moment(workingPlanExceptionStart, 'YYYY-MM-DD HH:mm', true).toDate(),
|
||||
end: moment(workingPlanExceptionEnd, 'YYYY-MM-DD HH:mm', true)
|
||||
.add(1, 'day')
|
||||
.toDate(),
|
||||
end: moment(workingPlanExceptionEnd, 'YYYY-MM-DD HH:mm', true).add(1, 'day').toDate(),
|
||||
allDay: true,
|
||||
color: '#879DB4',
|
||||
editable: false,
|
||||
|
@ -1352,10 +1363,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
title: lang('not_working'),
|
||||
start: calendarDate.clone().toDate(),
|
||||
end: moment(
|
||||
calendarDate.format('YYYY-MM-DD') +
|
||||
' ' +
|
||||
sortedWorkingPlan[weekdayName].start +
|
||||
':00'
|
||||
calendarDate.format('YYYY-MM-DD') + ' ' + sortedWorkingPlan[weekdayName].start + ':00'
|
||||
).toDate(),
|
||||
allDay: false,
|
||||
color: '#BEBEBE',
|
||||
|
@ -1376,10 +1384,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
unavailabilityEvent = {
|
||||
title: lang('not_working'),
|
||||
start: moment(
|
||||
calendarDate.format('YYYY-MM-DD') +
|
||||
' ' +
|
||||
sortedWorkingPlan[weekdayName].end +
|
||||
':00'
|
||||
calendarDate.format('YYYY-MM-DD') + ' ' + sortedWorkingPlan[weekdayName].end + ':00'
|
||||
).toDate(),
|
||||
end: calendarDate.clone().add(1, 'day').toDate(),
|
||||
allDay: false,
|
||||
|
@ -1405,9 +1410,7 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
|
||||
const unavailabilityEvent = {
|
||||
title: lang('break'),
|
||||
start: moment(
|
||||
calendarDate.format('YYYY-MM-DD') + ' ' + breakPeriod.start
|
||||
).toDate(),
|
||||
start: moment(calendarDate.format('YYYY-MM-DD') + ' ' + breakPeriod.start).toDate(),
|
||||
end: moment(calendarDate.format('YYYY-MM-DD') + ' ' + breakPeriod.end).toDate(),
|
||||
allDay: false,
|
||||
color: '#BEBEBE',
|
||||
|
@ -1420,7 +1423,6 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
|
||||
calendarDate.add(1, 'day');
|
||||
}
|
||||
|
||||
})
|
||||
.always(() => {
|
||||
$('#loading').css('visibility', '');
|
||||
|
@ -1562,7 +1564,10 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
|
||||
const localSelectFilterItemValue = window.localStorage.getItem('EasyAppointments.SelectFilterItem');
|
||||
|
||||
if (localSelectFilterItemValue && $selectFilterItem.find(`option[value="${localSelectFilterItemValue}"]`).length) {
|
||||
if (
|
||||
localSelectFilterItemValue &&
|
||||
$selectFilterItem.find(`option[value="${localSelectFilterItemValue}"]`).length
|
||||
) {
|
||||
$selectFilterItem.val(localSelectFilterItemValue).trigger('change');
|
||||
} else {
|
||||
$reloadAppointments.trigger('click');
|
||||
|
@ -1601,6 +1606,11 @@ App.Utils.CalendarDefaultView = (function () {
|
|||
$appointmentsModal.find('#appointment-status').val(appointment.status);
|
||||
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
|
||||
$appointmentsModal.find('#customer-notes').val(customer.notes);
|
||||
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
|
||||
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
|
||||
$appointmentsModal.find('#custom-field-3').val(customer.custom_field_3);
|
||||
$appointmentsModal.find('#custom-field-4').val(customer.custom_field_4);
|
||||
$appointmentsModal.find('#custom-field-5').val(customer.custom_field_5);
|
||||
|
||||
App.Components.ColorSelection.setColor($appointmentsModal.find('#appointment-color'), appointment.color);
|
||||
|
||||
|
|
|
@ -232,6 +232,11 @@ App.Utils.CalendarTableView = (function () {
|
|||
$appointmentsModal.find('#appointment-status').val(appointment.status);
|
||||
$appointmentsModal.find('#appointment-notes').val(appointment.notes);
|
||||
$appointmentsModal.find('#customer-notes').val(customer.notes);
|
||||
$appointmentsModal.find('#custom-field-1').val(customer.custom_field_1);
|
||||
$appointmentsModal.find('#custom-field-2').val(customer.custom_field_2);
|
||||
$appointmentsModal.find('#custom-field-3').val(customer.custom_field_3);
|
||||
$appointmentsModal.find('#custom-field-4').val(customer.custom_field_4);
|
||||
$appointmentsModal.find('#custom-field-5').val(customer.custom_field_5);
|
||||
|
||||
App.Components.ColorSelection.setColor(
|
||||
$appointmentsModal.find('#appointment-color'),
|
||||
|
@ -387,7 +392,9 @@ App.Utils.CalendarTableView = (function () {
|
|||
App.Utils.UI.initializeDatepicker($calendarHeader.find('.select-date'), {
|
||||
onChange(selectedDates) {
|
||||
const startDate = selectedDates[0];
|
||||
const endDate = moment(startDate).add(parseInt($selectFilterItem.val()) - 1, 'days').toDate();
|
||||
const endDate = moment(startDate)
|
||||
.add(parseInt($selectFilterItem.val()) - 1, 'days')
|
||||
.toDate();
|
||||
createView(startDate, endDate);
|
||||
}
|
||||
});
|
||||
|
@ -853,7 +860,7 @@ App.Utils.CalendarTableView = (function () {
|
|||
return;
|
||||
}
|
||||
|
||||
const filterServiceIds = $filterService.val().map(serviceId => Number(serviceId));
|
||||
const filterServiceIds = $filterService.val().map((serviceId) => Number(serviceId));
|
||||
|
||||
appointments = appointments.filter(
|
||||
(appointment) => !filterServiceIds.length || filterServiceIds.includes(appointment.id_services)
|
||||
|
@ -868,9 +875,7 @@ App.Utils.CalendarTableView = (function () {
|
|||
continue;
|
||||
}
|
||||
|
||||
const title = [
|
||||
appointment.service.name
|
||||
];
|
||||
const title = [appointment.service.name];
|
||||
|
||||
const customerInfo = [];
|
||||
|
||||
|
|
30
openapi.yml
30
openapi.yml
|
@ -1902,6 +1902,16 @@ components:
|
|||
type: string
|
||||
language:
|
||||
type: string
|
||||
customField1:
|
||||
type: string
|
||||
customField2:
|
||||
type: string
|
||||
customField3:
|
||||
type: string
|
||||
customField4:
|
||||
type: string
|
||||
customField5:
|
||||
type: string
|
||||
notes:
|
||||
type: string
|
||||
example:
|
||||
|
@ -1914,6 +1924,11 @@ components:
|
|||
zip: '12345'
|
||||
timezone: UTC
|
||||
language: english
|
||||
customField1: Value1
|
||||
customField2: Value2
|
||||
customField3: Value3
|
||||
customField4: Value4
|
||||
customField5: Value5
|
||||
notes: This is a test customer.
|
||||
CustomerPayload:
|
||||
type: object
|
||||
|
@ -1936,6 +1951,16 @@ components:
|
|||
type: string
|
||||
language:
|
||||
type: string
|
||||
customField1:
|
||||
type: string
|
||||
customField2:
|
||||
type: string
|
||||
customField3:
|
||||
type: string
|
||||
customField4:
|
||||
type: string
|
||||
customField5:
|
||||
type: string
|
||||
notes:
|
||||
type: string
|
||||
example:
|
||||
|
@ -1947,6 +1972,11 @@ components:
|
|||
zip: '12345'
|
||||
timezone: UTC
|
||||
language: english
|
||||
customField1: Value1
|
||||
customField2: Value2
|
||||
customField3: Value3
|
||||
customField4: Value4
|
||||
customField5: Value5
|
||||
notes: This is a test customer.
|
||||
CustomerCollection:
|
||||
type: array
|
||||
|
|
Loading…
Reference in a new issue