I'm interested in the implications of compliance with the upcoming GDPR EU-regulation due to be law in May 2018.
Printable View
I'm interested in the implications of compliance with the upcoming GDPR EU-regulation due to be law in May 2018.
As I understand it the law will apply to any data system serving EU-citizens, so presumably any ecommerce or CRM website on the internet will need to comply unless it blocks eu-registrations. This article suggests that it maybe advisable to save further data at the time of registration, eg to save a 'consent record' when agreeing to the website terms and conditions, one that includes a copy of the T&C's that were published at the time of registration, to provide sufficient evidence should it be needed.
This is another article I found useful.
Actually this article states:
Data encryption shall be used, when possible: Recitals 83 and Articles 6-4(e), 32-1(a)
Data pseudonymization shall be used, when possible: Recitals 26, 28, 29, 78 and Articles 6-4(e), 25-1, 32-1(a)
This article gives further information.
or GDPR for short
Can't find anything new about this and time is passing by rather quickly
Can Zencart do this or will it be able to do this in the future as this is something that will be needed in the not to far distant future for most of us in the EU......
Apologies if this can already be done but I can't find much on it in regards to Zencart
Details to a full link https://www.itgovernance.co.uk/data-...ion-regulation
What are you expecting Zen Cart to do that it doesn't do now?
In the real world, ie not one populated by scare mongering consultants, the privacy policy has always been up to you, you do not have to auto enrol anyone for anything and you can delete users from the admin panel and/or PHPMyadmin. The only teeny tiny thing missing is a date stamp for when they positively agree to newsletters etc.
All this talk of multi million pound fines is Y2K all over again...... for most normal people and companies it is a non issue.
Hi
Can anyone tell me please if the current version of zencart and my older 1.5.4 will OK with the new EU laws due in May this year?
Thanks
Ian
The other major shopping carts have produced plugins for GDPR which include extra check boxes on forms, the right to be forgotten, click here to see what data we hold about you, etc etc. Zen Cart has not yet as far as I can see. You think a boffin would come up with something, even if is is paid for, to help the small shop keepers out here to comply.
Reiterating the last post. While some points of the GDPR are not in Zen Cart's core remit, I think there are a couple of things that will need code adaptations.
The right to be forgotten - allowing the customer to delete their account
As I read it, a user's browser settings can be used as the consent for cookies 'strictly necessary for the legitimate purpose of enabling the use of a specific service requested by the subscriber or user' i.e. Zen Cart cookies. Consent would be needed for analytical/advertising cookies. Not sure if the latter would need ZC core code modifications.
'Even after getting valid consent, there must be a route for people to change their mind' i.e opt-out at any time. As this would have to include ZC cookies I suspect core code changes would be needed.
Probably a lot more questions will arise, hopefully things will be clearer once the final regulations are wriiten - closer to May.
I took a quick look at the current GDPR documentation and got a headache. Does anyone have a link they could share that boils the bureaucratic babble-speak down into a set of requirements?
There was an interesting discussion about GDPR over at the dark side :D (osCommerce forum), and there was this link, that has some useful information
Great article.
I guess a new ticket box at registration page is needed ? ( like newsletters ? ), making a new field at customers table ?
I still don't know what it's done with existing customers. Do we have to email them to agree with the new terms ? That would be easy, but, reading this thread, (actually I never thought on that), there is no way that a customer can delete their account now... never search the forum or modules on that.
I don't have 250 employees ( only 249 :smile:), but even so, I think this is a important thread.
Right to Access
Part of the expanded rights of data subjects outlined by the GDPR is the right for data subjects to obtain from the data controller confirmation as to whether or not personal data concerning them is being processed, where and for what purpose. Further, the controller shall provide a copy of the personal data, free of charge, in an electronic format. This change is a dramatic shift to data transparency and empowerment of data subjects.
https://www.eugdpr.org/key-changes.html
I love EU. It makes us think. So what data is zencart default core, collecting from customers (extra modules apart) ?
Registration fields ( that can or not be required)
Last login / logout
Customer basket
So I guess that one also has to make some kind of export / display at customer page.
That data would include all fields in the following Zen Cart database tables:
- address_book (one entry for each stored customer address)
- customers (name, email, newsletter opt-in and more)
- customers_info (last login, account-creation date and more)
- customers_basket, customers_basket_attributes (products, with optional attributes, stored in their basket)
- orders, orders_products, orders_products_attributes (orders that the customer has placed, along with the purchased products and their optional attributes).
- paypal (if your store uses one of the PayPal payment variants, for any order paid via PayPal).
- reviews (could contain the customer's full name)
and
8. authorizenet (if used)
9. coupon_gv_customer, coupon_gv_queue, coupon_redeem_track (I've never used coupons so not entirely sure what exactly is captured)
10. whos_online (surely not!)
11. files_uploaded
12. products_notification
Non ZC table that will cause a headache - user_tracking!
Thanks for the follow-up!
Note that stores that provide one-time coupons could have issues when removing a customer's account (since the one-time usage is tied to a customers_id). Once the account is removed, the customer is free to re-create their account and, again, enjoy the benefits of that coupon.
Also,
13. admin_activity_log
14. coupon_email_track
15. coupon_gv_queue
16. coupon_redeem_track
17. email_archive
18. In addition to the reviews table (perhaps eluded to) reviews_description.
These all potentially contain information about the customer and/or their activities, etc. Yes, even the admin_activity_log contains operations performed on the admin side related to processing a customer's data.
Under GDPR do we need consent to tell a customer we have despatched their goods? The way I read it we do. If this is the case then changes will be required to the order system, create account etc. to allow us to know if they want this contact. Additionally changes may be required to admin to allow/block e-mails or any other form of contact that we may choose to make.
Additionally is suggest that all customer data should be encrypted. Would this be a core change to the database/zen cart.
But if a site uses SSL I guess it's encrypted.
So, the list gets bigger.
In sum: zencart admin function to delete an account could be "altered" to allow a customer to delete is own account killing the session.
I'm thinking out loud, cause I don't use zencart with his full power and features.
In terms of export data ( still thinking out loud), it seems that two kind of exports have to exists.
One to deal with a customer request, another from some other auditorie .
This could be accomplished using EP4 ( or DB I/O), for a complete export.
The personal data export, could follow the same principles.
Of course this would implie the use of this scripts.
So maybe it's better to start from scratch...
Not sure what "deleting their account" actually means?
What about all their "orders"?
Can't delete those as by law we need to keep this info for at least 7 years for tax purposes here in Oz
As well if you actually deleted "orders" we wouldn't be able to do basic stock control and profit and loss etc....
Perhaps it means renaming the account somehow to keep the actual data but to remove all customer identifying details?
If so then how would you handle cases when the government wants details on who you sold stuff to?
Perhaps it only applies to online data. Maybe you can keep printed offline records of all this stuff?
Just thinking here....
As the only core team member residing in the EU, thought I would offer my thoughts here.
First, as mentioned in a previous post, be wary of scaremongers, especially when they are consultants looking to make some money from you.
The first steps in compliance is to make sure your Privacy and Conditions of use tell the customer exactly what data you are collecting, what use it is put to, and how to contact you if they have concerns or want you to amend/delete their data.
Another big issue is consent. Using Agree to terms on both sign up and checkout will help here. Also remember that any consent should be opt in, don't automatically check those checkboxes.
Zen Cart by default does not have a Cookie consent pop up, although there are modules that you can install.
When you are collecting information, make sure you are only collecting information you really need. Do you really need a customers telephone number, their date of birth etc. If you are collecting that information then tell the customer why you need it.
On the right to forget, there are obviously some conflicts here. While its easy to delete a customers record, if they have made orders then personal info is also stored in the order. However as a general principle, the tax requirements to keep order information for n years will override the GDPR requirements. Again this fact should be shared with the customer in your privacy policy.
On encryption. The actual section in the wonderful GDPR documentation does not make it an absolute necessity, at least as far as database encryption is concerned. However no store now should ever operate without SSL, and as a general principle should use SSL site wide and not just for admin/checkout.
Finally, I am not a lawyer. My advice above is based on my reading of GDPR, and my experience working with Zen Cart for many many years :)
I never took close look on the customers tables and all that stuff.
I was thinking about creating a new table that could save the customers agreement in the new gdpr laws. But there's a beautiful table called customers_info, that could hold this extra info.
My concern is on future zencart updates. I belive in principle that it will update tables without removing extra columns , right ?
About the 7 years. I believe this depends if one is using zencart as a accounting software.
This has been the operation of ZC for as far back as I have seen the install/upgrade process work. In fact there was discussion that one of the ZC provided tables had a field in it that was never used in core code (final_price as found in the customers_basket table). Removal of that field (from the install script and from the database in the upgrade process) was under review for nearly a year. Now, this was a direction to affect a field within a table that was generated by core Zen Cart code. Otherwise, the process has been to still generally leave other fields and tables alone to be controlled by some other process. So, provided the path forward continues to be one of Zen Cart taking care of its own tables and fields with any other modifications made to be addressed by an applicable process, you can yes use the customers_info table to track this additional field.
Thanks !
I see now that I was inventing the wheel. The zencart terms and conditions configuration, can handle this bit at the registration page! Cool!
Edit:
Not so cool! However it seems that it's not inserting this data anywhere...
I'm glad our volume of sales exempts us from all/Most of this.
I guess something like bbc.com , where you can control what cookies are in place. So one could stop analytics or whatever to run before user consent.
However zencart uses IP from visitors, and IP are now considered personal information.
A lot of issues here.
I've given some thought to how to implement the 'right to be forgotten'. Some years ago Kuroi highlighted a potential fraud issue with allowing customers to delete their own accounts. So given that I'm unlikely to have to deal with many account deletions I've gone down the road of having a customer request that their account be deleted - click on a button and it sends me an email requesting such. In case anyone's interested:
I added a link in the customers Account page (\includes\templates\my_template\templates\tpl_account_default.php) pointing to a 'Delete My Account' page.
I created 3 new files:
\includes\languages\english\my_template\account_delete.php
\includes\templates\my_template\templates\tpl_account_delete_default.phpCode:define('HEADING_TITLE', 'Delete My Account');
define('NAVBAR_TITLE_1', 'My Account');
define('NAVBAR_TITLE_2', 'Delete Account');
define('TEXT_SUCCESS_ACCOUNT_DELETE', 'Your request for your account to be deleted has been successfully sent and will be actioned as soon as possible.');
define('ACCOUNT_DELETE_INFORMATION', 'Do you wish to delete your account? Please confirm by clicking the button below. <br/><br/>This will notify us of your request and we will delete your account as soon as possible (by law we must action your request within one month).<br/><br/>Please note that this will permanently remove all of your personal information, including order history, from our system.');
define('EMAIL_SUBJECT', 'Website Enquiry from ' . STORE_NAME);
define('ENTRY_NAME', 'Full Name:');
define('ENTRY_EMAIL', 'Email Address:');
define('ENTRY_ENQUIRY', 'Message:');
define('MESSAGE_BODY', 'Please permanently delete my account');
define('MESSAGE_CUSTOMERS_ID', 'customers_id: ');
\includes\modules\pages\account_delete\header_php.phpCode:<article id="main">
<header><h1><?php echo HEADING_TITLE; ?></h1>
</header>
<section class="wrapper style5">
<div class="inner">
<?php echo zen_draw_form('account_delete', zen_href_link(FILENAME_ACCOUNT_DELETE, 'action=send', 'SSL')); ?>
<?php
if (isset($_GET['action']) && ($_GET['action'] == 'success')) {
?>
<div class="mainContent success"><?php echo TEXT_SUCCESS_ACCOUNT_DELETE; ?></div>
<br class="clearBoth" />
<div class="buttonRow"><?php echo zen_back_link() . zen_image_button(BUTTON_IMAGE_BACK, BUTTON_BACK_ALT) . '</a>'; ?></div>
<?php
} else {
?>
<?php echo zen_draw_input_field('contactname', $name, 'style="visibility:hidden; display:none;"'); ?>
<?php echo zen_draw_input_field('email', ($email_address), 'style="visibility:hidden; display:none;"'); ?>
<?php echo zen_draw_input_field('enquiry', $enquiry, 'style="visibility:hidden; display:none;"'); ?>
<fieldset class="accountDelete">
<legend><?php echo HEADING_TITLE; ?></legend>
<?php echo ACCOUNT_DELETE_INFORMATION; ?>
</fieldset>
<div class="buttonRow forward"><?php echo zen_image_submit(BUTTON_IMAGE_CONFIRM,BUTTON_CONFIRM_DELETE_ALT); ?></div>
<div class="buttonRow back"><?php echo '<a href="' . zen_href_link(FILENAME_ACCOUNT, '', 'SSL') . '">' . zen_image_button(BUTTON_IMAGE_BACK, BUTTON_BACK_ALT) . '</a>'; ?></div>
<?php
}
?>
</form>
<br class="clearBoth" />
</div>
</section>
</article>
and added a line to:Code:$zco_notifier->notify('NOTIFY_HEADER_START_ACCOUNT_DELETE');
if (!$_SESSION['customer_id']) {
$_SESSION['navigation']->set_snapshot();
zen_redirect(zen_href_link(FILENAME_LOGIN, '', 'SSL'));
}
require(DIR_WS_MODULES . zen_get_module_directory('require_languages.php'));
$error = false;
if (isset($_GET['action']) && ($_GET['action'] == 'send')) {
$name = zen_db_prepare_input($_POST['contactname']);
$email_address = zen_db_prepare_input($_POST['email']);
$enquiry = zen_db_prepare_input(strip_tags($_POST['enquiry']));
$sql = "SELECT customers_id, customers_firstname, customers_lastname, customers_password, customers_email_address, customers_default_address_id
FROM " . TABLE_CUSTOMERS . "
WHERE customers_id = :customersID";
$sql = $db->bindVars($sql, ':customersID', $_SESSION['customer_id'], 'integer');
$check_customer = $db->Execute($sql);
$customer_email= $check_customer->fields['customers_email_address'];
$customer_name= $check_customer->fields['customers_firstname'] . ' ' . $check_customer->fields['customers_lastname'];
$send_to_email = trim(EMAIL_FROM);
$send_to_name = trim(STORE_NAME);
// Prepare extra-info details
$extra_info = email_collect_extra_info($name, $email_address, $customer_name, $customer_email);
// Prepare Text-only portion of message
$text_message = OFFICE_FROM . "\t" . $name . "\n" .
OFFICE_EMAIL . "\t" . $email_address . "\n\n" .
'------------------------------------------------------' . "\n\n" .
strip_tags($_POST['enquiry']) . "\n\n" .
'------------------------------------------------------' . "\n\n" .
$extra_info['TEXT'];
// Prepare HTML-portion of message
$html_msg['EMAIL_MESSAGE_HTML'] = strip_tags($_POST['enquiry']);
$html_msg['CONTACT_US_OFFICE_FROM'] = OFFICE_FROM . ' ' . $name . '<br />' . OFFICE_EMAIL . '(' . $email_address . ')';
$html_msg['EXTRA_INFO'] = $extra_info['HTML'];
// Send message
zen_mail($send_to_name, $send_to_email, EMAIL_SUBJECT, $text_message, $name, $email_address, $html_msg,'contact_us');
zen_redirect(zen_href_link(FILENAME_ACCOUNT_DELETE, 'action=success', 'SSL'));
} // end action==send
// default email and name if customer is logged in
if($_SESSION['customer_id']) {
$sql = "SELECT customers_id, customers_firstname, customers_lastname, customers_password, customers_email_address, customers_default_address_id
FROM " . TABLE_CUSTOMERS . "
WHERE customers_id = :customersID";
$sql = $db->bindVars($sql, ':customersID', $_SESSION['customer_id'], 'integer');
$check_customer = $db->Execute($sql);
$email_address = $check_customer->fields['customers_email_address'];
$name= $check_customer->fields['customers_firstname'] . ' ' . $check_customer->fields['customers_lastname'];
$customers_id = $check_customer->fields['customers_id'];
$enquiry = MESSAGE_BODY . ' (' . MESSAGE_CUSTOMERS_ID . $customers_id . ')';
}
$breadcrumb->add(NAVBAR_TITLE_1, zen_href_link(FILENAME_ACCOUNT, '', 'SSL'));
$breadcrumb->add(NAVBAR_TITLE_2, zen_href_link(FILENAME_ACCOUNT_DELETE, '', 'SSL'));
// This should be last line of the script:
$zco_notifier->notify('NOTIFY_HEADER_END_ACCOUNT_DELETE_PROCESS');
\includes\languages\english\my_template\button_names.php
All this gives give meCode:define('BUTTON_CONFIRM_DELETE_ALT', 'Yes, Delete My Account');
Attachment 17789
A click on the button gives a 'message received and understood' page and an email is sent to the address in the admin > configuration > e-mail options > Email Address (sent FROM) field.
This is just a copy and paste job (so there are probably plenty of errors/omissions/redundant code).
Edit: forgot to say that I've posted the full code from the three files so there'll be some custom HTML tags that won't relate to the standard ZC template
And just for my curiosity, as I don't need to implement this (yet)
What data do you actually delete when you decide to go ahead with their request?
That's a good question. I haven't quite decided that, still looking into it.
Thanks!
I'm going on the same road, was about to do that, so it's a good thrust.
So far I've battle with javascript to manage to change the cookiecontent script to allow a user configuration.
Basically, it starts with zenid ( but I think that analytics with IP anonymization is allowed) and sets some other cookies uppon user configuration.
They will permit or not, the entrance of different levels of FB pixel, remarketing, etc... with tag manager (that I still have to learn a bit more)
I've created a new table "customers_gdpr" that will save the users consent on registration, date, etc...
A observer that will check the registration page to insert thos values on that table, and also check registers customers prior to this law, so if they start a session, redirects then to the account where may signal their agreement. (it's the same form used on registration page. ) .
That notification is also recorded in the customers_gdpr, so even if a customer chooses not to agree, there is a record that has been notified.( with a date)
Now it's that part, allowing the deletion of a account upon request.
What to delete: there's no general answer to that, it really depends on the the size of the business and what kind of data that business asks and holds and the business informs.
As far as I'm concern:
There's a registered user that never made a purchase, or a comment. Don't see a problem here
There's a registered user that never made a purchase but made some comments, etc. I don't see a problem here.
There's a customer, bougth some stuff:
We don't use zencart as a accounting software, neither we have integrations between other accounting plataforms (ie: sage pay) and zencart, so that purchase is registered on another software and can not be deleted according to our national law. We only ask the necessary data and hold the necessary data.
But online, I don't see a problem either. The customers for what ever reason wants to leave, he leaves. I agree with that.
That's the conclusion that our team of lawyers, highly reputable consultants, and implementation jscript programmers, php and mysql made.
A team made up of me, myself, and sometimes I.
And that's it. I'm done with this.
In fact I'm looking forward for this law, because I'm also a customer, and I want to ask some questions to some big communication companies over here about my data.
Re Cookie Control, I'm probably going to do something like cookiebot . com, although I don't like the way their cookie banner disappears when I start scrolling. Hopefully when I sign up for a free account, and taking into account your ideas, I'll get a better idea of how to implement it on my site .
On my system I think that deleting the Customer and their associated Orders from withing the ZC Admin will be enough to remove customer identifiable information. Deleting an order affects a number of dbase tables but I think I might adjust this to keep the Order in TABLE_ORDERS_PRODUCTS at least then ZC has a record of products sold.
Cookie Control, now it's the time to make money. I've searched for some free scripts that would allow some sort of configuration. Didn't find any, but it's a big internet.
Maybe the cookieconsent script will be updated to give this option.
I'm using foundation has a base template. I've added a link "Configure" to the cookie consent that will use the foundation reveal "module" ( a popup), a form using the foundation switch module. So it's mix of php and jscritp and cookies
But it all can be done using jscritp, but I don't have the knowledge to do that neither the time.
https://cookieconsent.insites. com/documentation/disabling-cookies/
In the cookie consent script I created another status ( Config) , basically a copy from the "allow" status. More or less you can get the idea, just check where the cc.status.allow is used.
In the configuration ( window.addEventListener("load", function () { ) ( has to be set to add the new status ( When I say has, please read maybe )Code:// valid cookie values
cc.status = {
deny: 'deny',
allow: 'allow',
dismiss: 'dismiss',
config: 'config'
};
"revokable": "true",Code:"content": {
"allow": "Allow",
"config": '<i class="ic_settings_white_1x_small"></i>Configure'
},
"type": "opt-in",
Then all is going to be on the
onPopupOpen: function onPopupOpen(status, chosenBefore, options, utils) {
onStatusChange: function onStatusChange(status, chosenBefore) {
The only reason I don't paste here the complete code, it's because I know that makes the job for me, but it's a quick bandage, and it's using foundation base modules, and it's cookies strategies to configure cookies ( a paradox )
To be a general scritp , a lot of JavaScript knowledge is required.
But what was the more complicated part for me, was this.
The rest is a form, with input checkboxes, etc... With PHP i'm checking the cookie config , and allowing or not analytics etc....
Again, this is not a copy paste, but a general idea.
PHP Code:
"use strict";
function delete_cookie(name, domain) {
document.cookie = name + '=; Path=/; Expires=Thu, 01 Jan 1970 00:00:01 GMT; Domain=' + domain;
}
window.addEventListener("load", function () {
var host = window.location.hostname;
window.cookieconsent.initialise({
"palette": {
"popup": {
"background": "#000"
},
"button": {
"background": "#f1d600"
}
},
"layout": "basic",
"theme": "edgeless",
"content": {
"message": "bla bla bla:",
"dismiss": "ok",
"allow": "Aloow Cookies",
"link": "Privacy Link",
"href": "thelinink . com ",
"config": '<i class="ic_settings_white_1x_small"></i>Configure'
},
"revokable": "true",
"type": "opt-in",
onPopupOpen: function onPopupOpen(status, chosenBefore, options, utils) {
var type = this.options.type;
var hasConsented = this.hasConsented(); // allow, dismiss, deny, config
var didConsent = hasConsented;
var cfgCookiesAnalytics = '';
var cfgCookiesExternal = '';
// to check if analytics is GDPR compliant
var isAnalyticsChecked = document.getElementById('c-analytics');
var isExternalChecked = document.getElementById('c-external');
function updateState(input) { //This is update the input buttons state
var inputName = input.name == 'secondaryC-switch' ? 'secondaryC-switch' : 'secondaryC-switch-external';
if (inputName == 'secondaryC-switch' && input.checked) {
cfgCookiesAnalytics = 'active';
} else if (inputName == 'secondaryC-switch' && !input.checked) {
cfgCookiesAnalytics = 'inactive';
isExternalChecked.checked = false;
cfgCookiesExternal = 'inactive';
}
if (inputName == 'secondaryC-switch-external' && input.checked) {
cfgCookiesExternal = 'active';
isAnalyticsChecked.checked = true;
cfgCookiesAnalytics = 'active';
} else if (inputName == 'secondaryC-switch-external' && !input.checked) {
cfgCookiesExternal = 'inactive';
}
return false;
}
var cookieForm = document.getElementById("ccForm");
// listen to input events
cookieForm.addEventListener("click", checkInputState, false); // It's going to listen to the INPUT buttons
function checkInputState(e) {
if (e.target.nodeName == "INPUT") {
var listen = updateState(e.target);
}
e.stopPropagation();
}
// console.log('ce: ' + cfgCookiesExternal + ' - ca ' + cfgCookiesAnalytics);
var saveConfig = document.querySelector('[aria-label="config cookie"]');
// define cookie
var cname = this.options.cookie.name;
var expiryDays = this.options.cookie.expiryDays;
var path = this.options.cookie.path;
var domain = this.options.cookie.domain;
var allDomains = '.' + document.location.hostname;
if (saveConfig.addEventListener) {
saveConfig.addEventListener("click", function (checkInputState) { // On save will get the Input Buttons State
//event.preventDefault();
if (cfgCookiesAnalytics == 'active' && cfgCookiesExternal == 'active') {
didConsent = 'config';
var set = cookieconsent.utils.setCookie(cname, 'allow', expiryDays, domain, path);
setTimeout(function () {window.location.reload(true);}, 100);
} else {
didConsent = 'config'; // flag some user interaction
delete_cookie('_ga', allDomains);
delete_cookie('_gid', allDomains);
var set = cookieconsent.utils.setCookie(cname, didConsent, expiryDays, domain, path);
setTimeout(function () { window.location.reload(true);}, 100);
}
var getCookieName = '';
if (cfgCookiesAnalytics == 'active') { // Analytics is good to go
var set = cookieconsent.utils.setCookie('cc_analytics', 'allow', expiryDays, allDomains, path);
} else {
getCookieName = cookieconsent.utils.getCookie('cc_analytics');
if (getCookieName) {
delete_cookie('cc_analytics', allDomains);
}
}
if (cfgCookiesExternal == 'active') {
// review this bit, if it's active, analytics cookie is also active
var set = cookieconsent.utils.setCookie('cc_allowSocial', 'allow', expiryDays, allDomains, path);
} else {
getCookieName = cookieconsent.utils.getCookie('cc_allowSocial');
if (getCookieName) {
delete_cookie('cc_allowSocial', allDomains);
}
}
}, false);
}
},
onInitialise: function onInitialise(status, chosenBefore) {
var type = this.options.type;
var hasConsented = this.hasConsented();
var hasAnswered = this.hasAnswered();
//console.log( 'onInitialise' + hasConsented + hasAnswered + type);
if (type == 'opt-in' && hasConsented == true) {
// enable cookies
}
if (type == 'opt-out' && !hasConsented) {
// disable cookies
}
},
onStatusChange: function onStatusChange(status, chosenBefore) { // The user revoke his choice
var type = this.options.type;
var hasConsented = this.hasConsented();
var hasAnswered = this.hasAnswered();
if (this.hasAnswered() && this.hasConsented()) {
setTimeout(function(){ window.location.reload(true) }, 100);
// Put Your Google Analytics Tracking Code here ( Not using this, but this is the way to go )
}
if (!hasConsented || !hasAnswered) {
setTimeout(function(){ window.location.reload(true) }, 100);
// Put Your Google Analytics Tracking Code here
}
},
onRevokeChoice: function onRevokeChoice() {
var type = this.options.type;
var hasConsented = this.hasConsented();
if (type == 'opt-in' && hasConsented) {
// enable cookies
}
if (type == 'opt-out' && !hasConsented) {
// disable cookies
}
}
});
});
I forgot to put the link https://www.kirupa.com/html5/handlin...y_elements.htm
That's the function ( checkInputState ) that it's called on save. First I had a bunch of listeners that row me nowhere.
Bits of this, bits of that
What would be the implications in Zencart if instead of deleting orders, we could update orders only deleting personal information ?
Something like returning the table to default values ?
UPDATE orders SET
customers_name = 'User Deleted OR EMPTY',
customers_company = DEFAULT,
customers_street_address = DEFAULT,
customers_email_address = DEFAULT,
customers_street_address = DEFAULT
etc, etc, etc,
WHERE customers_id = 1;
You should not delete the orders, or edit personal data in the orders. That is in may countries illegal, and will destroy your audit trail.
It is allowed to keep personal data in the orders, as long as you tell your customers you have that data, and tell them it has to be kept for a certain amount of years.
Ok, but let's say in theory, this could be done. No zones stuff would get in the way, etc ? That's what I'm trying to find out ( in a lazy way I confess)
I'll start now by not deleting any orders ( honestly I'm really tired :sleep1: ).
More or less I made the changes and we are ready for the new regulation.
My only doubt is this one, since we are not using zencart as a accounting software, neither we could use it here, since it's not certify , etc..
So the customers with orders that asks to delete their personal data, we will give then the option to remove online data, but we can not delete a invoice from the accounting software. That's clear crystal.
But online, we really don't need that info, since we are not providing their info to google or whatever.
We have "physical" stores, and that assembles to a customer that enters the shop, provides me with his name, address, mail, phone number, etc , and goes to a corner of the shop and stays there for the rest of his live.
I'm not expecting tons of removal requests, but we have to be ready for the first, since we will notify our customers (all of them) but specially the ones without orders of our new privacy policy.
There are no exceptions in terms of data protection, and it's not just online. Just different levels of implementation regarding what kind of data do you hold, the amount of data and for what purposes.
For example, your site sets analytics cookies without asking. If the IP is anonymous ( there's a configuration in analytics for that ), it's considered not personal Information. If it tracks the complete IP , then it's personal data, since it can track your localization , and google loves locations to sell.
Basically we all work for google for free.
For security reasons, a company can track IP. But the user has to consent, or at least there must be some sort of information that explains why a company need that data.
If you have more than 250 employees, then a company must have a kind of data manager.
If there's a data breach, all companies are obliged to report that to authorities ( dont« recall the name )
https://ec.europa.eu/info/law/law-to...rsonal-data_en
Quote:
Personal data is any information that relates to an identified or identifiable living individual. Different pieces of information, which collected together can lead to the identification of a particular person, also constitute personal data.
Personal data that has been de-identified, encrypted or pseudonymised but can be used to re-identify a person remains personal data and falls within the scope of the law.
Personal data that has been rendered anonymous in such a way that the individual is not or no longer identifiable is no longer considered personal data. For data to be truly anonymised, the anonymisation must be irreversible.
in a certain way, this all comes down to politics losing the power to big data processors and data controllers.
And a huge amount of data anarchy using user tags, like email, id , cart connections, etc.
The internet moved from piracy to piracy.
Money Laundering statutory requirements, as well as accounting requirements trump GDPR
Sorry, I must have been day-dreaming when I thought there were minimum thresholds for compliance because I can't fine it now but we eliminated any 'targeting' for EU sales and removed the euro as an acceptable currency.
Been trying to think this through with customer deletions.
If a customer request their record be deleted. If we remove all records from the following tables.
zen_address_book
zen_customers
zen_customers_basket
zen_customers_basket_attributes
zen_customers_wishlist
zen_files_uploaded
zen_products_notifications
zen_reviews
zen_whos_online
Not sure about coupons if they need to be kept.
zen_coupon_gv_customer
zen_coupon_gv_queue
zen_coupon_redeem_track
Could we keep the following tables intact with out breaking zen cart. This way we still hold records of the transactions and customer and shipping details.
zen_authorizenet
zen_orders
if this appears ok a delete function could be added to the My account processing.
Could also change this to hold an optin for marketing messages/newsletters.
This works for people who create an account.
Might need equivalent added to admin for people who use paypal express checkout or check out as guest (not sure if customer account is created when they checkout in this way).
Done a bit more research. It appears that if someone uses PayPal express checkout they have an account created for them (in our store) each time they use it. So Admin function to delete also needed.
Remember that the "Delete" button for deleting a customer already handles deleting non-order-related information: https://github.com/zencart/zencart/b....php#L362-L414
Remember: deleting the customer record means they can no longer gain access to anything that requires a login ... including virtual purchases. Might want to inform them of that if you're entertaining such requests.
Those same "accounts" are listed along with all other customer accounts, so nothing extra/special needed.
Remember: the "right to be forgotten" initiated with the problem of public social media posting, not with ecommerce transactions. With your store, the public-facing data would primarily be "product reviews", or other features you've added such as "testimonials".
Double-check with your legal team whether you're going too far with the amount of data you're considering deleting. Check also with your accountant about transaction data retention requirements, particularly if your online store is the primary record of your transactions.
A lot of websites are sending email to ask to resubscribe to newsletter. Are there any implications for not doing this? I asked the newsletter people I use, even they are not sure how to proceed.
They must have a way to opt-out. If you use ie: mailchimp, there's always a footer with your details and a unsubscribe link.
I was told today, that even if a customers agrees with with company's privacy policies, that should be renewed 1 year later. ie: cookies, etc
Another thing that I still didn't find, it's a Document that must be keap, because even if we do all correct, if we don't fill that kind of form saying what we did and why, it useless. Wich makes sense. It has to be save, recorded, somewhere.
If anyone knows the name of that form or file, please post
What Sage is doing on upcoming updates ( at least here for what I've been told ), it's to delete all data that it's not required to be in a invoice.
I've extended the zencart delete function, to check other tables, like rewards points, etc, it really depends on what's installed, and in the Orders, If a customer wants to delete the account, but has placed a order, I'll update the email to empty or something that the table default value accepts.
Has anyone solved complications with GDPR? I solve this for a long time now, and I still don't have a complete solution, just minor modifications.
I'm looking for a module or someone who will be able to solve the problem of customer deletion + all the links with. Please for info, thanks in advance.
@DarkMen,
Really depends on your site data collection , etc.
For cookies opt-in : there is a "free" script from One trust ( just in english last time I saw) . But if you need more, perhaps you'll have to pay.
Is it worth it or not ? Depends on your site sales, etc.
The one from cookie consent can be altered also , but it takes some work, etc...
Deleting a customers: Zencart already does that, the only issue is on orders. I've opt to update the customers data that I don't need for a invoice. Also you must check other tables ( additional modules that may have customers info).
There is a post here in this thread where you have a way to do this in the account files. Perhaps it's a start.
Hey all is there a way to add a memorable question to the sign in forms with FEC that we can see on their account ..Both account and non account, it's so we can prove it is really them and not someone else ..It's 1 of the GDPR requirements.
I've got the delete account sorted as it can be done
Also got to add a data capture form on website ,but can't exactly remember what I was told so need to check on that
That's actually not a bad idea ... Once the order is completed..Well I send a final email , you could also add would you like to delete account yes / no
Question for the GDPR knowledgeable folks...
How does "Canvas Fingerprinting" relate to GDPR since it identifies a specific piece of hardware (computer, tablet, phone, etc) and then has ability to track that hardware presence across the internet in a seemingly more intrusive manner than a cookie? But since it does not identify a person or any PII, does that make a Canvas Fingerprint OK in terms of GDPR?
Not trying to open a can of worms but I am seeing more canvas fingerprinting popup notices and some websites actually stop working if fingerprinting is blocked or if a fake fingerprint is transmitted.
@Darkmen
Please PM me if you still need help.
To summarise the essentials of GDPR ....your users must
give Explicit Consent for you to use their data for the purposes you intend,
have Access to their information and
have the Option to remove their information.
Zencart has Consent (you may need to set admin> configuration > regulations ...Confirm Privacy Notice During Account Creation Procedure to true) and Access (through My Account) in place while the Option to Remove exists in the sense that the user must inform you that they want to have their data removed upon which you can delete their account from admin > customers > customers, but there is not really the clear guidance that GDPR demands.
Giving consent extends to your existing clients, so they need to have the opportunity to review and Accept/Decline your privacy policy.
So we've added 2 new links in My Account for Review and accept privacy statement and Delete My account.
The former takes the user to a page which displays the contents of admin > tools > define_pages_editor...define_privacy.php, with buttons to Accept or Decline. If they Accept, they continue with whatever they were doing, but if they decline, they are logged out and taken to a page which explains why, and lets them know they can log back in and change their mind, otherwise their account will be deleted.
Whichever decision they make, the date is recorded in the database and a flag also set to show the decision. These flags can then be used by those with appropriate skills to identify and automatically delete accounts. You would need to action Delete Requests manually via admin > customers > customers where, as a reminder, deleting the customer does not delete their past orders which you are legally required to retain in the UK by HMRC for 6 years.
It would also be necessary to email your existing customer base to invite them to visit the site and login to update their preferences.
Admin functions
You can specify the email address to which the Delete requests are sent.
Should you need to modify your privacy statement and require people to re-consent, you can reset so that the client will have to review the privacy on their next login.
The date of acceptance (or otherwise) displays in the customer info page.
There is a sortable and "searchable by email" display of all those who HAVE accepted
This manual version of our GDPR package for Zencart was written for ZC155 (although it will work on older) and for now you can download it from http://jsweb.uk/gdpr_service/gdpr4zc.zip as we haven't had time yet to meet the documentation requirements for submitting to the plugins section.
Thank you will use your package ...
Re memorable question I have been advised to have this option as it can prove who you are if you actually want your details known or not.. Don't blame me I'm just trying to do what I have been advised to do by a legal advisor...Apparently if you have a account and you separate your partner or who ever cannot access your account without knowing the memorable password
Apparently we are also suppose to have a data capture form on website ..
I personally do not want all this, so if anyone can advise that would be great
@mesnitu - can you tell us how did you manage to handle the consent problem? How did you create the field that records user's consent value and date (the Privacy Checkbox thick). We are trying to achieve this in order to prove given consent from new customers as of 25 may.
10x
I'm using the default zencart "Regulations->Confirm Privacy Notice During Account Creation Procedure"
But since that Confirm Privacy Notice is not registered anywhere , I had to create a table to save all records on create account and existent users.
So if a user creates a account, he has to accept. If a existing user login he's notify and that notification is registers. If he accepts or not, really doen't matter. I just need to have something to show that the client was notify and is aware of that, etc,etc...Code:CREATE TABLE `customers_gdpr` (
`customers_id` int(11) NOT NULL,
`customers_account_created_date` datetime DEFAULT NULL,
`customers_accept_terms` tinyint(4) DEFAULT '0',
`customers_accept_terms_date` datetime DEFAULT CURRENT_TIMESTAMP,
`customers_was_notify_date` datetime DEFAULT NULL,
`customers_delete_account_request` tinyint(4) DEFAULT '0',
PRIMARY KEY (`customers_id`)
) ENGINE=InnoDB DEFAULT CHARSET=utf8
I just use the confirm privacy regulation at account creation and accept terms and conditions at the point of sale.
I do not think there is a need to keep a record that they accepted it as they cannot create an account without accepting it or place an order without accepting terms.
I did change the wording on the terms one to say accept and read terms and privacy policy. That should be proof enough for anyone.
DO NOT COPY AND PASTE, cause it will not work.
create a file at "auto_loader" folder, to load observer and init_scripts
THE OBSERVER - It checks at create account and loging. Sends some emails, etc...PHP Code:
$autoLoadConfig[190][] = array('autoType'=>'class',
'loadFile'=>'observers/class.customer_gdpr.php');
$autoLoadConfig[190][] = array('autoType'=>'classInstantiate',
'className'=>'CustomerGdpr',
'objectName'=>'CustomerGdpr');
$autoLoadConfig[180][] = array('autoType'=>'init_script',
'loadFile'=> 'init_customers_rgpd.php');
INIT_SCRIPTPHP Code:
<?php
/**
* customerGdpr Class.
* This class is used to manage customers RGPD compliance
*
* @package classes
*/
class CustomerGdpr extends base {
private $has_accepted = false;
private $was_notify = false;
private $was_notify_date = '';
var $users_delete_request = '';
function __construct() {
global $zco_notifier;
$notifyme = array();
// if not redirects to account page
$notifyme[] = 'NOTIFY_LOGIN_SUCCESS';
// Now the customer can agree or not. Either way it was a record is inserted in DB
$notifyme[] = 'NOTIFY_HEADER_END_ACCOUNT';
// Inserts privacy policy into DB at registration page
$notifyme[] = 'NOTIFY_MODULE_CREATE_ACCOUNT_ADDED_CUSTOMER_RECORD';
$this->attach($this, $notifyme);
if($_SESSION['customers_delete_account_request']==1) {
$this->users_delete_request = true;
}
}
/**
* NOTIFY_LOGIN_SUCCESS
* Verifica se o cliente já concordou com a RGPD.
*/
public function updateNotifyLoginSuccess(&$callingClass, $notifier, $paramsArray) {
global $db, $messageStack;
if ($_SESSION['customer_rgpd'] =='' && $_SESSION['customer_rgpd_notified'] == '') {
$customer_id = $_SESSION['customer_id'];
$customers_info = $db->Execute("SELECT customers_info_date_account_created FROM " . TABLE_CUSTOMERS_INFO . " WHERE customers_info_id=" . (int)$customer_id. ";");
$sql = " SELECT * FROM ".TABLE_CUSTOMERS_GDPR." WHERE customers_id = :customers_id: ";
$sql = $db->bindVars($sql , ':customers_id:', $_SESSION['customer_id'], 'integer');
$res = $db->Execute($sql);
if ($res->RecordCount() == 0) {
$sql = "INSERT INTO ".TABLE_CUSTOMERS_GDPR." VALUES (:customers_id:, :customers_account_created_date:, :customers_accept_terms:, :customers_accept_terms_date:, :customers_was_notify_date:, :customers_delete_account_request:)";
$sql = $db->bindVars($sql , ':customers_id:', $customer_id, 'integer');
$sql = $db->bindVars($sql, ':customers_account_created_date:', $customers_info->fields['customers_info_date_account_created'], 'date');
$sql = $db->bindVars($sql, ':customers_accept_terms:', '0', 'integer');
$sql = $db->bindVars($sql, ':customers_accept_terms_date:', 'NULL', 'string');
$sql = $db->bindVars($sql, ':customers_was_notify_date:', 'NOW()', 'noquotestring');
$sql = $db->bindVars($sql, ':customers_delete_account_request:', '0', 'integer');
$res = $db->Execute($sql);
$_SESSION['customer_rgpd_notified'] = true;
//$messageStack->add_session('site_notifications', $this->displayRgpdMsg(), 'caution');
}
} elseif ($_SESSION['customer_rgpd'] =='0' && $_SESSION['customer_rgpd_notified'] !== '') {
//$messageStack->add_session('site_notifications', $this->displayRgpdMsg(), 'caution');
}
}
/**
* Inserir politica de privacidade no registo do cliente
*/
public function updateCreateAccountAddedCustomerRecord(&$callingClass, $notifier, $paramsArray) {
global $db;
$customer_id = $_SESSION['customer_id'];
$sql = "INSERT INTO ".TABLE_CUSTOMERS_GDPR." VALUES (:customers_id:, :customers_account_created_date:, :customers_accept_terms:, :customers_accept_terms_date:, :customers_was_notify_date:, :customers_delete_account_request:)";
$sql = $db->bindVars($sql , ':customers_id:', $customer_id, 'integer');
$sql = $db->bindVars($sql, ':customers_account_created_date:', 'NOW()', 'noquotestring');
$sql = $db->bindVars($sql, ':customers_accept_terms:', '1', 'integer');
$sql = $db->bindVars($sql, ':customers_accept_terms_date:', 'NOW()', 'noquotestring');
$sql = $db->bindVars($sql, ':customers_was_notify_date:', 'NOW()', 'noquotestring');
$sql = $db->bindVars($sql, ':customers_delete_account_request:', '0', 'integer');
$res = $db->Execute($sql);
unset($sql, $res);
}
// Notifier user account page
public function updateHeaderEndAccount(&$callingClass, $notifier, $paramsArray) {
global $db, $customer_newsletter_status;
global $messageStack;
$customer_id = $_SESSION['customer_id'];
if ( $_SESSION['customer_rgpd'] == '' ) {
if (isset($_POST) && ($_POST['privacy_conditions'] =='1')) {
$_SESSION['customer_rgpd'] = true;
$customers_info = $db->Execute("SELECT customers_info_date_account_created FROM " . TABLE_CUSTOMERS_INFO . " WHERE customers_info_id=" . (int)$customer_id. ";");
$sql = " SELECT * FROM ".TABLE_CUSTOMERS_GDPR." WHERE customers_id = :customers_id: ";
$sql = $db->bindVars($sql , ':customers_id:', $customer_id, 'integer');
$res = $db->Execute($sql);
if ($res->RecordCount() > 0) {
$sql_up = "UPDATE ".TABLE_CUSTOMERS_GDPR." SET customers_id = :customers_id:, customers_account_created_date= :customers_account_created_date:, customers_accept_terms = :customers_accept_terms:, customers_accept_terms_date = :customers_accept_terms_date:, customers_was_notify_date = :customers_was_notify_date: WHERE customers_id = :customers_id:";
$sql_up = $db->bindVars($sql_up , ':customers_id:', $customer_id, 'integer');
$sql_up = $db->bindVars($sql_up, ':customers_account_created_date:', $customers_info->fields['customers_info_date_account_created'], 'date');
$sql_up = $db->bindVars($sql_up, ':customers_accept_terms:', '1', 'integer');
$sql_up = $db->bindVars($sql_up, ':customers_accept_terms_date:', 'NOW()', 'noquotestring');
$sql_up = $db->bindVars($sql_up, ':customers_was_notify_date:', 'NOW()', 'noquotestring');
$res_up = $db->Execute($sql_up);
$messageStack->add_session('site_notifications', 'Obrigado por Actualizar!', 'caution');
}
//Send Emails
$to_name = STORE_NAME;
$to_address = EMAIL_FROM;
$email_subject = "Cliente Aceita Politica de privacidade";
$email_text = "------------------------------------------------------------"."\n";
$email_text .= "O Cliente " .$customer_id." aceitou politica de privacidade"."\n";
$email_text .= "-----------------------------------------------------------"."\n";
$from_email_name = STORE_NAME;
$from_email_address = EMAIL_FROM;
$html_msg['EMAIL_MESSAGE_HTML'] = strip_tags($_POST['privacy_conditions']);
zen_mail($to_name, $to_address, $email_subject, $email_text, $from_email_name, $from_email_address, $html_msg );
}
unset($sql, $res, $sql_up, $res_up,$_POST['privacy_conditions']);
}
//DELETE ACCOUNT
if (isset($_POST) && ($_POST['action'] == 'delete_customer_account')) {
$_SESSION['customers_delete_account_request'] == '1';
//Collect Customer Info
$sql = "SELECT customers_firstname, customers_lastname, customers_email_address, customers_email_format FROM ".TABLE_CUSTOMERS." WHERE customers_id = :customers_id:";
$sql = $db->bindVars($sql , ':customers_id:', $customer_id, 'integer');
$res = $db->Execute($sql);
$customer_name = $res->fields['customers_firstname']. ' '. $res->fields['customers_lastname'];
$email_address = $res->fields['customers_email_address'];
//SEND MAIL TO CUSTOMER
$to_name = $customer_name;
$to_address = $email_address;
$email_subject = "Pedido para Apagar a Conta na Livraria PromoBooks";
$email_text = "Olá ".$customer_name." Recebemos um pedido para apagar a sua conta na Livraria PromoBooks"."\n";
$email_text .= "Gostariamos que continuasse connosco, mas vamos proceder à eliminação da conta no prazo máximo de 20 dias"."\n\n";
$email_text .= "Todos os dados serão eliminados da Loja Online."."\n";
$email_text .= "Caso tenha efectuado encomendas, os dados relativos a facturação continuarão na LUNADIL UNIPESSOAL LDA, ao abrigo da lei portuguesa."."\n";
$email_text .= "Se pensa que este email é um engano, ou tem outras questões, por favor entre em contacto connosco"."\n";
$email_text .= "------------------------------------------------------"."\n\n";
$from_email_name = STORE_NAME;
$from_email_address = EMAIL_FROM;
zen_mail($to_name, $to_address, $email_subject, $email_text, $from_email_name, $from_email_address );
$email_text_to_admin = "Pedido para apagar conta de ".$customer_name." com o ID:".$customer_id." ";
zen_mail(STORE_NAME, EMAIL_FROM, $email_subject , $email_text_to_admin , STORE_NAME, EMAIL_FROM, $html_msg, 'welcome_extra');
// Insere pedido na base de dados
$sql_del_account = "UPDATE ".TABLE_CUSTOMERS_GDPR." SET customers_delete_account_request = :customers_delete_account_request: WHERE customers_id = :customers_id:";
$sql_del_account = $db->bindVars($sql_del_account , ':customers_delete_account_request:', '1', 'integer');
$sql_del_account = $db->bindVars($sql_del_account , ':customers_id:', $customer_id, 'integer');
$res_del_account = $db->Execute($sql_del_account);
}
//Informa cliente das sua subscrição em newsletter
$sql = " SELECT customers_newsletter FROM ".TABLE_CUSTOMERS." WHERE customers_id = :customers_id: ";
$sql = $db->bindVars($sql, ':customers_id:', $customer, 'integer');
$res = $db->Execute($sql);
//pr($res);
$customer_newsletter_status = $res->fields['customers_newsletter'];
}
function update(&$callingClass, $notifier, $paramsArray)
{
if ( $notifier == 'NOTIFY_LOGIN_SUCCESS' ) {
$this->updateNotifyLoginSuccess($callingClass, $notifier, $paramsArray);
}
if ( $notifier == 'NOTIFY_MODULE_CREATE_ACCOUNT_ADDED_CUSTOMER_RECORD' ) {
$this->updateCreateAccountAddedCustomerRecord($callingClass, $notifier, $paramsArray);
}
if ( $notifier == 'NOTIFY_HEADER_END_ACCOUNT' ) {
$this->updateHeaderEndAccount($callingClass, $notifier, $paramsArray);
}
}
}
And then at template user account_defaultPHP Code:
<?php
if (!defined('IS_ADMIN_FLAG')) {
die('Illegal Access');
}
$check_until_date = '20181231'; // ON
$rgpd_date = '20180528';
// GDPR - If cookieconsent_status is set, allow tag manager to load.
// Leaving two choices here for something
$cookie_config = false; // Start only with zenid cookie
$cookie_ga_default = true; // Analytics default: doesn't track remarketing and sets anonymous IP
$cookie_external = false; // GA tracks for marketing, FB pixel, social shares, etc
//adds analytics cookie with Anonymous IP
if (!$_COOKIE["cookieconsent_status"] ) {
if( !$_COOKIE["cc_analytics"] == 'deny') {
zen_setcookie('cc_analytics', 'allow', time()+60*60*24*30, '/', (zen_not_null($current_domain) ? $current_domain : ''));
}
if ( (str_replace('-','',$_SESSION['today_is']) <= $rgpd_date) && !$_COOKIE["cc_allowSocial"] == 'deny' ) {
$cookie_external = true;
zen_setcookie('cc_allowSocial', 'allow', time()+60*60*24*30, '/', (zen_not_null($current_domain) ? $current_domain : ''));
}
}
if (isset($_COOKIE['cc_analytics']) && $_COOKIE['cc_analytics'] == 'deny') {
$cookie_ga_default = false;
}
if (isset($_COOKIE['cc_allowSocial']) && $_COOKIE['cc_allowSocial'] == 'allow') {
$cookie_external = true;
}
if (isset($_COOKIE['cookieconsent_status'])) { // It's set, check
$cookie_config = true; // flag that the user made some configuration
// allow all cookies
if ($_COOKIE['cookieconsent_status'] == 'allow') {
$cookie_ga_default = true;
$cookie_external = true;
}
}
if ( !isset($_SESSION['customers_warning_count'])) {
$_SESSION['customers_warning_count'] = 0;
}
if($_SESSION['customer_id']) {
if ( !$_SESSION['customers_delete_account_request']) {
$sql = " SELECT customers_delete_account_request FROM ".TABLE_CUSTOMERS_GDPR." WHERE customers_id = :customers_id: ";
$sql = $db->bindVars($sql , ':customers_id:', $_SESSION['customer_id'], 'integer');
$res = $db->Execute($sql);
if ($res->fields['customers_delete_account_request'] == '1') {
$_SESSION['customers_delete_account_request'] = $res->fields['customers_delete_account_request'];
unset($sql, $res);
}
}
if(str_replace('-','',$_SESSION['today_is']) <= $check_until_date ) {
define('RGPD_MSG', 'Para estar em conformidade com o Regulamento Geral da Protecção de Dados Europeia, a Livraria PromoBooks, está a informar todos os seus cliente registados antes da nova lei, a fim de tomarem conhecimento sobre os dados processados. Por favor leia a nossa política de privacidade e aceda à <a href="'.zen_href_link(FILENAME_ACCOUNT, '', 'SSL').'"> Sua Área de Cliente</a> para efectuar as alterações necessárias. Ao continuar no site, pressupõe que tem conhecimento e que assim deseja continuar. ');
if ( $_SESSION['customer_rgpd'] == '') {
$sql = " SELECT customers_accept_terms, customers_was_notify_date, customers_delete_account_request FROM ".TABLE_CUSTOMERS_GDPR." WHERE customers_id = :customers_id: ";
$sql = $db->bindVars($sql , ':customers_id:', $_SESSION['customer_id'], 'integer');
$res = $db->Execute($sql);
if ($res->RecordCount() > 0) {
if ($res->fields['customers_accept_terms'] !=='0') {
$_SESSION['customer_rgpd'] = true;
}else {
$_SESSION['customer_rgpd'] = '';
if($_SESSION['customers_warning_count'] <= 2 && $_SESSION['customers_warning_count'] !=='stop') {
$messageStack->add_session('site_notifications', RGPD_MSG, 'caution');
$_SESSION['customers_warning_count'] ++;
}
}
if ($res->fields['customers_was_notify_date'] !=='') {
$_SESSION['customer_rgpd_notified'] = $res->fields['customers_was_notify_date'];
} else {
$_SESSION['customer_rgpd_notified'] = '';
}
} else {
$_SESSION['customer_rgpd'] = '';
$_SESSION['customer_rgpd_notified'] = '';
if(($_SESSION['customers_warning_count'] <= 2) && ($_SESSION['customers_warning_count'] !=='stop')) {
$messageStack->add_session('site_notifications', RGPD_MSG, 'caution');
}
}
}
}
}
if($_SESSION['customers_warning_count'] == 2) {
unset($_SESSION['customers_warning_count']);
$_SESSION['customers_warning_count'] ='stop';
}
if ( $_SESSION['customers_delete_account_request'] == '1') {
$messageStack->add_session('site_notifications', 'Recebemos a notificação para apagar a sua conta dentro do prazo estipulado po lei será eliminada', 'caution');
}
And added a delete account formPHP Code:
<?php
if (DISPLAY_PRIVACY_CONDITIONS == 'true' && $_SESSION['customer_rgpd'] == '') {
echo zen_draw_form('customer_privacy_policy', zen_href_link(FILENAME_ACCOUNT, '', 'SSL'), 'post', '') . zen_draw_hidden_field('action', 'process') . zen_draw_hidden_field('email_pref_html', 'email_format');
?>
<fieldset>
<legend><?php echo TABLE_HEADING_PRIVACY_CONDITIONS; ?></legend>
<div class="information gdpr-info"><?php echo TEXT_PRIVACY_CONDITIONS_DESCRIPTION_AT_REGISTRATION;?></div>
<?php echo zen_draw_checkbox_field('privacy_conditions', '1', false, 'id="privacy" required');?>
<label class="checkboxLabel gdpr-info-label" for="privacy"><?php echo TEXT_PRIVACY_CONDITIONS_CONFIRM;?></label>
<div class="buttonRow forward"><?php echo zen_image_submit(BUTTON_IMAGE_SUBMIT, BUTTON_SUBMIT_ALT); ?></div>
</fieldset>
<?php
}
?>
</form>
Hope it helps, but arrange this to your code.
Made this for myself so didnt't take into account some other zencart stuff "modules stuff"
Yes, that's a sql statement.... but listen, this is just a example of what I've done taking into account what the store is using, etc...
You must examine what you're requiring as personal data, etc, and implement according to that.
The other post by Congerman says he's not using this record. Maybe he's right, but I prefer to have that record , even for re-consent purposes.
So you'll have to analyze what you are collecting, to be able to delete or transfer, etc..
But this is not a module.
But I think even this is not enough.
Let's take a example of a inspection to a restaurant.
They inspect everything, they say it's wonderful, everything it's fine. They even lunch at the restaurant but they leave and leave no records of what they done....
It's useless.
Same way, I believe some kind of record must exist saying what was implemented and for what.
If not.... it makes no sense.
For the moment I just want to be able to see in the DB when a user enters personal data via create account or COWOA that he checked the box and he accepted the Privacy Statement and also the date that he accepted it (for proof reasons). There isn't a record to store this information at the moement.
Can u tel me what do I need to do to achieve this?
There is also the other thing about their "right to be forgotten".
Some people think that to comply they must just delete the customers account and purchase history etc. But not so, In the UK we are required to keep certain records under statute for 7, 10 and in some cases 20 years. This includes transactions and proving of them for tax purposes etc.
So I had to put in my privacy policy "If you wish to exercise your “Right to be forgotten” under GDPR please contact us and we will remove all data about you with the exception of data that we are required to keep under statute."
Attaching a zip of two items from my site. Page to request removal and privacy check added to the database with date for annual checkup. Not a plugin, just some quick instructions and the base code setup in folder format. Privacy, If its more then a year, they will get nag to review and check the privacy box on each login. How you use is up to you.Quote:
For the moment I just want to be able to see in the DB when a user enters personal data via create account or COWOA that he checked the box and he accepted the Privacy Statement and also the date that he accepted it (for proof reasons). There isn't a record to store this information at the moement.
Thank You very much
I installed the mod but i have a question, if you could shed some light...
Case: When a new customer creates an account, if the Regulations> Confirm Privacy Notice During Account Creation Procedure is set to True he has to check the confirmation box to go further (otherwise he can't continue), but this action doesn't record the acceptance anywhere and he can place the order with nothing recorded in the privacy_conditions fields in the DB.
Only after he logs in the next time he is forced to accept the "real privacy - the one in the module" and the action is indeed recorded.
Is there a possibility to validate Privacy and also create the DB record at create account level? Because at the moment he is obligated to accept the privacy twice - once at create account level, and once at privacy page level...
Thanks again,
Adrian
Have you tried this mod in an earlier post by jsweb? I think it does all that you need.
I tried it, but my site crashes, merged the files twice, I' don't know what I did wrong, davewest's mod works but i only have the problems mentioned earlier. waiting for his answer...
A
If you find davewest's mod can't do what you want, post any error messages you had - I've installed that mod I referred to and it's working fine (only one issue I had to resolve).
In is not actually an error, at create account page you thick the Zen Cart's default Privacy box, nothing is recorded and you can go further to the next step and place the order, but no Privacy acceptance is recorded!!! in the database fields.
Only after you log out and login again the mod prompts Privacy Page with message that you need to agree with the Policy to continue shopping. But since you already have agreed at create account page level then you have to agree twice ...
I would like the NEW user to be able to agree the mod's Privacy checkbox not Zen Cart's default checkbox at create account page level and that should be enough, without having to agree again when he logs in.
For existing accounts it's working fine - when they visit the site next time, they will be prompted that they have to agree to continue which is what we need.
I'm using V 1.5.1 - forgot to mention
10x
Sorry, I don't use the create account page and had to go back and get/match code.
The includes/modules/create_account.php if you modified this file then it would be in your template folder. If you are using COWOA or COWAA it would be the same for the register, and no_account modules too.
Standard input check, then storing the info into the database. The date is auto created for the time of creation.
look for this set of lines:
add this line above ACCOUNT_COMPANYCode:if (isset($_POST['email_format'])) {
$email_format = zen_db_prepare_input($_POST['email_format']);
}
if (ACCOUNT_COMPANY == 'true') $company = zen_db_prepare_input($_POST['company']);
$firstname = zen_db_prepare_input(zen_sanitize_string($_POST['firstname']));
$lastname = zen_db_prepare_input(zen_sanitize_string($_POST['lastname']));
$nick = zen_db_prepare_input($_POST['nick']);
if (ACCOUNT_DOB == 'true') $dob = zen_db_prepare_input($_POST['dob']);
Then on the database sql or look for this set of lines:Code:
if (DISPLAY_PRIVACY_CONDITIONS == 'true') $privacy_conditions = zen_db_prepare_input($_POST['privacy_conditions']); //added for gdpr
add to the bottom:Code:$sql_data_array = array(array('fieldName'=>'customers_firstname', 'value'=>$firstname, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_lastname', 'value'=>$lastname, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_email_address', 'value'=>$email_address, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_nick', 'value'=>$nick, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_telephone', 'value'=>$telephone, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_fax', 'value'=>$fax, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_newsletter', 'value'=>$newsletter, 'type'=>'integer'),
array('fieldName'=>'customers_email_format', 'value'=>$email_format, 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_default_address_id', 'value'=>0, 'type'=>'integer'),
array('fieldName'=>'customers_password', 'value'=>zen_encrypt_password($password), 'type'=>'stringIgnoreNull'),
array('fieldName'=>'customers_authorization', 'value'=>$customers_authorization, 'type'=>'integer'),
);
corrected the upload... The added create_account.php is from 155fCode:
array('fieldName'=>'customers_privacy_conditions', 'value'=>$privacy_conditions, 'type'=>'integer'),
array('fieldName'=>'customers_privacy_date', 'value'=>now(), 'type'=>'date'),
I think it's the sql area i'm merging wrong, it is not working, the create acount page crashes after i click create account, i think it's because the lines are different, in 1.55 & i-m using 1.5.1.
I tried to adapt it in the sql array area, but i don't think i did it right, please tell me how the 1.5.1 version below should look like after adding the 2 lines you mentioned?
1.5.1 code without the 2 lines:
$sql_data_array = array('customers_firstname' => $firstname,
'customers_lastname' => $lastname,
'customers_email_address' => $email_address,
'customers_nick' => $nick,
'customers_telephone' => $telephone,
'customers_fax' => $fax,
'customers_newsletter' => (int)$newsletter,
'customers_email_format' => $email_format,
'customers_default_address_id' => 0,
'customers_password' => zen_encrypt_password($password),
'customers_authorization' => (int)CUSTOMERS_APPROVAL_AUTHORIZATION
I don't have any testing setup to go back that far, but this should be it, pay attention to the commas.
Code:'customers_authorization' => (int)CUSTOMERS_APPROVAL_AUTHORIZATION,
'customers_privacy_conditions' => (int)$privacy_conditions,
'customers_privacy_date' => now()
);
10x again,
but it doesn't seem to do the job, i'm pulling my hair off, the create_account.php modifications break the site when i go ahead and i hit create account button, it returns 500 error, if I remove these lines everything goes back to normal. Can't figure out why these 3 lines break it i put them exactly where they are supposed to go, checked for commas...
Maybe it doesen't communicate with the db, or looking for non existing tables...
The 2 tables that i'm thinking should record the action are those created by the sql patch customers_privacy_conditions and customers_privacy_date.
Should there be more than these? duno
It's more then likely the date now()
Then it needs to be like this:
'customers_privacy_date' => 'now()'
There seems to be two threads running about this matter. Anyway, I have had one of my friends send me a link to a wordpress plugin that checks to see if you are compliant., may be useful. www.edmundloh.net/gdpr-fix
Also, one of my other friends, yes I have two friends, who has a lot to do with data protection etc, he is going to put together a human version of what you need to do and how. This may be the other side of this weekend before he can get something to me, as he needs to make sure, the stuff he looks after is up to spec for the 25th May. He did say the big thing to note is that you can look at everything somebody has on you for free instead of the £10 charge.
Nothing to do with this did everybody know you can no longer charge for a customer using a credit card? I bet you did
Question: If the customer has to check the "Accept Conditions" checkbox when they create an account, why is not
table customer_info->field:customers_info_date_account_created
proof of acceptance?
Hello there,
I just wondered if you are able to use the popup privacy link on the create account page? I have CSS Loader, I think it is blocking it for me. I tried pasting the following snippet to tpl_modules_create_account.php directly but no joy. Though I think it has to be done from a different code somewhere:-
Quote:
<script type="text/javascript">
<!--
function gdpr_decline(){
window.location = "<?php echo zen_href_link(FILENAME_DEFAULT); ?>"
}
//-->
</script>
Regarding deleting orders and customers details,
I didn't like putting holes in the tables where things have just vanished and cannot be referenced to an invoice (produced by other software) and so decided to change these operations to delete the personal/identification data (name, address but not country and postcode, telephone) and leave the unidentifiable order details intact.
I too noticed that, I think it controls the return to the home page after declining to accept the privacy review in Account.
Hello,
I really thank you for this package because it's really saved me.
I found a small bug for which a non SuperUser account won't be able to enter the "GDPR Tools" from "Tools" menu.
The file includes/extra_datafiles/gdpr_filenames.php contains:
define('FILENAME_TOOLS_GDPR', 'gdpr.php');
but it really should be
define('FILENAME_TOOLS_GDPR', 'gdpr');
otherwise non-superuser accounts will be redirected to the denied.php page.
Plus it doesn't seem to send any e-mail upon denial of the new Privacy Policy. E-mails do work from Zen Cart in my configuration. I'm investigating this a little more by myself for this. Meanwhile, if you have any ideas, go on posting :)
Hi we have installed the GDPR tools, but the pop up you should open with the code: <script type = "text / javascript">
<! -
function gdpr_decline () {
window.location = "<? php echo zen_href_link (FILENAME_DEFAULT);?>"
}
// ->
</ Script>
It does not work there is some reference to the function that does not go.
has anyone made changes or already installed? Thank you
Thanks for identifying the define issue - we'll get a corrected version uploaded as oon as we can. As you'll appreciate, it's a bit manic as most people have totally ignored GDPR for the past 2 years!
The email is only sent when a user requests that their account is deleted, not just because they decline the policy.
Readers may find this useful/interesting/comforting as appropriate lol ... take a few moments to visit http://www.bbc.co.uk/news/business-44208456 , watch the video and read the briefing, which can be summarised as:
"Small businesses should not panic but there will be no grace period - the rules will be fully enforced from 25 May (today).
Firms that aren't compliant need to get their action plan sorted quickly"
@giancdr - the popup isn't part of this free version and that snippet wasn't supposed to be included.
During our own testing on our own servers with vanilla 155f, php 7, all went smoothly, but during the last few days over many installations, we have of course come across a few issues because of individual configurations - as well as a couple of our own.
The current version has the email fix, redirect fix, errant code removed and admin extra_datafile fixed
Can be downloaded from http://jsweb.uk/gdpr_service/gdpr4zc.zip
Great, I've just installed it and it works like a charm.
Thanks again.
Just 2 things that I'd like to point out:
1) this ZIP is full of hateful apple .DS_Store files ;)
2) I think that a target="_blank" into the "Privacy Notice" at the end of the "Create account" section is better than just opening the page
Best Regards and thanks again
I have been sent this link from Tech Pro Research. Might help
So - COWOA. Contrary to the name (checkout without account) it does create a customer account in the database - can create multiple accounts if you buy that way. There's no way for the customer to log in to request deletion. This looks to me to be a big nightmare. I'm guessing that best would be to address what a COWOA account is and state they need to contact the site owner to have it deleted - it or all of them. That sounds like a really big hassle on a large site though. I've always liked COWOA because it speeds up checkout and remains a simple way to do that without a lot of extra code like the FEC. I can see websites turning it off to avoid the hassle now. Anybody thinking along this line with coding? I'm thinking a delete that is based on email address and deletes all occurrences. Would necessitate a new delete button in admin?
Thanks to JSWeb for the mod. Note that us idiot Americans do need to look at your verbiage for Americanization and some specific things are written in (such as specified time to keep orders) that will differ from company to company. Your sample privacy page really did help though to make it clearer what transparency means in this case. My rewriting for my clients resulted in this http://deliatest.com/index.php?main_page=privacy. Feel free to use it as you wish. Disclaimer: course I'm no lawyer either but I took some liberties that may lessen the transparency as intended by GDPR, partially in an effort to match all my clients needs and partially because I'm thinking American companies will have trouble with the order retention part of this. We don't have a 7 year requirement to fall back on.
I looked at chargeback time limits - max seems to be maybe 180 days and as far as I know there is no requirements to keep the info anyway. I am resisting the idea of deleting those transactions at all as a website may not have any other way to track the sales or information. Since Zen Cart does not lend itself to integrating with other accounting platforms (or vice versa) most of my clients use the website only for keeping track of sales and statistics. Canada does have specific requirements and I'm hearing those in the know aren't worrying about this. I do have one UK client so got to get this right!
@fix_metal
1. Well aware of it but was in a hurry ...and annoying as they are, they don't harm anyone.
2. Two schools of thought here.
a. Opening another window frequently leads to people to getting lost...and if they click the back button on the new window, either the one in the page or the browser, they have nowhere to go back to. On the plus side, it does at least mean the details you've already typed in on your original window will still be there, whereas...
b. Opening the privacy page at the end of the create account process is actually not as good an idea as we thought and we've moved the Privacy fieldset back to its original place at the beginning of the Create Account process because Zencart does not retain the details you just typed in - so anyone actually reading the privacy page is going to be mightily upset when they return which is a good reason to go with the new window approach.
However, by putting it back to the beginning where the original ZCDevTeam had it means that if people don't want to accept your privacy statement, you shouldn't annoy them any further by making them fill in all their details and then go to check the Privacy.
But we uploaded this fileset expecting people with a bit of knowledge to be implementing it, so feel free to modify! We won't be offended.
And I was in so much of a rush earlier that I forgot to add the readme ...so an updated version is in place (with DS store files removed ;-)
http://jsweb.uk/gdpr_service/gdpr4zc.zip
ok Thanks You, but in the new tool package there is the file footer.php in the tamplate, but what is the purpose, what is the change made? because my file is very complex and I can not replace it with the default one. Thanks It would be advisable to insert in the readme the changes made to the individual files that have overdrive.
@glancalr
As explained previously, we haven't time at the moment to be dealing with the details as one normally would if we were offering a supported plugin via the downloads section, so this is why there are no detailed instructions or listings of changed files, edits etc. The only advice we are able to give is to "compare and merge"
I'm sorry about that but we have to give our clients priority, and right now our developers are very busy. My understanding is that the tpl_footer.php is necessary for the redirects from the privacy review page to work, but compare our tpl_footer,php against a vanilla one form your Zc version.