Better Customer data privacy protection (#1949)

This commit is contained in:
FrancescoUK
2018-04-29 14:13:00 +01:00
parent 3e9e144075
commit fdbdf55e71
13 changed files with 221 additions and 85 deletions

View File

@@ -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'),

View File

@@ -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);

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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";

View File

@@ -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.";

View File

@@ -0,0 +1,20 @@
<?php if (!defined('BASEPATH')) exit('No direct script access allowed');
class Migration_Upgrade_To_3_2_1 extends CI_Migration
{
public function __construct()
{
parent::__construct();
}
public function up()
{
execute_script(APPPATH . 'migrations/sqlscripts/3.2.0_to_3.2.1.sql');
}
public function down()
{
}
}
?>

View File

@@ -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');

View File

@@ -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));

View File

@@ -28,6 +28,21 @@
</div>
</div>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('config_enforce_privacy'), 'enforce_privacy', array('class' => 'control-label col-xs-2')); ?>
<div class='col-xs-1'>
<?php echo form_checkbox(array(
'name' => 'enforce_privacy',
'id' => 'enforce_privacy',
'value' => 'enforce_privacy',
'checked' => $this->config->item('enforce_privacy'))); ?>
&nbsp
<label class="control-label">
<span class="glyphicon glyphicon-info-sign" data-toggle="tooltip" data-placement="right" title="<?php echo $this->lang->line('config_enforce_privacy_tooltip'); ?>"></span>
</label>
</div>
</div>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('config_receiving_calculate_average_price'), 'receiving_calculate_average_price', array('class' => 'control-label col-xs-2')); ?>
<div class='col-xs-1'>

View File

@@ -32,6 +32,13 @@
<div class="tab-content">
<div class="tab-pane fade in active" id="customer_basic_info">
<fieldset>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_consent'), 'consent', array('class' => 'required control-label col-xs-3')); ?>
<div class='col-xs-1'>
<?php echo form_checkbox('consent', '1', $person_info->consent == '' ? (boolean)!$this->config->item('enforce_privacy') : (boolean)$person_info->consent); ?>
</div>
</div>
<?php $this->load->view("people/form_basic_info"); ?>
<div class="form-group form-group-sm">
@@ -43,7 +50,7 @@
'id'=>'discount_percent',
'class'=>'form-control input-sm',
'value'=>$person_info->discount_percent)
);?>
); ?>
<span class="input-group-addon input-sm"><b>%</b></span>
</div>
</div>
@@ -57,7 +64,7 @@
'id'=>'company_name',
'class'=>'form-control input-sm',
'value'=>$person_info->company_name)
);?>
); ?>
</div>
</div>
@@ -69,7 +76,7 @@
'id'=>'account_number',
'class'=>'form-control input-sm',
'value'=>$person_info->account_number)
);?>
); ?>
</div>
</div>
@@ -90,7 +97,7 @@
'class'=>'form-control input-sm',
'value'=>$person_info->points,
'disabled'=>'')
);?>
); ?>
</div>
</div>
<?php endif; ?>
@@ -98,9 +105,63 @@
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_taxable'), 'taxable', array('class' => 'control-label col-xs-3')); ?>
<div class='col-xs-1'>
<?php echo form_checkbox('taxable', '1', $person_info->taxable == '' ? TRUE : (boolean)$person_info->taxable);?>
<?php echo form_checkbox('taxable', '1', $person_info->taxable == '' ? TRUE : (boolean)$person_info->taxable); ?>
</div>
</div>
<?php
if($customer_sales_tax_enabled)
{
?>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_tax_code'), 'sales_tax_code_name', array('class'=>'control-label col-xs-3')); ?>
<div class='col-xs-8'>
<div class="input-group input-group-sm">
<?php echo form_input(array(
'name'=>'sales_tax_code_name',
'id'=>'sales_tax_code_name',
'class'=>'form-control input-sm',
'size'=>'50',
'value'=>$sales_tax_code_label)
); ?>
<?php echo form_hidden('sales_tax_code', $person_info->sales_tax_code); ?>
</div>
</div>
</div>
<?php
}
?>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_date'), 'date', array('class'=>'control-label col-xs-3')); ?>
<div class='col-xs-8'>
<div class="input-group">
<span class="input-group-addon input-sm"><span class="glyphicon glyphicon-calendar"></span></span>
<?php echo form_input(array(
'name'=>'date',
'id'=>'datetime',
'class'=>'form-control input-sm',
'value'=>date($this->config->item('dateformat') . ' ' . $this->config->item('timeformat'), strtotime($person_info->date)),
'readonly'=>'true')
); ?>
</div>
</div>
</div>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_employee'), 'employee', array('class'=>'control-label col-xs-3')); ?>
<div class='col-xs-8'>
<?php echo form_input(array(
'name'=>'employee',
'id'=>'employee',
'class'=>'form-control input-sm',
'value'=>$employee,
'readonly'=>'true')
); ?>
</div>
</div>
<?php echo form_hidden('employee_id', $person_info->employee_id); ?>
</fieldset>
</div>
@@ -123,7 +184,7 @@
'class'=>'form-control input-sm',
'value'=>to_currency_no_money($stats->total),
'disabled'=>'')
);?>
); ?>
<?php if (currency_side()): ?>
<span class="input-group-addon input-sm"><b><?php echo $this->config->item('currency_symbol'); ?></b></span>
<?php endif; ?>
@@ -144,7 +205,7 @@
'class'=>'form-control input-sm',
'value'=>to_currency_no_money($stats->max),
'disabled'=>'')
);?>
); ?>
<?php if (currency_side()): ?>
<span class="input-group-addon input-sm"><b><?php echo $this->config->item('currency_symbol'); ?></b></span>
<?php endif; ?>
@@ -165,7 +226,7 @@
'class'=>'form-control input-sm',
'value'=>to_currency_no_money($stats->min),
'disabled'=>'')
);?>
); ?>
<?php if (currency_side()): ?>
<span class="input-group-addon input-sm"><b><?php echo $this->config->item('currency_symbol'); ?></b></span>
<?php endif; ?>
@@ -186,7 +247,7 @@
'class'=>'form-control input-sm',
'value'=>to_currency_no_money($stats->average),
'disabled'=>'')
);?>
); ?>
<?php if (currency_side()): ?>
<span class="input-group-addon input-sm"><b><?php echo $this->config->item('currency_symbol'); ?></b></span>
<?php endif; ?>
@@ -204,7 +265,7 @@
'class'=>'form-control input-sm',
'value'=>$stats->quantity,
'disabled'=>'')
);?>
); ?>
</div>
</div>
</div>
@@ -219,7 +280,7 @@
'class'=>'form-control input-sm',
'value'=>$stats->avg_discount,
'disabled'=>'')
);?>
); ?>
<span class="input-group-addon input-sm"><b>%</b></span>
</div>
</div>
@@ -254,7 +315,7 @@
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_mailchimp_vip'), 'mailchimp_vip', array('class' => 'control-label col-xs-3')); ?>
<div class='col-xs-1'>
<?php echo form_checkbox('mailchimp_vip', '1', $mailchimp_info['vip'] == '' ? FALSE : (boolean)$mailchimp_info['vip']);?>
<?php echo form_checkbox('mailchimp_vip', '1', $mailchimp_info['vip'] == '' ? FALSE : (boolean)$mailchimp_info['vip']); ?>
</div>
</div>
@@ -266,7 +327,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_info['member_rating'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -278,7 +339,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_activity['total'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -290,7 +351,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_activity['lastopen'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -302,7 +363,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_activity['open'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -314,7 +375,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_activity['click'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -326,7 +387,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_activity['unopen'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
@@ -338,7 +399,7 @@
'class'=>'form-control input-sm',
'value'=>$mailchimp_info['email_client'],
'disabled'=>'')
);?>
); ?>
</div>
</div>
</fieldset>
@@ -347,31 +408,34 @@
}
?>
</div>
<?php if ($customer_sales_tax_enabled) { ?>
<div class="form-group form-group-sm">
<?php echo form_label($this->lang->line('customers_tax_code'), 'sales_tax_code_name', array('class'=>'control-label col-xs-3')); ?>
<div class='col-xs-8'>
<div class="input-group input-group-sm">
<?php echo form_input(array(
'name'=>'sales_tax_code_name',
'id'=>'sales_tax_code_name',
'class'=>'form-control input-sm',
'size'=>'50',
'value'=>$sales_tax_code_label)
); ?>
<?php echo form_hidden('sales_tax_code', $person_info->sales_tax_code);?>
</div>
</div>
</div>
<?php } ?>
<?php echo form_close(); ?>
<script type="text/javascript">
//validation and submit handling
$(document).ready(function()
{
$("input[name='sales_tax_code_name']").change(function() {
if( ! $("input[name='sales_tax_code_name']").val() ) {
$("input[name='sales_tax_code']").val('');
}
});
var fill_value = function(event, ui) {
event.preventDefault();
$("input[name='sales_tax_code']").val(ui.item.value);
$("input[name='sales_tax_code_name']").val(ui.item.label);
};
$("#sales_tax_code_name").autocomplete({
source: '<?php echo site_url("taxes/suggest_sales_tax_codes"); ?>',
minChars: 0,
delay: 15,
cacheLength: 1,
appendTo: '.modal-content',
select: fill_value,
focus: fill_value
});
$('#customer_form').validate($.extend({
submitHandler: function(form)
{
@@ -389,6 +453,7 @@ $(document).ready(function()
{
first_name: "required",
last_name: "required",
consent: "required",
email:
{
remote:
@@ -421,32 +486,10 @@ $(document).ready(function()
{
first_name: "<?php echo $this->lang->line('common_first_name_required'); ?>",
last_name: "<?php echo $this->lang->line('common_last_name_required'); ?>",
consent: "<?php echo $this->lang->line('customers_consent_required'); ?>",
email: "<?php echo $this->lang->line('customers_email_duplicate'); ?>",
account_number: "<?php echo $this->lang->line('customers_account_number_duplicate'); ?>"
}
}, form_support.error));
});
$("input[name='sales_tax_code_name']").change(function() {
if( ! $("input[name='sales_tax_code_name']").val() ) {
$("input[name='sales_tax_code']").val('');
}
});
var fill_value = function(event, ui) {
event.preventDefault();
$("input[name='sales_tax_code']").val(ui.item.value);
$("input[name='sales_tax_code_name']").val(ui.item.label);
};
$("#sales_tax_code_name").autocomplete({
source: '<?php echo site_url("taxes/suggest_sales_tax_codes"); ?>',
minChars: 0,
delay: 15,
cacheLength: 1,
appendTo: '.modal-content',
select: fill_value,
focus: fill_value
});
</script>
</script>

View File

@@ -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
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
1 First Name Last Name Gender Consent Email Phone Number Address 1 Address2 City State Zip Country Comments Company Account Number Discount Taxable
2 Bob Smith 1 y bsmith@nowhere.com 585-555-1111 123 Nowhere Street Apt 4 Awesome NY 11111 USA Awesome guy 5.00 5 y