From fdbdf55e71d9bff5b704b9209b0ef4a37a52897a Mon Sep 17 00:00:00 2001 From: FrancescoUK Date: Sun, 29 Apr 2018 14:13:00 +0100 Subject: [PATCH] Better Customer data privacy protection (#1949) --- application/controllers/Config.php | 1 + application/controllers/Customers.php | 61 +++++-- application/language/en-GB/common_lang.php | 2 +- application/language/en-GB/config_lang.php | 2 + application/language/en-GB/customers_lang.php | 4 + application/language/en-US/config_lang.php | 2 + application/language/en-US/customers_lang.php | 4 + .../20180429100000_upgrade_to_3_2_1.php | 20 +++ .../migrations/sqlscripts/3.2.0_to_3.2.1.sql | 15 ++ application/models/Customer.php | 9 +- application/views/configs/general_config.php | 15 ++ application/views/customers/form.php | 167 +++++++++++------- import_customers.csv | 4 +- 13 files changed, 221 insertions(+), 85 deletions(-) create mode 100644 application/migrations/20180429100000_upgrade_to_3_2_1.php create mode 100644 application/migrations/sqlscripts/3.2.0_to_3.2.1.sql diff --git a/application/controllers/Config.php b/application/controllers/Config.php index 83e2aa3b7..d7beefee9 100644 --- a/application/controllers/Config.php +++ b/application/controllers/Config.php @@ -286,6 +286,7 @@ class Config extends Secure_Controller $batch_save_data = array( 'theme' => $this->input->post('theme'), 'default_sales_discount' => $this->input->post('default_sales_discount'), + 'enforce_privacy' => $this->input->post('enforce_privacy'), 'receiving_calculate_average_price' => $this->input->post('receiving_calculate_average_price') != NULL, 'lines_per_page' => $this->input->post('lines_per_page'), 'notify_horizontal_position' => $this->input->post('notify_horizontal_position'), diff --git a/application/controllers/Customers.php b/application/controllers/Customers.php index 76fb4c66f..0022eaddb 100644 --- a/application/controllers/Customers.php +++ b/application/controllers/Customers.php @@ -117,6 +117,16 @@ class Customers extends Persons $info->$property = $this->xss_clean($value); } $data['person_info'] = $info; + + if(empty($info->person_id) || empty($info->date) || empty($info->employee_id)) + { + $data['person_info']->date = date('Y-m-d H:i:s'); + $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; + $data['sales_tax_code_label'] = $info->sales_tax_code . ' ' . $this->Tax->get_info($info->sales_tax_code)->tax_code_name; $packages = array('' => $this->lang->line('items_none')); foreach($this->Customer_rewards->get_all()->result_array() as $row) @@ -232,12 +242,17 @@ class Customers extends Persons 'comments' => $this->input->post('comments') ); + $date_formatter = date_create_from_format($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), $this->input->post('date')); + $customer_data = array( + 'consent' => $this->input->post('consent') != NULL, 'account_number' => $this->input->post('account_number') == '' ? NULL : $this->input->post('account_number'), 'company_name' => $this->input->post('company_name') == '' ? NULL : $this->input->post('company_name'), 'discount_percent' => $this->input->post('discount_percent') == '' ? 0.00 : $this->input->post('discount_percent'), 'package_id' => $this->input->post('package_id') == '' ? NULL : $this->input->post('package_id'), - 'taxable' => $this->input->post('taxable') != NULL + 'taxable' => $this->input->post('taxable') != NULL, + 'date' => $date_formatter->format('Y-m-d H:i:s'), + 'employee_id' => $this->input->post('employee_id') ); $tax_code = $this->input->post('sales_tax_code'); @@ -305,16 +320,23 @@ class Customers extends Persons $customers_to_delete = $this->input->post('ids'); $customers_info = $this->Customer->get_multiple_info($customers_to_delete); - if($this->Customer->delete_list($customers_to_delete)) + $count = 0; + + foreach($customers_info->result() as $info) { - foreach($customers_info->result() as $info) + if($this->Customer->delete($info->person_id)) { // remove customer from Mailchimp selected list $this->mailchimp_lib->removeMember($this->_list_id, $info->email); - } + $count++; + } + } + + if($count == count($customers_to_delete)) + { echo json_encode(array('success' => TRUE, - 'message' => $this->lang->line('customers_successful_deleted') . ' ' . count($customers_to_delete) . ' ' . $this->lang->line('customers_one_or_multiple'))); + 'message' => $this->lang->line('customers_successful_deleted') . ' ' . $count . ' ' . $this->lang->line('customers_one_or_multiple'))); } else { @@ -358,30 +380,31 @@ class Customers extends Persons // XSS file data sanity check $data = $this->xss_clean($data); - if(sizeof($data) >= 15) + if(sizeof($data) >= 16) { - $email = strtolower($data[3]); + $email = strtolower($data[4]); $person_data = array( 'first_name' => $data[0], 'last_name' => $data[1], 'gender' => $data[2], + 'consent' => $data[3] == '' ? 0 : 1, 'email' => $email, - 'phone_number' => $data[4], - 'address_1' => $data[5], - 'address_2' => $data[6], - 'city' => $data[7], - 'state' => $data[8], - 'zip' => $data[9], - 'country' => $data[10], - 'comments' => $data[11] + 'phone_number' => $data[5], + 'address_1' => $data[6], + 'address_2' => $data[7], + 'city' => $data[8], + 'state' => $data[9], + 'zip' => $data[10], + 'country' => $data[11], + 'comments' => $data[12] ); $customer_data = array( - 'company_name' => $data[12], - 'discount_percent' => $data[14], - 'taxable' => $data[15] == '' ? 0 : 1 + 'company_name' => $data[13], + 'discount_percent' => $data[15], + 'taxable' => $data[16] == '' ? 0 : 1 ); - $account_number = $data[13]; + $account_number = $data[14]; // don't duplicate people with same email $invalidated = $this->Customer->check_email_exists($email); diff --git a/application/language/en-GB/common_lang.php b/application/language/en-GB/common_lang.php index e2de82a1a..b904869a7 100644 --- a/application/language/en-GB/common_lang.php +++ b/application/language/en-GB/common_lang.php @@ -20,7 +20,7 @@ $lang["common_export_excel_no"] = "No"; $lang["common_export_excel_yes"] = "Yes"; $lang["common_fields_required_message"] = "Fields in red are required"; $lang["common_first_name"] = "First Name"; -$lang["common_first_name_required"] = "First Name is a required field."; +$lang["common_first_name_required"] = "First Name is a required field"; $lang["common_first_page"] = "First"; $lang["common_gender"] = "Gender"; $lang["common_gender_female"] = "F"; diff --git a/application/language/en-GB/config_lang.php b/application/language/en-GB/config_lang.php index c91bc2f09..044bfdb08 100644 --- a/application/language/en-GB/config_lang.php +++ b/application/language/en-GB/config_lang.php @@ -110,6 +110,8 @@ $lang["config_email_smtp_pass"] = "SMTP Password"; $lang["config_email_smtp_port"] = "SMTP Port"; $lang["config_email_smtp_timeout"] = "SMTP Timeout (s)"; $lang["config_email_smtp_user"] = "SMTP Username"; +$lang["config_enforce_privacy"] = "Enforce privacy"; +$lang["config_enforce_privacy_tooltip"] = "Protect Customers privacy enforcing data scrambling in case of their data being deleted"; $lang["config_fax"] = "Fax"; $lang["config_financial_year"] = "Financial Year Start"; $lang["config_financial_year_apr"] = "1st of April"; diff --git a/application/language/en-GB/customers_lang.php b/application/language/en-GB/customers_lang.php index 030f47237..19b692ff0 100644 --- a/application/language/en-GB/customers_lang.php +++ b/application/language/en-GB/customers_lang.php @@ -10,9 +10,13 @@ $lang["customers_cannot_be_deleted"] = "Could not delete the selected Customer(s $lang["customers_company_name"] = "Company"; $lang["customers_confirm_delete"] = "Are you sure you want to delete the selected Customer(s)?"; $lang["customers_confirm_restore"] = "Are you sure you want to restore the selected Customers(s)?"; +$lang["customers_consent"] = "Registration consent"; +$lang["customers_consent_required"] = "Registration consent is a required field"; $lang["customers_customer"] = "Customer"; +$lang["customers_date"] = "Date"; $lang["customers_discount"] = "Discount"; $lang["customers_email_duplicate"] = "Email address is already present in the database"; +$lang["customers_employee"] = "Employee"; $lang["customers_error_adding_updating"] = "Error adding/updating Customer"; $lang["customers_excel_import_failed"] = "The excel import failed"; $lang["customers_excel_import_nodata_wrongformat"] = "The uploaded file has no data or is incorrectly formatted"; diff --git a/application/language/en-US/config_lang.php b/application/language/en-US/config_lang.php index eb88832e3..1ba77a526 100644 --- a/application/language/en-US/config_lang.php +++ b/application/language/en-US/config_lang.php @@ -110,6 +110,8 @@ $lang["config_email_smtp_pass"] = "SMTP Password"; $lang["config_email_smtp_port"] = "SMTP Port"; $lang["config_email_smtp_timeout"] = "SMTP Timeout (s)"; $lang["config_email_smtp_user"] = "SMTP Username"; +$lang["config_enforce_privacy"] = "Enforce privacy"; +$lang["config_enforce_privacy_tooltip"] = "Protect Customers privacy enforcing data scrambling in case of their data being deleted"; $lang["config_fax"] = "Fax"; $lang["config_financial_year"] = "Fiscal Year Start"; $lang["config_financial_year_apr"] = "1st of April"; diff --git a/application/language/en-US/customers_lang.php b/application/language/en-US/customers_lang.php index 5bef97201..8f3d9f26f 100644 --- a/application/language/en-US/customers_lang.php +++ b/application/language/en-US/customers_lang.php @@ -10,9 +10,13 @@ $lang["customers_cannot_be_deleted"] = "Could not delete selected customers, one $lang["customers_company_name"] = "Company"; $lang["customers_confirm_delete"] = "Are you sure you want to delete the selected customer(s)?"; $lang["customers_confirm_restore"] = "Are you sure you want to restore selected customers(s)?"; +$lang["customers_consent"] = "Registration consent"; +$lang["customers_consent_required"] = "Registration consent is a required field."; $lang["customers_customer"] = "Customer"; +$lang["customers_date"] = "Date"; $lang["customers_discount"] = "Discount"; $lang["customers_email_duplicate"] = "Email Address is already present in the database."; +$lang["customers_employee"] = "Employee"; $lang["customers_error_adding_updating"] = "Customer add or update failed."; $lang["customers_excel_import_failed"] = "Excel import failed"; $lang["customers_excel_import_nodata_wrongformat"] = "The uploaded file has no data or is incorrectly formatted."; diff --git a/application/migrations/20180429100000_upgrade_to_3_2_1.php b/application/migrations/20180429100000_upgrade_to_3_2_1.php new file mode 100644 index 000000000..1fc8308b1 --- /dev/null +++ b/application/migrations/20180429100000_upgrade_to_3_2_1.php @@ -0,0 +1,20 @@ + diff --git a/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql b/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql new file mode 100644 index 000000000..ac92db486 --- /dev/null +++ b/application/migrations/sqlscripts/3.2.0_to_3.2.1.sql @@ -0,0 +1,15 @@ +-- +-- Add support for GDPR utility +-- + +-- Add columns to customer table for tracking purposes and explicit consent of data registration + +ALTER TABLE `ospos_customers` + ADD COLUMN `date` timestamp NOT NULL DEFAULT CURRENT_TIMESTAMP, + ADD COLUMN `employee_id` int(10) NOT NULL, + ADD COLUMN `consent` int(1) NOT NULL DEFAULT '0'; + +-- This is to enforce privacy by means of scrambling customer details + +INSERT INTO `ospos_app_config` (`key`, `value`) VALUES +('enforce_privacy', '0'); diff --git a/application/models/Customer.php b/application/models/Customer.php index 7a6ad488c..7f1f647f2 100644 --- a/application/models/Customer.php +++ b/application/models/Customer.php @@ -218,12 +218,19 @@ class Customer extends Person $this->db->update('customers', array('points' => $value)); } - /* Deletes one customer */ public function delete($customer_id) { + // if privacy enforcement is selected scramble customer data + if($this->config->item('enforce_privacy')) + { + $this->db->where('person_id', $customer_id); + + return $this->db->update('people', array('first_name' => $customer_id, 'last_name' => $customer_id, 'phone_number' => '', 'email' => '')); + } + $this->db->where('person_id', $customer_id); return $this->db->update('customers', array('deleted' => 1)); diff --git a/application/views/configs/general_config.php b/application/views/configs/general_config.php index b376ce86e..cf910dfaf 100644 --- a/application/views/configs/general_config.php +++ b/application/views/configs/general_config.php @@ -28,6 +28,21 @@ +
+ lang->line('config_enforce_privacy'), 'enforce_privacy', array('class' => 'control-label col-xs-2')); ?> +
+ 'enforce_privacy', + 'id' => 'enforce_privacy', + 'value' => 'enforce_privacy', + 'checked' => $this->config->item('enforce_privacy'))); ?> +   + +
+
+
lang->line('config_receiving_calculate_average_price'), 'receiving_calculate_average_price', array('class' => 'control-label col-xs-2')); ?>
diff --git a/application/views/customers/form.php b/application/views/customers/form.php index b35ec882f..c6b534726 100644 --- a/application/views/customers/form.php +++ b/application/views/customers/form.php @@ -32,6 +32,13 @@
+
+ lang->line('customers_consent'), 'consent', array('class' => 'required control-label col-xs-3')); ?> +
+ consent == '' ? (boolean)!$this->config->item('enforce_privacy') : (boolean)$person_info->consent); ?> +
+
+ load->view("people/form_basic_info"); ?>
@@ -43,7 +50,7 @@ 'id'=>'discount_percent', 'class'=>'form-control input-sm', 'value'=>$person_info->discount_percent) - );?> + ); ?> %
@@ -57,7 +64,7 @@ 'id'=>'company_name', 'class'=>'form-control input-sm', 'value'=>$person_info->company_name) - );?> + ); ?>
@@ -69,7 +76,7 @@ 'id'=>'account_number', 'class'=>'form-control input-sm', 'value'=>$person_info->account_number) - );?> + ); ?>
@@ -90,7 +97,7 @@ 'class'=>'form-control input-sm', 'value'=>$person_info->points, 'disabled'=>'') - );?> + ); ?> @@ -98,9 +105,63 @@
lang->line('customers_taxable'), 'taxable', array('class' => 'control-label col-xs-3')); ?>
- taxable == '' ? TRUE : (boolean)$person_info->taxable);?> + taxable == '' ? TRUE : (boolean)$person_info->taxable); ?>
+ + +
+ lang->line('customers_tax_code'), 'sales_tax_code_name', array('class'=>'control-label col-xs-3')); ?> +
+
+ 'sales_tax_code_name', + 'id'=>'sales_tax_code_name', + 'class'=>'form-control input-sm', + 'size'=>'50', + 'value'=>$sales_tax_code_label) + ); ?> + sales_tax_code); ?> +
+
+
+ + +
+ lang->line('customers_date'), 'date', array('class'=>'control-label col-xs-3')); ?> +
+
+ + 'date', + 'id'=>'datetime', + 'class'=>'form-control input-sm', + 'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($person_info->date)), + 'readonly'=>'true') + ); ?> +
+
+
+ +
+ lang->line('customers_employee'), 'employee', array('class'=>'control-label col-xs-3')); ?> +
+ 'employee', + 'id'=>'employee', + 'class'=>'form-control input-sm', + 'value'=>$employee, + 'readonly'=>'true') + ); ?> +
+
+ + employee_id); ?> @@ -123,7 +184,7 @@ 'class'=>'form-control input-sm', 'value'=>to_currency_no_money($stats->total), 'disabled'=>'') - );?> + ); ?> config->item('currency_symbol'); ?> @@ -144,7 +205,7 @@ 'class'=>'form-control input-sm', 'value'=>to_currency_no_money($stats->max), 'disabled'=>'') - );?> + ); ?> config->item('currency_symbol'); ?> @@ -165,7 +226,7 @@ 'class'=>'form-control input-sm', 'value'=>to_currency_no_money($stats->min), 'disabled'=>'') - );?> + ); ?> config->item('currency_symbol'); ?> @@ -186,7 +247,7 @@ 'class'=>'form-control input-sm', 'value'=>to_currency_no_money($stats->average), 'disabled'=>'') - );?> + ); ?> config->item('currency_symbol'); ?> @@ -204,7 +265,7 @@ 'class'=>'form-control input-sm', 'value'=>$stats->quantity, 'disabled'=>'') - );?> + ); ?> @@ -219,7 +280,7 @@ 'class'=>'form-control input-sm', 'value'=>$stats->avg_discount, 'disabled'=>'') - );?> + ); ?> % @@ -254,7 +315,7 @@
lang->line('customers_mailchimp_vip'), 'mailchimp_vip', array('class' => 'control-label col-xs-3')); ?>
- +
@@ -266,7 +327,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_info['member_rating'], 'disabled'=>'') - );?> + ); ?> @@ -278,7 +339,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_activity['total'], 'disabled'=>'') - );?> + ); ?> @@ -290,7 +351,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_activity['lastopen'], 'disabled'=>'') - );?> + ); ?> @@ -302,7 +363,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_activity['open'], 'disabled'=>'') - );?> + ); ?> @@ -314,7 +375,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_activity['click'], 'disabled'=>'') - );?> + ); ?> @@ -326,7 +387,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_activity['unopen'], 'disabled'=>'') - );?> + ); ?> @@ -338,7 +399,7 @@ 'class'=>'form-control input-sm', 'value'=>$mailchimp_info['email_client'], 'disabled'=>'') - );?> + ); ?> @@ -347,31 +408,34 @@ } ?> - - - -
- lang->line('customers_tax_code'), 'sales_tax_code_name', array('class'=>'control-label col-xs-3')); ?> -
-
- 'sales_tax_code_name', - 'id'=>'sales_tax_code_name', - 'class'=>'form-control input-sm', - 'size'=>'50', - 'value'=>$sales_tax_code_label) - ); ?> - sales_tax_code);?> -
-
-
- \ No newline at end of file + diff --git a/import_customers.csv b/import_customers.csv index ccff14bc5..0545827f1 100644 --- a/import_customers.csv +++ b/import_customers.csv @@ -1,2 +1,2 @@ -First Name,Last Name,Gender,Email,Phone Number,Address 1,Address2,City,State,Zip,Country,Comments,Company,Account Number,Discount,Taxable -Bob,Smith,1,bsmith@nowhere.com,585-555-1111,123 Nowhere Street,Apt 4,Awesome,NY,11111,USA,Awesome guy,,,5.00,y \ No newline at end of file +First Name,Last Name,Gender,Consent,Email,Phone Number,Address 1,Address2,City,State,Zip,Country,Comments,Company,Account Number,Discount,Taxable +Bob,Smith,1,y,bsmith@nowhere.com,585-555-1111,123 Nowhere Street,Apt 4,Awesome,NY,11111,USA,Awesome guy,,,5,y