Campaign_Commander_Transactional_Email_1_5 - Version 3.1.0

Version Notes

General Enhancement :
* A list of the status of prerequisites and extensions is now available in the SmartFocus menu of the System Configuration section.
* Cron jobs can now be configured to run on specific days of the week or on a specific day of the month.
* The cron job processes scheduled in the Magento Connector can now be restarted even if a previous cron job process encountered an error and did not close.

Data Synchronization :
* Data synchronization can now be configured to synchronize based on member email addresses.
* The data synchronization process now runs faster than in previous versions of the Magento Connector.
* You can now configure data synchronization for different stores with different SmartFocus accounts.
* In the Mapping feature:
** fields have been arranged into different categories,
** the following new fields for Calculated Purchase Information category have been added:
Used Email Addresses
Base Currency Code
List of Order #
Total Orders Purchased
Total Items Purchased
Average Items Purchased per Order
Total Order Amount Spent
Average Order Amount Spent per Purchase
Total Discount Amount
Average Discount Amount per Purchase
Total Shipping Amount
Average Shipping Amount per Purchase
Minimum Purchase Total
Maximum Purchase Total
First Purchase
Last Purchase
Minimum Items Purchased
Maximum Items Purchased
Shipping Methods
Payment Methods
Used Coupons
Total Purchases With Discount
* The menu Data Process List has been added to the Magento Connector, allowing you to monitor the progress of your scheduled synchronizations at a glance.

Transactional Emails
* You can now verify that your SmartFocus account is compatible with the Magento Connector in the Transactional Messages (NMP) menu and configure your account if you have modified the credentials for your account.
* A log clean-up process has been created.


Abandoned Carts Feature
* You can now process more than 8,000 abandoned carts simultaneously.
* You can now enable the test mode to send abandoned cart reminders in minutes rather than hours, and configure how long the cart will be able to receive reminders in hours.
* In the new menu 'List in the Abandoned Cart menu, you can access the list of abandoned cart reminder information.

Download this release

Release Info

Developer SmartFocus
Extension Campaign_Commander_Transactional_Email_1_5
Version 3.1.0
Comparing to
See all releases


Code changes from version 3.0.1 to 3.1.0

Files changed (138) hide show
  1. app/code/community/Emv/CHANGELOG +60 -0
  2. app/code/community/Emv/CartAlert/Block/Adminhtml/List.php +66 -0
  3. app/code/community/Emv/CartAlert/Block/Adminhtml/List/Grid.php +336 -0
  4. app/code/community/Emv/CartAlert/Block/Adminhtml/List/Grid/Column/Renderer/Currency.php +33 -0
  5. app/code/community/Emv/CartAlert/Block/Adminhtml/Quote.php +43 -0
  6. app/code/community/Emv/CartAlert/Block/Adminhtml/Quote/Grid.php +123 -0
  7. app/code/community/Emv/CartAlert/Block/Adminhtml/System/Config/PromoRule.php +100 -0
  8. app/code/community/Emv/CartAlert/Block/Cart/Items.php +1 -1
  9. app/code/community/Emv/CartAlert/Constants.php +5 -0
  10. app/code/community/Emv/CartAlert/Helper/Data.php +151 -9
  11. app/code/community/Emv/CartAlert/Model/Observer.php +267 -59
  12. app/code/community/Emv/CartAlert/controllers/Adminhtml/AbandonmentController.php +195 -0
  13. app/code/community/Emv/CartAlert/etc/adminhtml.xml +32 -0
  14. app/code/community/Emv/CartAlert/etc/config.xml +29 -15
  15. app/code/community/Emv/CartAlert/etc/system.xml +55 -19
  16. app/code/community/Emv/CartAlert/sql/abandonment_setup/mysql4-upgrade-0.5.2-0.5.3.php +15 -0
  17. app/code/community/Emv/CartAlert/sql/abandonment_setup/mysql4-upgrade-0.5.3-0.5.4.php +25 -0
  18. app/code/community/Emv/Core/Block/Adminhtml/Account/Edit/AssociatedUrls.php +1 -1
  19. app/code/community/Emv/Core/Block/Adminhtml/Config/ExtensionStatus.php +434 -0
  20. app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process.php +25 -0
  21. app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid.php +164 -0
  22. app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid/Column/Renderer/Links.php +33 -0
  23. app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid/Column/Renderer/Output.php +59 -0
  24. app/code/community/Emv/Core/Helper/Data.php +181 -18
  25. app/code/community/Emv/Core/Model/Account.php +16 -0
  26. app/code/community/Emv/Core/Model/Adminhtml/System/Config/Backend/Account/Abstract.php +1 -14
  27. app/code/community/Emv/Core/Model/Adminhtml/System/Config/Backend/Cron.php +87 -0
  28. app/code/community/Emv/Core/Model/{System → Adminhtml/System}/Config/Source/Account.php +1 -1
  29. app/code/community/Emv/Core/Model/Adminhtml/System/Config/Source/CronDate.php +36 -0
  30. app/code/community/Emv/Core/Model/Adminhtml/System/Config/Source/CronDay.php +58 -0
  31. app/code/community/Emv/Core/Model/DataProcessing/Exception.php +12 -0
  32. app/code/community/Emv/Core/Model/DataProcessing/Process.php +335 -0
  33. app/code/community/Emv/Core/Model/DataProcessing/Process/Log.php +102 -0
  34. app/code/community/Emv/Core/Model/DataProcessing/Profile.php +195 -0
  35. app/code/community/Emv/Core/Model/DataProcessing/Profile/Interface.php +46 -0
  36. app/code/community/Emv/Core/Model/Mysql4/DataProcessing/Process.php +29 -0
  37. app/code/community/Emv/Core/Model/Mysql4/DataProcessing/Process/Collection.php +16 -0
  38. app/code/community/Emv/Core/Model/Service/Abstract.php +1 -0
  39. app/code/community/Emv/Core/Model/Service/Notification.php +1 -1
  40. app/code/community/Emv/Core/Model/Service/Transactional.php +2 -2
  41. app/code/community/Emv/Core/controllers/Adminhtml/AccountController.php +1 -1
  42. app/code/community/Emv/Core/controllers/Adminhtml/DataProcessingController.php +175 -0
  43. app/code/community/Emv/Core/etc/adminhtml.xml +12 -3
  44. app/code/community/Emv/Core/etc/config.xml +11 -1
  45. app/code/community/Emv/Core/functions.php +118 -0
  46. app/code/community/Emv/Core/sql/emvcore_setup/mysql4-upgrade-0.2.0-0.3.0.php +26 -0
  47. app/code/community/Emv/DataSync/Block/Adminhtml/Form/Field/CustomerAttributes.php +8 -42
  48. app/code/community/Emv/DataSync/Block/Adminhtml/Newsletter/Subscriber.php +24 -0
  49. app/code/community/Emv/DataSync/Block/Adminhtml/Newsletter/Subscriber/Grid.php +255 -0
  50. app/code/community/Emv/DataSync/Block/Adminhtml/System/Config/CustomerAttributes.php +1 -1
  51. app/code/community/Emv/DataSync/Block/Adminhtml/System/Config/GetFields.php +19 -2
  52. app/code/community/Emv/DataSync/Helper/Data.php +206 -26
  53. app/code/community/Emv/DataSync/Helper/Service.php +58 -211
  54. app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/BatchMember/Cron.php +2 -48
  55. app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/Clean/Cron.php +3 -2
  56. app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/PurchaseProcess/Cron.php +59 -0
  57. app/code/community/Emv/DataSync/Model/AttributeProcessing/Config.php +321 -0
  58. app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Abstract.php +106 -0
  59. app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Customer.php +321 -0
  60. app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Newsletter.php +99 -0
  61. app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/PurchaseInformation.php +154 -0
  62. app/code/community/Emv/DataSync/Model/Cron.php +132 -37
  63. app/code/community/Emv/DataSync/Model/DataProcess/PurchaseInformation.php +32 -0
  64. app/code/community/Emv/DataSync/Model/Mysql4/DataProcess/PurchaseInformation.php +42 -0
  65. app/code/community/Emv/DataSync/Model/Mysql4/DataProcess/PurchaseInformation/Collection.php +19 -0
  66. app/code/community/Emv/DataSync/Model/Observer.php +94 -27
  67. app/code/community/Emv/DataSync/Model/Service/BatchMember.php +707 -219
  68. app/code/community/Emv/DataSync/Model/Service/DataProcess.php +360 -0
  69. app/code/community/Emv/DataSync/Model/Service/Member.php +133 -107
  70. app/code/community/Emv/DataSync/controllers/Adminhtml/DataSyncController.php +270 -12
  71. app/code/community/Emv/DataSync/etc/adminhtml.xml +33 -0
  72. app/code/community/Emv/DataSync/etc/config.xml +45 -5
  73. app/code/community/Emv/DataSync/etc/system.xml +110 -11
  74. app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-install-0.0.1.php +3 -3
  75. app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-upgrade-0.1.0-0.2.0.php +20 -0
  76. app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-upgrade-0.2.0-0.2.1.php +60 -0
  77. app/code/community/Emv/Emt/Block/Adminhtml/Config/ExtensionStatus.php +56 -0
  78. app/code/community/Emv/Emt/Block/Adminhtml/Log/Grid.php +12 -1
  79. app/code/community/Emv/Emt/Block/Adminhtml/Resending/Grid.php +2 -1
  80. app/code/community/Emv/Emt/Block/Adminhtml/System/Config/ValidateAccount.php +39 -0
  81. app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit.php +4 -3
  82. app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit/Tab/EmvDyn.php +1 -1
  83. app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit/Tab/General.php +1 -1
  84. app/code/community/Emv/Emt/Helper/Emvtemplate.php +78 -8
  85. app/code/community/Emv/Emt/Model/Adminhtml/System/Config/Backend/Account.php +1 -23
  86. app/code/community/Emv/Emt/Model/Adminhtml/System/Config/Backend/Log/Cron.php +12 -0
  87. app/code/community/Emv/Emt/Model/Cron.php +45 -1
  88. app/code/community/Emv/Emt/Model/Emt.php +1 -1
  89. app/code/community/Emv/Emt/Model/Log.php +11 -1
  90. app/code/community/Emv/Emt/Model/Mailmode.php +3 -3
  91. app/code/community/Emv/Emt/Model/Mysql4/Log.php +53 -0
  92. app/code/community/Emv/Emt/Model/Observer.php +28 -0
  93. app/code/community/Emv/Emt/Model/Resending/Rule.php +1 -1
  94. app/code/community/Emv/Emt/controllers/Adminhtml/TemplateController.php +23 -0
  95. app/code/community/Emv/Emt/etc/config.xml +30 -0
  96. app/code/community/Emv/Emt/etc/system.xml +77 -4
  97. app/code/community/Emv/Report/controllers/Adminhtml/ConversionController.php +1 -1
  98. app/code/community/Emv/Report/etc/adminhtml.xml +16 -6
  99. app/code/community/Emv/Report/etc/config.xml +1 -1
  100. app/design/adminhtml/default/default/layout/{emailvision → smartfocus}/abandonment_report.xml +1 -1
  101. app/design/adminhtml/default/default/layout/smartfocus/core.xml +8 -0
  102. app/design/adminhtml/default/default/template/emailvision/datasync/system/config/getfields.phtml +0 -15
  103. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/abandonment/grid/container.phtml +0 -0
  104. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/account/associated_urls.phtml +0 -0
  105. app/design/adminhtml/default/default/template/smartfocus/cartalert/system/config/promo_rule.phtml +75 -0
  106. app/design/adminhtml/default/default/template/smartfocus/config/extension_status.phtml +61 -0
  107. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/datasync/system/config/form/field/array.phtml +0 -0
  108. app/design/adminhtml/default/default/template/smartfocus/datasync/system/config/getfields.phtml +12 -0
  109. app/design/adminhtml/default/default/template/smartfocus/emt/system/config/account_validation.phtml +96 -0
  110. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/common_js.phtml +0 -0
  111. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/edit.phtml +0 -0
  112. app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/mapped_attributes.phtml +0 -0
  113. app/design/frontend/base/default/layout/{emailvision → smartfocus}/abandonment.xml +1 -1
  114. app/design/frontend/base/default/template/{emailvision → smartfocus}/abandonment/customer.phtml +0 -0
  115. app/design/frontend/base/default/template/{emailvision → smartfocus}/abandonment/reminder/items.phtml +4 -4
  116. app/locale/en_US/Emv_CartAlert.csv +40 -15
  117. app/locale/en_US/Emv_Core.csv +32 -2
  118. app/locale/en_US/Emv_DataSync.csv +15 -1
  119. app/locale/en_US/Emv_Emt.csv +6 -4
  120. app/locale/en_US/template/email/emailvision/datasync/cron_errors.html +0 -5
  121. app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template1.html +0 -0
  122. app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template2.html +0 -0
  123. app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template3.html +0 -0
  124. app/locale/en_US/template/email/smartfocus/datasync/cron_errors.html +5 -0
  125. app/locale/fr_FR/Emv_CartAlert.csv +40 -15
  126. app/locale/fr_FR/Emv_Core.csv +32 -2
  127. app/locale/fr_FR/Emv_DataSync.csv +16 -1
  128. app/locale/fr_FR/Emv_Emt.csv +6 -4
  129. app/locale/fr_FR/Emv_Report.csv +1 -0
  130. lib/EmailVision/Api/BatchMemberService.php +62 -6
  131. lib/EmailVision/Api/NotificationService.php +3 -3
  132. lib/EmailVision/Tools/File/Csv.php +4 -1
  133. package.xml +48 -8
  134. skin/adminhtml/default/default/campaign-commander.css +0 -14
  135. skin/adminhtml/default/default/images/smartfocus/tick.png +0 -0
  136. skin/adminhtml/default/default/images/smartfocus/untick.gif +0 -0
  137. skin/adminhtml/default/default/images/smartfocus/warning.png +0 -0
  138. skin/adminhtml/default/default/smartfocus.css +25 -0
app/code/community/Emv/CHANGELOG ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ v3.1.0 - the 15th May 2014 ********************************************************************
2
+ [General]
3
+ #33 - Feature - Add new UI menu to display the global version of the extension and prerequisite status
4
+ #45 - Enhancement - Enhance cron job scheduling interface
5
+ #46 - Enhancement - Enhance lock mechanism for cron processes
6
+
7
+ [Data Sync]
8
+ #27 - Feature - DataSync should allow email sync.
9
+ #35 - Enhancement - Simplify the verifications
10
+ #38 - Feature - Add multi-store support
11
+ #39 - Enhancement - Enhance Mapping Zone
12
+ #42 - Bug - The performance parameter (Max number of fetched members per page) is not correctly taken in account.
13
+ #44 - Bug - When no mapping is setup, a fatal error has been raised.
14
+ #55 - Feature - Add new menu to show the progress of synchronization.
15
+ #56 - Feature - Add Customer Shipping Address in the mapping list.
16
+ #58 - Feature - Add new menu to show the subscriber queue to export.
17
+ #59 - Feature - Add new column "queued" inside newsletter_subscriber table in order to manage the subscriber queue to export
18
+ #66 - Feature - Add calculated purchase information by customer v1
19
+ For this version, only calculated purchase information is available :
20
+ * Used Email Addresses
21
+ * Base Currency Code
22
+ * List of Order #
23
+ * Total Orders Purchased
24
+ * Total Items Purchased
25
+ * Average Items Purchased per Order
26
+ * Total Order Amount Spent
27
+ * Average Order Amount Spent per Purchase
28
+ * Total Discount Amount
29
+ * Average Discount Amount per Purchase
30
+ * Total Shipping Amount
31
+ * Average Shipping Amount per Purchase
32
+ * Minimum Purchase Total
33
+ * Maximum Purchase Total
34
+ * First Purchase
35
+ * Last Purchase
36
+ * Minimum Items Purchased
37
+ * Maximum Items Purchased
38
+ * Shipping Methods
39
+ * Payment Methods
40
+ * Used Coupons
41
+ * Total Purchases With Discount
42
+
43
+ [NMP]
44
+ #28 - Feature - Add new button to verify the generic template when creating or modify a smartfocus account.
45
+ #37 - Feature - Add new process to clean up the sending log + rescheduling log
46
+ #41 - Bug - When deleting a SmartFocus account, delete also the temporary sending email template
47
+ #43 - Enhancement - The sending logs should be sorted from newer to older
48
+ #62 - Enhancement - Change default sending mode name
49
+ #67 - Enhancement - Increase the default connection time out and the execution time out
50
+
51
+ [Abandoned Carts]
52
+ #30 - Enhancement - Performance issue for treating more than 8000 abandoned carts at the same time
53
+ #52 - Enhancement - Change shopping cart rule from text field to select
54
+ #57 - Feature - Add test mode and life time parameters
55
+ #61 - Enhancement - add date/time into abandonment table
56
+ #63 - Bug - When a registered customer comes back and modifies his cart, the reminder process does not restart.
57
+ #64 - Feature - New menu to display a list of abandoned cart reminder information
58
+ #64 - Enhancement - add correct index into the three tables (abandonment, stats_email_abandonment_sent, emv_order_flag)
59
+
60
+ ***********************************************************************************************
app/code/community/Emv/CartAlert/Block/Adminhtml/List.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abandoned Cart Reminder List Grid Container
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_CartAlert_Block_Adminhtml_List extends Mage_Adminhtml_Block_Widget_Grid_Container
11
+ {
12
+ /**
13
+ * Build abandonment list
14
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::__construct()
15
+ */
16
+ public function __construct()
17
+ {
18
+ parent::__construct();
19
+
20
+ $this->_blockGroup = 'abandonment';
21
+ $this->_controller = 'adminhtml_list';
22
+ $this->_headerText = Mage::helper('abandonment')->__('Abandoned Cart Reminders');
23
+ $this->_removeButton('add');
24
+ }
25
+
26
+ /**
27
+ * Add Store switcher to layout
28
+ *
29
+ * (non-PHPdoc)
30
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::_prepareLayout()
31
+ */
32
+ protected function _prepareLayout()
33
+ {
34
+ $this->setChild('store_switcher',
35
+ $this->getLayout()->createBlock('adminhtml/store_switcher')
36
+ ->setUseConfirm(false)
37
+ ->setSwitchUrl($this->getUrl('*/*/*', array('store'=>null)))
38
+ ->setTemplate('report/store/switcher.phtml')
39
+ );
40
+
41
+ return parent::_prepareLayout();
42
+ }
43
+
44
+ /**
45
+ * Get store switcher for multiple stores
46
+ *
47
+ * @return string
48
+ */
49
+ public function getStoreSwitcherHtml()
50
+ {
51
+ if (Mage::app()->isSingleStoreMode()) {
52
+ return '';
53
+ }
54
+ return $this->getChildHtml('store_switcher');
55
+ }
56
+
57
+ /**
58
+ * Get grid html with eventually store switcher block
59
+ * (non-PHPdoc)
60
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::getGridHtml()
61
+ */
62
+ public function getGridHtml()
63
+ {
64
+ return $this->getStoreSwitcherHtml() . parent::getGridHtml();
65
+ }
66
+ }
app/code/community/Emv/CartAlert/Block/Adminhtml/List/Grid.php ADDED
@@ -0,0 +1,336 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abandoned Cart Reminder List Grid Block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_CartAlert_Block_Adminhtml_List_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
+ {
12
+ /**
13
+ * Stores current currency code
14
+ */
15
+ protected $_currentCurrencyCode = null;
16
+
17
+ /**
18
+ * Ids of current stores
19
+ */
20
+ protected $_storeIds = array();
21
+
22
+ /**
23
+ * Constructor
24
+ *
25
+ * Set main configuration of grid
26
+ */
27
+ public function __construct()
28
+ {
29
+ parent::__construct();
30
+ $this->setId('abandonedcartGrid');
31
+ $this->setUseAjax(true);
32
+ $this->setDefaultSort('main_table.updated_at ', 'desc');
33
+ }
34
+
35
+ /**
36
+ * storeIds setter
37
+ *
38
+ * @param array $storeIds
39
+ * @return Mage_Adminhtml_Block_Report_Grid_Shopcart_Abstract
40
+ */
41
+ public function setStoreIds($storeIds)
42
+ {
43
+ $this->_storeIds = $storeIds;
44
+ return $this;
45
+ }
46
+
47
+ /**
48
+ * Retrieve currency code based on selected store
49
+ *
50
+ * @return string
51
+ */
52
+ public function getCurrentCurrencyCode()
53
+ {
54
+ if (is_null($this->_currentCurrencyCode)) {
55
+ reset($this->_storeIds);
56
+ $this->_currentCurrencyCode = (count($this->_storeIds) > 0)
57
+ ? Mage::app()->getStore(current($this->_storeIds))->getBaseCurrencyCode()
58
+ : Mage::app()->getStore()->getBaseCurrencyCode();
59
+ }
60
+ return $this->_currentCurrencyCode;
61
+ }
62
+
63
+ /**
64
+ * Prepare quote collection for grid
65
+ *
66
+ * @return Mage_Adminhtml_Block_Widget_Grid
67
+ */
68
+ protected function _prepareCollection()
69
+ {
70
+ $collection = Mage::getResourceSingleton('sales/quote_collection');
71
+ // prepare quote collection
72
+ $collection
73
+ ->addFieldToFilter('items_count', array('gt' => 0)) // have at least 1 item
74
+ ->addFieldToFilter('customer_email', array('notnull' => 1)) // a quote with a valid email address
75
+ ->addFieldToFilter('is_active', 1) // only get active quotes
76
+ ->setOrder('main_table.updated_at', Varien_Data_Collection::SORT_ORDER_DESC) // sort the carts from older to newer
77
+ ;
78
+
79
+ // link to abandonment table to get sent reminder information
80
+ $resource = Mage::getModel('core/resource');
81
+ $collection->getSelect()->joinLeft(
82
+ array('abandonment' => $resource->getTableName('abandonment/abandonment')),
83
+ 'main_table.entity_id = abandonment.entity_id',
84
+ array(
85
+ 'abandonment.customer_abandonment_subscribed' => 'customer_abandonment_subscribed',
86
+ 'abandonment.coupon_code' => 'abandonment.coupon_code',
87
+ 'abandonment.updated_at' => 'abandonment.updated_at',
88
+ 'abandonment.template' => 'abandonment.template'
89
+ )
90
+ );
91
+
92
+ // get subscription status to abandoned cart reminder notification
93
+ $attr = Mage::getModel('customer/customer')->getAttribute('abandonment_subscribed');
94
+ if ($attr->getAttributeId()) {
95
+ $adapter = $collection->getConnection();
96
+ $collection->getSelect()->joinLeft(
97
+ array('abandonment_subscribed' => $attr->getBackend()->getTable()),
98
+ $adapter->quoteInto(
99
+ 'main_table.customer_id = abandonment_subscribed.entity_id'
100
+ . ' AND abandonment_subscribed.attribute_id = ?',
101
+ $attr->getAttributeId()
102
+ ),
103
+ array(
104
+ 'abandonment.customer_abandonment_subscribed'
105
+ => 'IF(abandonment.customer_abandonment_subscribed IS NULL,
106
+ IF(abandonment_subscribed.value IS NULL, 1, abandonment_subscribed.value),
107
+ abandonment.customer_abandonment_subscribed)',
108
+ )
109
+ );
110
+ }
111
+
112
+ if (count($this->_storeIds)) {
113
+ $collection->addFieldToFilter('store_id', array('in' => $this->_storeIds));
114
+ }
115
+
116
+ $this->setCollection($collection);
117
+
118
+ return parent::_prepareCollection();
119
+ }
120
+
121
+ /**
122
+ * (non-PHPdoc)
123
+ * @see Mage_Adminhtml_Block_Widget_Grid::_prepareColumns()
124
+ */
125
+ protected function _prepareColumns()
126
+ {
127
+ $this->addColumn('customer_email', array(
128
+ 'header' => Mage::helper('reports')->__('Email'),
129
+ 'index' => 'customer_email',
130
+ 'sortable' => false
131
+ ));
132
+
133
+ $this->addColumn('items_count', array(
134
+ 'header' => Mage::helper('abandonment')->__('Number of Item Types'),
135
+ 'width' => '80px',
136
+ 'align' => 'right',
137
+ 'index' => 'items_count',
138
+ 'sortable' => false,
139
+ 'type' => 'number'
140
+ ));
141
+
142
+ $this->addColumn('items_qty', array(
143
+ 'header' => Mage::helper('abandonment')->__('Number of Items'),
144
+ 'width' => '80px',
145
+ 'align' => 'right',
146
+ 'index' => 'items_qty',
147
+ 'sortable' => false,
148
+ 'type' => 'number'
149
+ ));
150
+
151
+ if ($this->getRequest()->getParam('website')) {
152
+ $storeIds = Mage::app()->getWebsite($this->getRequest()->getParam('website'))->getStoreIds();
153
+ } else if ($this->getRequest()->getParam('group')) {
154
+ $storeIds = Mage::app()->getGroup($this->getRequest()->getParam('group'))->getStoreIds();
155
+ } else if ($this->getRequest()->getParam('store')) {
156
+ $storeIds = array((int)$this->getRequest()->getParam('store'));
157
+ } else {
158
+ $storeIds = array();
159
+ }
160
+ $this->setStoreIds($storeIds);
161
+ $currencyCode = $this->getCurrentCurrencyCode();
162
+
163
+ $this->addColumn('subtotal', array(
164
+ 'header' => Mage::helper('reports')->__('Subtotal'),
165
+ 'width' => '80px',
166
+ 'type' => 'currency',
167
+ 'currency_code' => $currencyCode,
168
+ 'index' => 'subtotal',
169
+ 'sortable' => false,
170
+ 'renderer' => 'abandonment/adminhtml_list_grid_column_renderer_currency',
171
+ 'rate' => $this->getRate($currencyCode),
172
+ ));
173
+
174
+ $this->addColumn('coupon_code', array(
175
+ 'header' => Mage::helper('reports')->__('Applied Coupon'),
176
+ 'width' => '80px',
177
+ 'index' => 'coupon_code',
178
+ 'filter_index' => 'main_table.coupon_code',
179
+ 'sortable' => false
180
+ ));
181
+
182
+ $this->addColumn('customer', array(
183
+ 'header' => Mage::helper('abandonment')->__('Customer ID'),
184
+ 'width' => '80px',
185
+ 'index' => 'customer_id',
186
+ 'filter_index' => 'main_table.customer_id',
187
+ 'sortable' => false
188
+ ));
189
+
190
+ $this->addColumn('created_at', array(
191
+ 'header' => Mage::helper('reports')->__('Created On'),
192
+ 'width' => '170px',
193
+ 'type' => 'datetime',
194
+ 'index' => 'created_at',
195
+ 'filter_index' => 'main_table.created_at',
196
+ 'sortable' => false
197
+ ));
198
+
199
+ $this->addColumn('updated_at', array(
200
+ 'header' => Mage::helper('reports')->__('Updated On'),
201
+ 'width' => '170px',
202
+ 'type' => 'datetime',
203
+ 'index' => 'updated_at',
204
+ 'filter_index'=> 'main_table.updated_at',
205
+ 'sortable' => false
206
+ ));
207
+
208
+ $this->addColumn('remote_ip', array(
209
+ 'header' => Mage::helper('reports')->__('IP Address'),
210
+ 'width' => '80px',
211
+ 'index' => 'remote_ip',
212
+ 'sortable' => false
213
+ ));
214
+
215
+ $this->addColumn('reminder_id', array(
216
+ 'header' => Mage::helper('abandonment')->__('Sent Reminder'),
217
+ 'index' => 'abandonment.template',
218
+ 'type' => 'options',
219
+ 'sortable' => false,
220
+ 'options' => Mage::helper('abandonment')->getReminderLables()
221
+ ));
222
+
223
+ $this->addColumn('abandonment_updated_at', array(
224
+ 'header' => Mage::helper('abandonment')->__('Reminder Last Update'),
225
+ 'type' => 'datetime',
226
+ 'index' => 'abandonment.updated_at',
227
+ 'sortable' => false
228
+ ));
229
+
230
+ $this->addColumn('abandonment_subscribed', array(
231
+ 'header' => Mage::helper('abandonment')->__('Subscribed to abandoned cart reminders'),
232
+ 'type' => 'options',
233
+ 'index' => 'abandonment.customer_abandonment_subscribed',
234
+ 'options' => array(
235
+ 1 => Mage::helper('core')->__('Yes'),
236
+ 0 => Mage::helper('core')->__('No'),
237
+ ),
238
+ 'filter' => false,
239
+ 'sortable' => false
240
+ ));
241
+
242
+ $this->addColumn('abandonment_coupon_code', array(
243
+ 'header' => Mage::helper('abandonment')->__('Reminder Coupon'),
244
+ 'width' => '80px',
245
+ 'index' => 'abandonment.coupon_code',
246
+ 'sortable' => false
247
+ ));
248
+
249
+ $this->addExportType('*/*/exportAbandonedCsv', Mage::helper('reports')->__('CSV'));
250
+ $this->addExportType('*/*/exportAbandonedExcel', Mage::helper('reports')->__('Excel XML'));
251
+
252
+ return parent::_prepareColumns();
253
+ }
254
+
255
+ /**
256
+ * Allow to find any abandoned carts that haven't had any reminder
257
+ *
258
+ * (non-PHPdoc)
259
+ * @see Mage_Adminhtml_Block_Widget_Grid::_addColumnFilterToCollection()
260
+ */
261
+ protected function _addColumnFilterToCollection($column)
262
+ {
263
+ $field = ( $column->getFilterIndex() ) ? $column->getFilterIndex() : $column->getIndex();
264
+
265
+ if ($field == 'abandonment.template'
266
+ && $column->getFilter()
267
+ && $column->getFilter()->getValue() == Emv_CartAlert_Constants::NONE_FLAG
268
+ ) {
269
+ $this->getCollection()->addFieldToFilter(
270
+ array('abandonment.template', 'abandonment.template'),
271
+ array(array('null' => 0), array('eq' => ""))
272
+ );
273
+ return $this;
274
+ }
275
+
276
+ parent::_addColumnFilterToCollection($column);
277
+ return $this;
278
+ }
279
+
280
+ /**
281
+ * (non-PHPdoc)
282
+ * @see Mage_Adminhtml_Block_Widget_Grid::_prepareMassaction()
283
+ */
284
+ protected function _prepareMassaction()
285
+ {
286
+ $this->setMassactionIdField('entity_id');
287
+ $this->getMassactionBlock()->setFormFieldName('quotes');
288
+
289
+ $this->getMassactionBlock()->addItem('first_reminder', array(
290
+ 'label' => Mage::helper('abandonment')->__('Test First Reminder'),
291
+ 'url' => $this->getUrl('*/*/testReminder' , array('template' => Emv_CartAlert_Constants::FIRST_ALERT_FLAG)),
292
+ 'confirm' => Mage::helper('customer')->__('Are you sure?')
293
+ ));
294
+ $this->getMassactionBlock()->addItem('second_reminder', array(
295
+ 'label' => Mage::helper('abandonment')->__('Test Second Reminder'),
296
+ 'url' => $this->getUrl('*/*/testReminder', array('template' => Emv_CartAlert_Constants::SECOND_ALERT_FLAG)),
297
+ 'confirm' => Mage::helper('customer')->__('Are you sure?')
298
+ ));
299
+ $this->getMassactionBlock()->addItem('third_reminder', array(
300
+ 'label' => Mage::helper('abandonment')->__('Test Third Reminder'),
301
+ 'url' => $this->getUrl('*/*/testReminder', array('template' => Emv_CartAlert_Constants::THIRD_ALERT_FLAG)),
302
+ 'confirm' => Mage::helper('customer')->__('Are you sure?')
303
+ ));
304
+ return $this;
305
+ }
306
+
307
+ /**
308
+ * Get row class - determine the row class according to their subscription information to reminder notification
309
+ *
310
+ * @param Varien_Object $emvEmt
311
+ * @return string
312
+ */
313
+ public function getRowClass(Varien_Object $row)
314
+ {
315
+ $class = "";
316
+ if ($row->getData('abandonment.customer_abandonment_subscribed') == 0) {
317
+ $class= "invalid";
318
+ }
319
+ return $class;
320
+ }
321
+
322
+ /**
323
+ * (non-PHPdoc)
324
+ * @see Mage_Adminhtml_Block_Widget_Grid::getRowUrl()
325
+ */
326
+ public function getRowUrl($row)
327
+ {
328
+ if ($row->getCustomerId()) {
329
+ return $this->getUrl('adminhtml/customer/edit', array('id' => $row->getCustomerId(), 'active_tab'=>'cart'));
330
+ } else {
331
+ return $this->getUrl('*/*/displayQuote', array('quote' => $row->getId()));
332
+ }
333
+
334
+ return '#';
335
+ }
336
+ }
app/code/community/Emv/CartAlert/Block/Adminhtml/List/Grid/Column/Renderer/Currency.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Adminhtml grid item renderer currency
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+
11
+ class Emv_CartAlert_Block_Adminhtml_List_Grid_Column_Renderer_Currency extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Currency
12
+ {
13
+ /**
14
+ * Renders grid column
15
+ *
16
+ * @param Varien_Object $row
17
+ * @return string
18
+ */
19
+ public function render(Varien_Object $row)
20
+ {
21
+ $data = $row->getData($this->getColumn()->getIndex());
22
+ $currency_code = $this->_getCurrencyCode($row);
23
+
24
+ if (!$currency_code) {
25
+ return $data;
26
+ }
27
+
28
+ $data = floatval($data) * $this->_getRate($row);
29
+ $data = sprintf("%f", $data);
30
+ $data = Mage::app()->getLocale()->currency($currency_code)->toCurrency($data);
31
+ return $data;
32
+ }
33
+ }
app/code/community/Emv/CartAlert/Block/Adminhtml/Quote.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Quote grid container block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_CartAlert_Block_Adminhtml_Quote extends Mage_Adminhtml_Block_Widget_Grid_Container
11
+ {
12
+
13
+ /**
14
+ * Construct account menu
15
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::__construct()
16
+ */
17
+ public function __construct()
18
+ {
19
+ parent::__construct();
20
+ $this->_blockGroup = 'abandonment';
21
+ $this->_controller = 'adminhtml_quote';
22
+
23
+ $quote = Mage::registry('smartfocus_quote');
24
+ $this->_headerText = Mage::helper('abandonment')->__(
25
+ 'Abandoned Cart (customer email : %s - on store %s)',
26
+ $quote->getCustomerEmail(),
27
+ Mage::app()->getStore($quote->getStoreId())->getName()
28
+ );
29
+
30
+ $this->_removeButton('add');
31
+ $this->_addBackButton();
32
+ }
33
+
34
+ /**
35
+ * Link back to abandoned cart list page
36
+ *
37
+ * @return string
38
+ */
39
+ public function getBackUrl()
40
+ {
41
+ return $this->getUrl('*/*/list');
42
+ }
43
+ }
app/code/community/Emv/CartAlert/Block/Adminhtml/Quote/Grid.php ADDED
@@ -0,0 +1,123 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Quote Product Information Grid Block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_CartAlert_Block_Adminhtml_Quote_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
+ {
12
+ /**
13
+ * Prepare grid
14
+ *
15
+ * @return void
16
+ */
17
+ protected function _prepareGrid()
18
+ {
19
+ $this->setId('smartfocus_cart_grid');
20
+ $quote = Mage::registry('smartfocus_quote');
21
+
22
+ if ($quote) {
23
+ $this->setStoreId($quote->getStoreId());
24
+ }
25
+ parent::_prepareGrid();
26
+ }
27
+
28
+ /**
29
+ * Prepare collection
30
+ *
31
+ * (non-PHPdoc)
32
+ * @see Mage_Adminhtml_Block_Widget_Grid::_prepareCollection()
33
+ */
34
+ protected function _prepareCollection()
35
+ {
36
+ $quote = Mage::registry('smartfocus_quote');
37
+ if ($quote) {
38
+ $collection = $quote->getItemsCollection(false);
39
+ } else {
40
+ $collection = new Varien_Data_Collection();
41
+ }
42
+
43
+ $collection->addFieldToFilter('parent_item_id', array('null' => true));
44
+
45
+ $this->setCollection($collection);
46
+
47
+ return parent::_prepareCollection();
48
+ }
49
+
50
+ /**
51
+ * (non-PHPdoc)
52
+ * @see Mage_Adminhtml_Block_Widget_Grid::_prepareColumns()
53
+ */
54
+ protected function _prepareColumns()
55
+ {
56
+ $this->addColumn('product_id', array(
57
+ 'header' => Mage::helper('catalog')->__('Product ID'),
58
+ 'index' => 'product_id',
59
+ 'width' => '100px',
60
+ ));
61
+
62
+ $this->addColumn('name', array(
63
+ 'header' => Mage::helper('catalog')->__('Product Name'),
64
+ 'index' => 'name',
65
+ 'renderer' => 'adminhtml/customer_edit_tab_view_grid_renderer_item'
66
+ ));
67
+
68
+ $this->addColumn('created_at', array(
69
+ 'header' => Mage::helper('reports')->__('Created At'),
70
+ 'index' => 'created_at',
71
+ 'type' => 'datetime',
72
+ 'width' => '150px',
73
+ ));
74
+ $this->addColumn('updated_at', array(
75
+ 'header' => Mage::helper('reports')->__('Updated At'),
76
+ 'index' => 'updated_at',
77
+ 'type' => 'datetime',
78
+ 'width' => '150px',
79
+ ));
80
+
81
+ $this->addColumn('sku', array(
82
+ 'header' => Mage::helper('catalog')->__('SKU'),
83
+ 'index' => 'sku',
84
+ 'width' => '100px',
85
+ ));
86
+
87
+ $this->addColumn('qty', array(
88
+ 'header' => Mage::helper('catalog')->__('Qty'),
89
+ 'index' => 'qty',
90
+ 'type' => 'number',
91
+ 'width' => '60px',
92
+ ));
93
+
94
+ $this->addColumn('price', array(
95
+ 'header' => Mage::helper('catalog')->__('Price'),
96
+ 'index' => 'price',
97
+ 'type' => 'currency',
98
+ 'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE,
99
+ $this->getStoreId()),
100
+ ));
101
+
102
+ $this->addColumn('total', array(
103
+ 'header' => Mage::helper('sales')->__('Total'),
104
+ 'index' => 'row_total',
105
+ 'type' => 'currency',
106
+ 'currency_code' => (string) Mage::getStoreConfig(Mage_Directory_Model_Currency::XML_PATH_CURRENCY_BASE,
107
+ $this->getStoreId()),
108
+ ));
109
+
110
+ return parent::_prepareColumns();
111
+ }
112
+
113
+ /**
114
+ * The link to product page
115
+ *
116
+ * (non-PHPdoc)
117
+ * @see Mage_Adminhtml_Block_Widget_Grid::getRowUrl()
118
+ */
119
+ public function getRowUrl($row)
120
+ {
121
+ return $this->getUrl('adminhtml/catalog_product/edit', array('id' => $row->getProductId()));
122
+ }
123
+ }
app/code/community/Emv/CartAlert/Block/Adminhtml/System/Config/PromoRule.php ADDED
@@ -0,0 +1,100 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Promotion Rule Chooser block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+
11
+ class Emv_CartAlert_Block_Adminhtml_System_Config_PromoRule
12
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
13
+ {
14
+ /**
15
+ * Set template to itself
16
+ *
17
+ * @return Emv_CartAlert_Block_Adminhtml_System_Config_PromoRule
18
+ */
19
+ protected function _prepareLayout()
20
+ {
21
+ parent::_prepareLayout();
22
+ if (!$this->getTemplate()) {
23
+ $this->setTemplate('smartfocus/cartalert/system/config/promo_rule.phtml');
24
+ }
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Get button config in Json
30
+ *
31
+ * @return string
32
+ */
33
+ public function getButtonConfigInJson()
34
+ {
35
+ $config = array(
36
+ 'buttons' => array(
37
+ 'open' => Mage::helper('abandonment')->__('Select Promotion Rule'),
38
+ 'close' => Mage::helper('abandonment')->__('Close'),
39
+ )
40
+ );
41
+ return Mage::helper('core')->jsonEncode($config);
42
+ }
43
+
44
+ /**
45
+ * Get promotion rule id
46
+ *
47
+ * @return int
48
+ */
49
+ public function getRuleId()
50
+ {
51
+ $id = '';
52
+ if ($this->getElement()) {
53
+ $id = (int)$this->getElement()->getValue();
54
+ }
55
+ return $id;
56
+ }
57
+
58
+ /**
59
+ * Get Label for element
60
+ *
61
+ * @return string
62
+ */
63
+ public function getLabel()
64
+ {
65
+ $label = false;
66
+ if ($this->getElement()) {
67
+ $rule = Mage::getModel('salesrule/rule')->load((int)$this->getElement()->getValue());
68
+ if ($rule->getId()) {
69
+ $label = $rule->getName();
70
+ }
71
+ }
72
+
73
+ if (!$label) {
74
+ $label = Mage::helper('widget')->__('Not Selected');
75
+ }
76
+
77
+ return $label;
78
+ }
79
+
80
+ /**
81
+ * @return string
82
+ */
83
+ public function getElementName()
84
+ {
85
+ return ($this->getElement()) ? $this->getElement()->getName() : '';
86
+ }
87
+
88
+ /**
89
+ * Get the button and scripts contents
90
+ *
91
+ * @param Varien_Data_Form_Element_Abstract $element
92
+ *
93
+ * @return string
94
+ */
95
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
96
+ {
97
+ $this->setElement($element);
98
+ return $this->_toHtml();
99
+ }
100
+ }
app/code/community/Emv/CartAlert/Block/Cart/Items.php CHANGED
@@ -14,6 +14,6 @@ class Emv_CartAlert_Block_Cart_Items extends Mage_Sales_Block_Items_Abstract
14
  public function __construct()
15
  {
16
  parent::__construct();
17
- $this->setTemplate('emailvision' . DS . 'abandonment' . DS . 'reminder' . DS . 'items.phtml');
18
  }
19
  }
14
  public function __construct()
15
  {
16
  parent::__construct();
17
+ $this->setTemplate('smartfocus' . DS . 'abandonment' . DS . 'reminder' . DS . 'items.phtml');
18
  }
19
  }
app/code/community/Emv/CartAlert/Constants.php CHANGED
@@ -4,10 +4,14 @@
4
  *
5
  * @category Emv
6
  * @package Emv_CartAlert
 
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
  interface Emv_CartAlert_Constants
10
  {
 
 
 
11
  const XML_PATH_FIRST_ALERT_ENABLED = 'abandonment/first_alert_config/enabled';
12
  const XML_PATH_FIRST_ALERT_TEMPLATE = 'abandonment/first_alert_config/template';
13
  const XML_PATH_FIRST_ALERT_DELAY = 'abandonment/first_alert_config/delay';
@@ -28,6 +32,7 @@ interface Emv_CartAlert_Constants
28
  const XML_PATH_COUPON_CODE_SUFFIX = 'abandonment/general/suffix';
29
  const XML_PATH_COUPON_CODE_DASH = 'abandonment/general/dash';
30
 
 
31
  const FIRST_ALERT_FLAG = 'first_alert';
32
  const FIRST_ALERT_REMINDER_ID = 1;
33
  const SECOND_ALERT_FLAG = 'second_alert';
4
  *
5
  * @category Emv
6
  * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
9
  */
10
  interface Emv_CartAlert_Constants
11
  {
12
+ const XML_PATH_TEST_MODE_ENABLED = 'abandonment/general/test_mode';
13
+ const XML_PATH_LIFETIME = 'abandonment/general/lifetime';
14
+
15
  const XML_PATH_FIRST_ALERT_ENABLED = 'abandonment/first_alert_config/enabled';
16
  const XML_PATH_FIRST_ALERT_TEMPLATE = 'abandonment/first_alert_config/template';
17
  const XML_PATH_FIRST_ALERT_DELAY = 'abandonment/first_alert_config/delay';
32
  const XML_PATH_COUPON_CODE_SUFFIX = 'abandonment/general/suffix';
33
  const XML_PATH_COUPON_CODE_DASH = 'abandonment/general/dash';
34
 
35
+ const NONE_FLAG = 'none';
36
  const FIRST_ALERT_FLAG = 'first_alert';
37
  const FIRST_ALERT_REMINDER_ID = 1;
38
  const SECOND_ALERT_FLAG = 'second_alert';
app/code/community/Emv/CartAlert/Helper/Data.php CHANGED
@@ -4,6 +4,7 @@
4
  *
5
  * @category Emv
6
  * @package Emv_CartAlert
 
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
  class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
@@ -18,6 +19,12 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
18
  */
19
  const XML_PATH_IMAGE_SIZE = 'abandonment/general/image_size';
20
 
 
 
 
 
 
 
21
  /**
22
  * @var array
23
  */
@@ -46,6 +53,53 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
46
  */
47
  protected $_rules = array();
48
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
49
  /**
50
  * Detect whether the quote is associated with a registered customer
51
  *
@@ -154,12 +208,12 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
154
  * Retrieves an image URL for the product, if it exists.
155
  * The priority is: thumbnail -> small image -> image -> Magento's placeholder.
156
  *
157
- * @param $productId
158
  * @return string the image's URL
159
  */
160
- public function getProductImageUrl ($productId)
161
  {
162
- $product = $this->getProduct($productId);
163
 
164
  $imageSize = Mage::getStoreConfig(self::XML_PATH_IMAGE_SIZE);
165
  if (!$imageSize) {
@@ -186,10 +240,11 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
186
  * @param string $productId
187
  * @return multitype:
188
  */
189
- public function getProduct($productId)
190
  {
 
191
  if (!isset($this->_loadedProducts[$productId])) {
192
- $this->_loadedProducts[$productId] = Mage::getModel('catalog/product')->load($productId);
193
  }
194
 
195
  return $this->_loadedProducts[$productId];
@@ -224,11 +279,13 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
224
  * @param $storeId
225
  * @param Emv_CartAlert_Model_Abandonment $abandonment
226
  * @param Mage_Core_Model_Email_Template
 
227
  */
228
  public function sendReminder(
229
  Mage_Sales_Model_Quote $abandonedCart,
230
  $storeId,
231
- Emv_CartAlert_Model_Abandonment $abandonment
 
232
  ) {
233
  // determine which template should be used
234
  $reminderId = false;
@@ -269,17 +326,58 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
269
  Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_ALERT_SENDER_IDENTITY, $storeId),
270
  $abandonedCart->getCustomerEmail(),
271
  $abandonedCart->getPreparedCustomerName(),
272
- Array('cart' => $abandonedCart, 'promo_code' => $abandonment->getCouponCode()),
273
  $storeId
274
  );
275
 
276
- // update reminder statistic
277
- $this->updateStats($reminderId, $abandonedCart->getId(), $storeId);
 
 
278
  }
279
  }
280
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
281
  /**
282
  * Update statistic information about the reminder sending
 
283
  * @param int $reminderId
284
  * @param int $quoteId
285
  * @param int $storeId
@@ -440,6 +538,50 @@ class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
440
  return $code;
441
  }
442
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
443
  /**
444
  * Support functions - Used for debugging purposes
445
  */
4
  *
5
  * @category Emv
6
  * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_CartAlert_Helper_Data extends Mage_Core_Helper_Abstract
19
  */
20
  const XML_PATH_IMAGE_SIZE = 'abandonment/general/image_size';
21
 
22
+ /**
23
+ *
24
+ * XML PATH to get the limit to run
25
+ */
26
+ const XML_PATH_CART_LIMIT = 'abandonment/general/limit';
27
+
28
  /**
29
  * @var array
30
  */
53
  */
54
  protected $_rules = array();
55
 
56
+ /**
57
+ * Lock file name pattern
58
+ */
59
+ const LOCK_FILE_NAME_PATTERN = 'abandoned_cart_process';
60
+
61
+ /**
62
+ * Check if lock file exists
63
+ *
64
+ * @return boolean
65
+ */
66
+ public function checkLockFile()
67
+ {
68
+ return Mage::helper('emvcore')->checkLockFile(self::LOCK_FILE_NAME_PATTERN);
69
+ }
70
+
71
+ /**
72
+ * Get cart limit for one run
73
+ *
74
+ * @return int
75
+ */
76
+ public function getCartLimitForOneRun()
77
+ {
78
+ return (int)Mage::getStoreConfig(self::XML_PATH_CART_LIMIT);
79
+ }
80
+
81
+ /**
82
+ * Create a lock file
83
+ *
84
+ * @param string $content
85
+ * @return mutilple <number, boolean>
86
+ */
87
+ public function createLockFile($content = '')
88
+ {
89
+ return Mage::helper('emvcore')->createLockFile(self::LOCK_FILE_NAME_PATTERN, $content);
90
+ }
91
+
92
+ /**
93
+ * Remove a lock file
94
+ *
95
+ * @param string $content
96
+ * @return boolean
97
+ */
98
+ public function removeLockFile($content = '')
99
+ {
100
+ return Mage::helper('emvcore')->removeLockFile(self::LOCK_FILE_NAME_PATTERN);
101
+ }
102
+
103
  /**
104
  * Detect whether the quote is associated with a registered customer
105
  *
208
  * Retrieves an image URL for the product, if it exists.
209
  * The priority is: thumbnail -> small image -> image -> Magento's placeholder.
210
  *
211
+ * @param Mage_Sales_Model_Quote_Item $item
212
  * @return string the image's URL
213
  */
214
+ public function getProductImageUrl (Mage_Sales_Model_Quote_Item $item)
215
  {
216
+ $product = $this->getProductFromQuoteItem($item);
217
 
218
  $imageSize = Mage::getStoreConfig(self::XML_PATH_IMAGE_SIZE);
219
  if (!$imageSize) {
240
  * @param string $productId
241
  * @return multitype:
242
  */
243
+ public function getProductFromQuoteItem(Mage_Sales_Model_Quote_Item $item)
244
  {
245
+ $productId = $item->getProductId();
246
  if (!isset($this->_loadedProducts[$productId])) {
247
+ $this->_loadedProducts[$productId] = $item->getProduct();
248
  }
249
 
250
  return $this->_loadedProducts[$productId];
279
  * @param $storeId
280
  * @param Emv_CartAlert_Model_Abandonment $abandonment
281
  * @param Mage_Core_Model_Email_Template
282
+ * @param boolean $updateStats
283
  */
284
  public function sendReminder(
285
  Mage_Sales_Model_Quote $abandonedCart,
286
  $storeId,
287
+ Emv_CartAlert_Model_Abandonment $abandonment,
288
+ $updateStats = true
289
  ) {
290
  // determine which template should be used
291
  $reminderId = false;
326
  Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_ALERT_SENDER_IDENTITY, $storeId),
327
  $abandonedCart->getCustomerEmail(),
328
  $abandonedCart->getPreparedCustomerName(),
329
+ array('cart' => $abandonedCart, 'promo_code' => $abandonment->getCouponCode()),
330
  $storeId
331
  );
332
 
333
+ if ($updateStats) {
334
+ // update reminder statistic
335
+ $this->updateStats($reminderId, $abandonedCart->getId(), $storeId);
336
+ }
337
  }
338
  }
339
 
340
+ /**
341
+ * Prepare necessary information and send an appropriate reminder for a given quote.
342
+ * If $updateStats is equal to true, we update the reminder sending statistics
343
+ *
344
+ * @param string $reminderTemplate (which reminder to send - first, second or third)
345
+ * @param Mage_Sales_Model_Quote $quote
346
+ * @param Emv_CartAlert_Model_Abandonment $abandonment
347
+ * @param boolean $updateStats
348
+ */
349
+ public function prepareAndSendReminder($reminderTemplate,
350
+ Mage_Sales_Model_Quote $quote,
351
+ Emv_CartAlert_Model_Abandonment $abandonment,
352
+ $updateStats = true
353
+ )
354
+ {
355
+ $preparedCustomerName = ($quote->getCustomerPrefix() ? $quote->getCustomerPrefix() . ' ' : '')
356
+ . $quote->getCustomerFirstname()
357
+ . ' ' . ($quote->getCustomerMiddlename() ? $quote->getCustomerMiddlename() . ' ' : '')
358
+ . $quote->getCustomerLastname()
359
+ . ($quote->getCustomerSuffix() ? ' ' . $quote->getCustomerSuffix() : '')
360
+ ;
361
+ $quote->setPreparedCustomerName($preparedCustomerName);
362
+
363
+ // set the unsubscription link (depends on whether the user was logged in)
364
+ $quote->setUnsubLink($this->getUnsubscribeLink($quote));
365
+ // set the cart link (depends on whether the user was logged in)
366
+ $quote->setCartLink($this->getCartLink($quote, $reminderTemplate));
367
+ // set the store link (depends on whether the user was logged in)
368
+ $quote->setStoreLink($this->getStoreLink($quote, $reminderTemplate));
369
+ // set the reminder template will be used to send
370
+ $quote->setReminderTemplate($reminderTemplate);
371
+
372
+ // set formated grand total
373
+ $quote->setPreparedGrandToTal(Mage::helper('checkout')->formatPrice($quote->getGrandTotal(), true, true));
374
+
375
+ $this->sendReminder($quote, $quote->getStoreId(), $abandonment, $updateStats);
376
+ }
377
+
378
  /**
379
  * Update statistic information about the reminder sending
380
+ *
381
  * @param int $reminderId
382
  * @param int $quoteId
383
  * @param int $storeId
538
  return $code;
539
  }
540
 
541
+ /**
542
+ * Remove the last save reminder template for a give quote
543
+ * so that the abandoned cart reminder processus can restart again
544
+ *
545
+ * @param Mage_Sales_Model_Quote $quote
546
+ */
547
+ public function resetReminderForQuote(Mage_Sales_Model_Quote $quote)
548
+ {
549
+ $gmtDate = Mage::getModel('core/date')->gmtDate();
550
+
551
+ $resource = Mage::getModel('core/resource');
552
+ $writeConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE);
553
+
554
+ $query = "
555
+ UPDATE {$resource->getTableName('abandonment/abandonment')}
556
+ SET updated_at = '$gmtDate', template = NULL
557
+ ";
558
+ $query .= $writeConnection->quoteInto(' WHERE entity_id = ?', $quote->getId());
559
+
560
+ if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED)) {
561
+ $query .= $writeConnection->quoteInto(' AND template = ?', Emv_CartAlert_Constants::THIRD_ALERT_FLAG);
562
+ } else if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED)) {
563
+ $query .= $writeConnection->quoteInto(' AND template = ?', Emv_CartAlert_Constants::SECOND_ALERT_FLAG);
564
+ } else if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED)) {
565
+ $query .= $writeConnection->quoteInto(' AND template = ?', Emv_CartAlert_Constants::FIRST_ALERT_FLAG);
566
+ }
567
+ $writeConnection->query($query);
568
+ }
569
+
570
+ /**
571
+ * Get available reminder labels
572
+ *
573
+ * @return array
574
+ */
575
+ public function getReminderLables()
576
+ {
577
+ return array(
578
+ Emv_CartAlert_Constants::NONE_FLAG => Mage::helper('abandonment')->__('None'),
579
+ Emv_CartAlert_Constants::FIRST_ALERT_FLAG => Mage::helper('abandonment')->__('First Reminder'),
580
+ Emv_CartAlert_Constants::SECOND_ALERT_FLAG => Mage::helper('abandonment')->__('Second Reminder'),
581
+ Emv_CartAlert_Constants::THIRD_ALERT_FLAG => Mage::helper('abandonment')->__('Third Reminder')
582
+ );
583
+ }
584
+
585
  /**
586
  * Support functions - Used for debugging purposes
587
  */
app/code/community/Emv/CartAlert/Model/Observer.php CHANGED
@@ -5,15 +5,59 @@
5
  *
6
  * @category Emv
7
  * @package Emv_CartAlert
 
8
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Get abandoned quotes to send reminders
 
 
 
14
  * @return Mage_Sales_Model_Mysql4_Quote_Collection
15
  */
16
- protected function _getConcernedQuotes()
17
  {
18
  // prepare query for abandoned quotes
19
  $minHour = Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_DELAY);
@@ -23,27 +67,44 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
23
 
24
  /* @var $date Zend_Date */
25
  $from = Mage::app()->getLocale()->utcDate(null, $now);
26
- $from->subHour($minHour);
 
 
 
 
 
27
  $from = $from->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
28
 
29
  // the expiration date
30
  $expDate = Mage::app()->getLocale()->utcDate(null, $now);
31
- $expDate->sub(Emv_CartAlert_Constants::OUTDATED_CART_DELAY, Zend_Date::HOUR);
32
  $expDate = $expDate->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
33
 
34
  // get abandoned quotes
35
  /* @var $quotes Mage_Sales_Model_Mysql4_Quote_Collection */
36
  $quotes = Mage::getModel('sales/quote')->getCollection();
37
  $select = $quotes->getSelect();
38
- // make a left join to abandonment table in order to know which template has been used
 
 
 
 
39
  $select->joinLeft(
40
  array('a' => $quotes->getTable('abandonment/abandonment')),
41
  'main_table.entity_id = a.entity_id',
42
- array('template')
 
 
 
 
 
 
 
 
43
  );
44
 
45
- //get customers' abandonment_subscribed value
46
- $attr = Mage::getModel('customer/customer')->getAttribute('abandonment_subscribed');
47
  $adapter = $quotes->getConnection();
48
  if ($attr->getAttributeId()) {
49
  $select->joinLeft(
@@ -53,45 +114,87 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
53
  . ' AND abandonment_subscribed.attribute_id = ?',
54
  $attr->getAttributeId()
55
  ),
56
- // by default, we activate abandonment reminder subscription for all clients
57
- array('abandonment_subscribed_value' => 'IF(abandonment_subscribed.value IS NULL, 1, abandonment_subscribed.value)')
 
 
 
58
  );
59
  }
60
 
61
- $select->where('a.customer_abandonment_subscribed = ? OR a.customer_abandonment_subscribed IS NULL', 1)
 
 
 
 
 
 
 
 
 
 
 
 
 
 
62
  ->where('a.template <> ? OR a.template IS NULL', Emv_CartAlert_Constants::OUTDATED_FLAG)
63
  ->where('a.template <> ? OR a.template IS NULL', Emv_CartAlert_Constants::THIRD_ALERT_FLAG)
64
  ;
65
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
66
  $quotes
67
- ->addFieldToFilter('updated_at', array('to' => $from, 'from' => $expDate))
68
- ->addFieldToFilter('items_count', array('gt' => 0))
69
  ->addFieldToFilter('customer_email', array('notnull' => 1)) // a quote with a valid email address
70
  ->addFieldToFilter('is_active', 1) // only get active quotes
71
- ->setOrder('updated_at')
72
  ;
73
 
74
  return $quotes;
75
  }
76
 
77
  /**
78
- * Observer to check for abandoned shopping carts
 
 
79
  */
80
- public function processAbandonedCarts ()
81
  {
82
- // save the current store so that this observer doesn't interfere with any other functions
83
- $currentStore = Mage::app()->getStore()->getStoreId();
 
 
 
 
 
 
 
 
 
 
 
 
 
84
 
85
- // if Shopping Cart Abandonment is enabled
86
- if(
87
- Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED) == 1
88
- || Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED) == 1
89
- || Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED) == 1
90
- ) {
91
- /* @var $helper Emv_CartAlert_Helper_Data */
92
- $helper = Mage::helper('abandonment');
93
 
94
- $quotes = $this->_getConcernedQuotes();
95
  /* @var $quote Mage_Sales_Model_Quote */
96
  foreach ($quotes as $quote) {
97
  // Set the current store
@@ -101,7 +204,7 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
101
  $needToSaveAbandonment = false;
102
 
103
  // search abandoned carts for this particular quote
104
- $abandonment = Mage::getModel('abandonment/abandonment')->loadByQuoteId($quote->getEntityId());
105
 
106
  if (!$abandonment->getId()) {
107
  $abandonment->setEntityId($quote->getId())
@@ -127,53 +230,115 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
127
  );
128
 
129
  if ($updatedTemplate != null) {
130
- $preparedCustomerName = ($quote->getCustomerPrefix() ? $quote->getCustomerPrefix() . ' ' : '')
131
- . $quote->getCustomerFirstname()
132
- . ' ' . ($quote->getCustomerMiddlename() ? $quote->getCustomerMiddlename() . ' ' : '')
133
- . $quote->getCustomerLastname()
134
- . ($quote->getCustomerSuffix() ? ' ' . $quote->getCustomerSuffix() : '')
135
- ;
136
- $quote->setPreparedCustomerName($preparedCustomerName);
137
-
138
- // set the unsubscription link (depends on whether the user was logged in)
139
- $quote->setUnsubLink($helper->getUnsubscribeLink($quote));
140
- // set the cart link (depends on whether the user was logged in)
141
- $quote->setCartLink($helper->getCartLink($quote, $updatedTemplate));
142
- // set the store link (depends on whether the user was logged in)
143
- $quote->setStoreLink($helper->getStoreLink($quote, $updatedTemplate));
144
- // set the reminder template will be used to send
145
- $quote->setReminderTemplate($updatedTemplate);
146
-
147
- // set formated grand total
148
- $quote->setPreparedGrandToTal(Mage::helper('checkout')->formatPrice($quote->getGrandTotal(), true, true));
149
-
150
  if ($previousTemplate != $updatedTemplate) {
151
  // update the reminder template will be used to send
152
  $abandonment->setTemplate($updatedTemplate);
153
 
 
154
  $rule = $helper->getShoppingCartPriceRule();
155
  if ($rule->getId() != $abandonment->getShoppingCartRuleId()) {
156
  $abandonment->setShoppingCartRuleId($rule->getId());
157
  $abandonment->setCouponCode($helper->getCouponCode($rule->getId()));
158
  }
159
-
160
  $needToSaveAbandonment = true;
161
  }
162
 
163
- $helper->sendReminder($quote, $quote->getStoreId(), $abandonment);
164
  }
165
  }
166
 
167
  if ($needToSaveAbandonment) {
 
 
168
  $abandonment->save();
169
  }
170
  }
171
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
 
173
  // return the store to normal
174
  Mage::app()->setCurrentStore($currentStore);
175
  }
176
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
177
  /**
178
  * Indicate which reminder template can be used to send.
179
  * Return null if we can't send the reminder else the reminder name
@@ -199,7 +364,7 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
199
 
200
  // expiration date
201
  $expirationDate = $locale->utcDate(null, $now);
202
- $expirationDate->subHour(Emv_CartAlert_Constants::OUTDATED_CART_DELAY);
203
 
204
  if ($expirationDate->isLater($lastUpdate)) {
205
  $updatedTemplate = Emv_CartAlert_Constants::OUTDATED_FLAG;
@@ -210,23 +375,41 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
210
 
211
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED, $store)) {
212
  $firstAlertDelay = $locale->utcDate(null, $now);
213
- $firstAlertDelay->subHour(
214
- Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_DELAY, $store)
215
- );
 
 
 
 
 
 
216
  }
217
 
218
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED, $store)) {
219
  $secondAlertDelay = $locale->utcDate(null, $now);
220
- $secondAlertDelay->subHour(
221
- Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_DELAY, $store)
222
- );
 
 
 
 
 
 
223
  }
224
 
225
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED, $store)) {
226
  $thirdAlertDelay = $locale->utcDate(null, $now);
227
- $thirdAlertDelay->subHour(
228
- Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_DELAY, $store)
229
- );
 
 
 
 
 
 
230
  }
231
 
232
  // determine which reminder (first, second, third) needs to be sent
@@ -307,4 +490,29 @@ class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
307
  $session->unsetData('abandonment_flag');
308
  $session->unsetData('abandonment_date');
309
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
310
  }
5
  *
6
  * @category Emv
7
  * @package Emv_CartAlert
8
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
9
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
10
  */
11
  class Emv_CartAlert_Model_Observer extends Mage_Core_Model_Abstract
12
  {
13
+ protected $_testMode = null;
14
+
15
+ /**
16
+ * @var Mage_Customer_Model_Entity_Attribute
17
+ */
18
+ protected $_subscribeAttribute = null;
19
+
20
+ /**
21
+ * @var array
22
+ */
23
+ protected $_reminderTypes = array('first', 'second', 'third');
24
+
25
+ /**
26
+ * @return boolean
27
+ */
28
+ public function getTestMode()
29
+ {
30
+ if ($this->_testMode === null) {
31
+ $this->_testMode = (bool)Mage::getStoreConfig(
32
+ Emv_CartAlert_Constants::XML_PATH_TEST_MODE_ENABLED,
33
+ Mage_Core_Model_App::ADMIN_STORE_ID
34
+ );
35
+ }
36
+
37
+ return $this->_testMode;
38
+ }
39
+
40
+ /**
41
+ * Get abandonment_subscribed attribute
42
+ * @return Mage_Customer_Model_Entity_Attribute | null
43
+ */
44
+ protected function _getSubscribeAttribute()
45
+ {
46
+ if (!$this->_subscribeAttribute) {
47
+ // get customers' abandonment_subscribed value
48
+ $this->_subscribeAttribute = Mage::getModel('customer/customer')->getAttribute('abandonment_subscribed');
49
+ }
50
+ return $this->_subscribeAttribute;
51
+ }
52
+
53
  /**
54
  * Get abandoned quotes to send reminders
55
+ *
56
+ * @param int $limit
57
+ * @param string $type reminder type
58
  * @return Mage_Sales_Model_Mysql4_Quote_Collection
59
  */
60
+ protected function _getConcernedQuotes($limit, $type)
61
  {
62
  // prepare query for abandoned quotes
63
  $minHour = Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_DELAY);
67
 
68
  /* @var $date Zend_Date */
69
  $from = Mage::app()->getLocale()->utcDate(null, $now);
70
+
71
+ if ($this->getTestMode()) {
72
+ $from->subMinute($minHour);
73
+ } else {
74
+ $from->subHour($minHour);
75
+ }
76
  $from = $from->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
77
 
78
  // the expiration date
79
  $expDate = Mage::app()->getLocale()->utcDate(null, $now);
80
+ $expDate->sub(Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_LIFETIME), Zend_Date::HOUR);
81
  $expDate = $expDate->toString(Varien_Date::DATETIME_INTERNAL_FORMAT);
82
 
83
  // get abandoned quotes
84
  /* @var $quotes Mage_Sales_Model_Mysql4_Quote_Collection */
85
  $quotes = Mage::getModel('sales/quote')->getCollection();
86
  $select = $quotes->getSelect();
87
+
88
+ // set the limit
89
+ $select->limit($limit);
90
+
91
+ // make a left join to abandonment table get all data
92
  $select->joinLeft(
93
  array('a' => $quotes->getTable('abandonment/abandonment')),
94
  'main_table.entity_id = a.entity_id',
95
+ array(
96
+ 'abandonment_id',
97
+ 'abandonment_entity_id' => 'a.entity_id',
98
+ 'abandonment_template' => 'a.template',
99
+ 'abandonment_customer_abandonment_subscribed' => 'a.customer_abandonment_subscribed',
100
+ 'abandonment_customer_id' => 'a.customer_id',
101
+ 'abandonment_shopping_cart_rule_id' => 'a.shopping_cart_rule_id',
102
+ 'abandonment_coupon_code' => 'a.coupon_code'
103
+ )
104
  );
105
 
106
+ // get customers' abandonment_subscribed value
107
+ $attr = $this->_getSubscribeAttribute();
108
  $adapter = $quotes->getConnection();
109
  if ($attr->getAttributeId()) {
110
  $select->joinLeft(
114
  . ' AND abandonment_subscribed.attribute_id = ?',
115
  $attr->getAttributeId()
116
  ),
117
+ // by default, we activate abandonment reminder for all clients
118
+ array(
119
+ 'abandonment_subscribed_value'
120
+ => 'IF(abandonment_subscribed.value IS NULL, 1, abandonment_subscribed.value)'
121
+ )
122
  );
123
  }
124
 
125
+ // only get the carts which
126
+ // 1. their users allow to receive the reminders
127
+ // 2. are not too late
128
+ // 3. have not received the third reminders yet
129
+ $select
130
+ ->where('
131
+ (
132
+ main_table.customer_id IS NOT NULL
133
+ AND (abandonment_subscribed.value = 1 OR abandonment_subscribed.value IS NULL)
134
+ )
135
+ OR (
136
+ main_table.customer_id IS NULL
137
+ AND (a.customer_abandonment_subscribed = 1 OR a.customer_abandonment_subscribed IS NULL)
138
+ )
139
+ ')
140
  ->where('a.template <> ? OR a.template IS NULL', Emv_CartAlert_Constants::OUTDATED_FLAG)
141
  ->where('a.template <> ? OR a.template IS NULL', Emv_CartAlert_Constants::THIRD_ALERT_FLAG)
142
  ;
143
 
144
+ switch ($type) {
145
+ case 'first' :
146
+ $select->where(
147
+ 'a.template IS NULL OR a.template = "" OR a.template = ?',
148
+ Emv_CartAlert_Constants::TO_BE_PROCESSED_FLAG
149
+ );
150
+ break;
151
+ case 'second' :
152
+ $select->where('a.template = ?', Emv_CartAlert_Constants::FIRST_ALERT_FLAG);
153
+ break;
154
+ case 'third' :
155
+ $select->where('a.template = ?', Emv_CartAlert_Constants::SECOND_ALERT_FLAG);
156
+ break;
157
+ }
158
+
159
  $quotes
160
+ ->addFieldToFilter('main_table.updated_at', array('to' => $from, 'from' => $expDate))
161
+ ->addFieldToFilter('items_count', array('gt' => 0)) // have at least 1 item
162
  ->addFieldToFilter('customer_email', array('notnull' => 1)) // a quote with a valid email address
163
  ->addFieldToFilter('is_active', 1) // only get active quotes
164
+ ->setOrder('updated_at', Varien_Data_Collection::SORT_ORDER_ASC) // sort the carts from older to newer
165
  ;
166
 
167
  return $quotes;
168
  }
169
 
170
  /**
171
+ * Process the abandonned carts for a given type reminder
172
+ * @param int $limit
173
+ * @param string $type reminder type (first, second, third)
174
  */
175
+ public function processAbandonedCartsForType($limit, $type)
176
  {
177
+ /* @var $helper Emv_CartAlert_Helper_Data */
178
+ $helper = Mage::helper('abandonment');
179
+
180
+ $pathConfig;
181
+ switch ($type) {
182
+ case 'first' :
183
+ $pathConfig = Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED;
184
+ break;
185
+ case 'second' :
186
+ $pathConfig = Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED;
187
+ break;
188
+ case 'third' :
189
+ $pathConfig = Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED;
190
+ break;
191
+ }
192
 
193
+ // check if this reminder is activated
194
+ if (Mage::getStoreConfig($pathConfig) == 1) {
195
+ // get all quotes that can be sent for this reminder
196
+ $quotes = $this->_getConcernedQuotes($limit, $type);
 
 
 
 
197
 
 
198
  /* @var $quote Mage_Sales_Model_Quote */
199
  foreach ($quotes as $quote) {
200
  // Set the current store
204
  $needToSaveAbandonment = false;
205
 
206
  // search abandoned carts for this particular quote
207
+ $abandonment = $this->_prepareAbandonmentObjectFromQuote($quote);
208
 
209
  if (!$abandonment->getId()) {
210
  $abandonment->setEntityId($quote->getId())
230
  );
231
 
232
  if ($updatedTemplate != null) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
233
  if ($previousTemplate != $updatedTemplate) {
234
  // update the reminder template will be used to send
235
  $abandonment->setTemplate($updatedTemplate);
236
 
237
+ // if we change the promotion shopping cart rule, we need to change the coupon code
238
  $rule = $helper->getShoppingCartPriceRule();
239
  if ($rule->getId() != $abandonment->getShoppingCartRuleId()) {
240
  $abandonment->setShoppingCartRuleId($rule->getId());
241
  $abandonment->setCouponCode($helper->getCouponCode($rule->getId()));
242
  }
 
243
  $needToSaveAbandonment = true;
244
  }
245
 
246
+ $helper->prepareAndSendReminder($updatedTemplate, $quote, $abandonment, true);
247
  }
248
  }
249
 
250
  if ($needToSaveAbandonment) {
251
+ $gmtDate = Mage::getModel('core/date')->gmtDate();
252
+ $abandonment->setUpdatedAt($gmtDate);
253
  $abandonment->save();
254
  }
255
  }
256
  }
257
+ }
258
+
259
+ /**
260
+ * Observer to check for abandoned shopping carts
261
+ */
262
+ public function processAbandonedCarts ()
263
+ {
264
+ /* @var $helper Emv_CartAlert_Helper_Data */
265
+ $helper = Mage::helper('abandonment');
266
+ $createdLock = false;
267
+
268
+ // save the current store so that this observer doesn't interfere with any other functions
269
+ $currentStore = Mage::app()->getStore()->getStoreId();
270
+ // !!! it's very important to set a custom error handler in order to remove lock file in case of fatal error
271
+ Mage::helper('emvcore')->setSmartFocusErrorHandler();
272
+
273
+ try {
274
+ // check if another process is being run now
275
+ if (!$helper->checkLockFile()) {
276
+ // create lock file => do not allow several process at the same time
277
+ $helper->createLockFile();
278
+ $createdLock = true;
279
+
280
+ $limit = $helper->getCartLimitForOneRun();
281
+ $activatedTypes = 0;
282
+ if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED) == 1) {
283
+ $activatedTypes++;
284
+ }
285
+ if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED) == 1) {
286
+ $activatedTypes++;
287
+ }
288
+ if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED) == 1) {
289
+ $activatedTypes++;
290
+ }
291
+ $limitPerType = $limit;
292
+ if ($activatedTypes > 0) {
293
+ $limitPerType = (int)$limit / $activatedTypes;
294
+ }
295
+
296
+ foreach($this->_reminderTypes as $type) {
297
+ $this->processAbandonedCartsForType($limitPerType, $type);
298
+ // return the store to normal
299
+ Mage::app()->setCurrentStore($currentStore);
300
+ }
301
+ }
302
+ } catch (Exception $e) {
303
+ Mage::logException($e);
304
+ }
305
+
306
+ // if lock is created, need to delete it
307
+ if ($createdLock) {
308
+ try {
309
+ $helper->removeLockFile();
310
+ } catch (Exception $e) {
311
+ Mage::logException($e);
312
+ }
313
+ }
314
+
315
+ // reset error handler to Magento one
316
+ Mage::helper('emvcore')->resetErrorHandler();
317
 
318
  // return the store to normal
319
  Mage::app()->setCurrentStore($currentStore);
320
  }
321
 
322
+ /**
323
+ * Prepare abandonment object from quote retrieved from last query select
324
+ *
325
+ * @param Varien_Object $quote
326
+ * @return Emv_CartAlert_Model_Abandonment
327
+ */
328
+ protected function _prepareAbandonmentObjectFromQuote(Varien_Object $quote)
329
+ {
330
+ $abandonment = Mage::getModel('abandonment/abandonment');
331
+ $abandonment->setData('abandonment_id', $quote->getData('abandonment_id'));
332
+ $abandonment->setData('entity_id', $quote->getData('abandonment_entity_id'));
333
+ $abandonment->setData('template', $quote->getData('abandonment_template'));
334
+ $abandonment->setData('customer_abandonment_subscribed', $quote->getData('abandonment_customer_abandonment_subscribed'));
335
+ $abandonment->setData('customer_id', $quote->getData('abandonment_customer_id'));
336
+ $abandonment->setData('shopping_cart_rule_id', $quote->getData('abandonment_shopping_cart_rule_id'));
337
+ $abandonment->setData('coupon_code', $quote->getData('abandonment_coupon_code'));
338
+
339
+ return $abandonment;
340
+ }
341
+
342
  /**
343
  * Indicate which reminder template can be used to send.
344
  * Return null if we can't send the reminder else the reminder name
364
 
365
  // expiration date
366
  $expirationDate = $locale->utcDate(null, $now);
367
+ $expirationDate->subHour(Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_LIFETIME));
368
 
369
  if ($expirationDate->isLater($lastUpdate)) {
370
  $updatedTemplate = Emv_CartAlert_Constants::OUTDATED_FLAG;
375
 
376
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_ENABLED, $store)) {
377
  $firstAlertDelay = $locale->utcDate(null, $now);
378
+ if ($this->getTestMode()) {
379
+ $firstAlertDelay->subMinute(
380
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_DELAY, $store)
381
+ );
382
+ } else {
383
+ $firstAlertDelay->subHour(
384
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_FIRST_ALERT_DELAY, $store)
385
+ );
386
+ }
387
  }
388
 
389
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_ENABLED, $store)) {
390
  $secondAlertDelay = $locale->utcDate(null, $now);
391
+ if ($this->getTestMode()) {
392
+ $secondAlertDelay->subMinute(
393
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_DELAY, $store)
394
+ );
395
+ } else {
396
+ $secondAlertDelay->subHour(
397
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_SECOND_ALERT_DELAY, $store)
398
+ );
399
+ }
400
  }
401
 
402
  if (Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_ENABLED, $store)) {
403
  $thirdAlertDelay = $locale->utcDate(null, $now);
404
+ if ($this->getTestMode()) {
405
+ $thirdAlertDelay->subMinute(
406
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_DELAY, $store)
407
+ );
408
+ } else {
409
+ $thirdAlertDelay->subHour(
410
+ Mage::getStoreConfig(Emv_CartAlert_Constants::XML_PATH_THIRD_ALERT_DELAY, $store)
411
+ );
412
+ }
413
  }
414
 
415
  // determine which reminder (first, second, third) needs to be sent
490
  $session->unsetData('abandonment_flag');
491
  $session->unsetData('abandonment_date');
492
  }
493
+
494
+ /**
495
+ * Handle Quote save after event - reset the reminder template for a registered customer
496
+ * so that he can receive a new reminder
497
+ * @param Varien_Event_Observer $observer
498
+ */
499
+ public function handleQuoteSaveAfter(Varien_Event_Observer $observer)
500
+ {
501
+ /* @var $order Mage_Sales_Model_Quote */
502
+ $quote = $observer->getEvent()->getQuote();
503
+ if ($quote instanceof Mage_Sales_Model_Quote) {
504
+ $session = Mage::getSingleton('customer/session');
505
+ // if customer is logged in and he has some products inside cart
506
+ if ($session->isLoggedIn() && $quote->getItemsCount() && $quote->getId()) {
507
+ if (!$session->getData('abandonment_reset_flag')) {
508
+ try {
509
+ Mage::helper('abandonment')->resetReminderForQuote($quote);
510
+ } catch (Exception $e) {
511
+ Mage::logException($e);
512
+ }
513
+ $session->setData('abandonment_reset_flag', 1);
514
+ }
515
+ }
516
+ }
517
+ }
518
  }
app/code/community/Emv/CartAlert/controllers/Adminhtml/AbandonmentController.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abandoned Cart Reminder controller
4
+ *
5
+ * @category Emv
6
+ * @package Emv_CartAlert
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_CartAlert_Adminhtml_AbandonmentController extends Mage_Adminhtml_Controller_Action
11
+ {
12
+ /**
13
+ * Initialise action
14
+ * - load all layout
15
+ * - set active menu SmartFocus
16
+ */
17
+ protected function _initAction()
18
+ {
19
+ $this->loadLayout();
20
+ $this->_setActiveMenu('emailvision/abandonment');
21
+ // Define module dependent translate
22
+ $this->setUsedModuleName('Emv_CartAlert');
23
+ $this->_title(Mage::helper('abandonment')->__('SmartFocus'))
24
+ ->_title(Mage::helper('abandonment')->__('Abandoned Cart Reminders'));
25
+ }
26
+
27
+ /**
28
+ * Check menu access
29
+ *
30
+ * (non-PHPdoc)
31
+ * @see Mage_Adminhtml_Controller_Action::_isAllowed()
32
+ */
33
+ protected function _isAllowed()
34
+ {
35
+ return Mage::getSingleton('admin/session')->isAllowed('emailvision/abandonment/list');
36
+ }
37
+
38
+ /**
39
+ * Abandoned Cart Reminder List
40
+ */
41
+ public function listAction()
42
+ {
43
+ if ($this->getRequest()->getParam('ajax')) {
44
+ $this->_forward('grid');
45
+ return;
46
+ }
47
+
48
+ // save all messages from session
49
+ $this->getLayout()->getMessagesBlock()->setMessages(
50
+ $this->_getSession()->getMessages()
51
+ );
52
+
53
+ $this->_initAction();
54
+ $this->_addContent(
55
+ $this->getLayout()->createBlock('abandonment/adminhtml_list','list')
56
+ );
57
+ $this->renderLayout();
58
+ }
59
+
60
+ /**
61
+ * Abandoned Cart Reminder Grid (for ajax query)
62
+ */
63
+ public function gridAction()
64
+ {
65
+ $this->loadLayout();
66
+ $this->getResponse()->setBody(
67
+ $this->getLayout()->createBlock('abandonment/adminhtml_list_grid')->toHtml()
68
+ );
69
+ }
70
+
71
+ /**
72
+ * Display product information in a given quote
73
+ */
74
+ public function displayQuoteAction()
75
+ {
76
+ $quoteId = $this->getRequest()->getParam('quote');
77
+ if ($quoteId) {
78
+ $collection = Mage::getModel('sales/quote')->getCollection();
79
+ $collection->addFieldToFilter('entity_id', array('in' => array($quoteId)));
80
+ $quote = $collection->getFirstItem();
81
+ if ($quote && $quote->getId()) {
82
+ Mage::register('smartfocus_quote', $quote);
83
+
84
+ // save all messages from session
85
+ $this->getLayout()->getMessagesBlock()->setMessages(
86
+ $this->_getSession()->getMessages()
87
+ );
88
+
89
+ $this->_initAction();
90
+
91
+ $this->_addContent(
92
+ $this->getLayout()->createBlock('abandonment/adminhtml_quote','list')
93
+ );
94
+ $this->renderLayout();
95
+ }
96
+ }
97
+ }
98
+
99
+ /**
100
+ * Test reminder - send a list of abandoned carts with a given reminder (first, second or third)
101
+ */
102
+ public function testReminderAction()
103
+ {
104
+ $quoteIds = $this->getRequest()->getParam('quotes');
105
+ if (!is_array($quoteIds)) {
106
+ $this->_getSession()->addError(Mage::helper('emvcore')->__('Please select something!'));
107
+ } else {
108
+ $template = $this->getRequest()->getParam('template');
109
+ if ($template && in_array($template,
110
+ array(
111
+ Emv_CartAlert_Constants::FIRST_ALERT_FLAG,
112
+ Emv_CartAlert_Constants::SECOND_ALERT_FLAG,
113
+ Emv_CartAlert_Constants::THIRD_ALERT_FLAG
114
+ )
115
+ )
116
+ ) {
117
+ // save the current store so that it doesn't interfere with any other functions
118
+ $currentStore = Mage::app()->getStore()->getStoreId();
119
+
120
+ /* @var $helper Emv_CartAlert_Helper_Data */
121
+ $helper = Mage::helper('abandonment');
122
+ $rule = $helper->getShoppingCartPriceRule();
123
+
124
+ $sent = 0;
125
+ $collection = Mage::getModel('sales/quote')->getCollection();
126
+ $collection->addFieldToFilter('entity_id', array('in' => array($quoteIds)));
127
+ foreach($collection as $quote) {
128
+ // Set the current store
129
+ Mage::app()->setCurrentStore($quote->getStoreId());
130
+
131
+ try {
132
+ $abandonment = Mage::getModel('abandonment/abandonment');
133
+ $abandonment->setShoppingCartRuleId($rule->getId());
134
+ $abandonment->setCouponCode($helper->getCouponCode($rule->getId()));
135
+
136
+ $helper->prepareAndSendReminder($template, $quote, $abandonment, false);
137
+ $sent ++;
138
+ } catch (Exception $e) {
139
+ $this->_getSession()->addError(
140
+ $helper->__(
141
+ 'Cannot send reminder for cart #%s. Reason: %s',
142
+ $quote->getEntityId(), $e->getMessage()
143
+ )
144
+ );
145
+ }
146
+ }
147
+
148
+ // return the store to normal
149
+ Mage::app()->setCurrentStore($currentStore);
150
+
151
+ $reminderLabels = Mage::helper('abandonment')->getReminderLables();
152
+ $label = $template;
153
+ if (isset($reminderLabels[$template])) {
154
+ $label = $reminderLabels[$template];
155
+ }
156
+ if ($sent > 1) {
157
+ $this->_getSession()->addSuccess(
158
+ $helper->__('%s carts were successfully sent with %s', $sent, $label)
159
+ );
160
+ } elseif ($sent == 1) {
161
+ $this->_getSession()->addSuccess(
162
+ $helper->__('One cart was successfully sent with %s', $label)
163
+ );
164
+ }
165
+ }
166
+ }
167
+
168
+ // get back to abandoned cart reminder list
169
+ $this->_redirect('*/*/list');
170
+ }
171
+
172
+ /**
173
+ * Export abandoned cart grid in csv file
174
+ */
175
+ public function exportAbandonedCsvAction()
176
+ {
177
+ $fileName = 'abandoned_carts.csv';
178
+ $content = $this->getLayout()->createBlock('abandonment/adminhtml_list_grid')
179
+ ->getCsvFile();
180
+
181
+ $this->_prepareDownloadResponse($fileName, $content);
182
+ }
183
+
184
+ /**
185
+ * Export abandoned cart grid in excel file (xml)
186
+ */
187
+ public function exportAbandonedExcelAction()
188
+ {
189
+ $fileName = 'abandoned_carts.xml';
190
+ $content = $this->getLayout()->createBlock('abandonment/adminhtml_list_grid')
191
+ ->getExcelFile();
192
+
193
+ $this->_prepareDownloadResponse($fileName, $content);
194
+ }
195
+ }
app/code/community/Emv/CartAlert/etc/adminhtml.xml CHANGED
@@ -1,9 +1,41 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <acl>
4
  <resources>
5
  <admin>
6
  <children>
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  <system>
8
  <children>
9
  <config>
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
+ <menu>
4
+ <!-- EmailVision menu in the back office -->
5
+ <emailvision>
6
+ <children>
7
+ <abandonment translate="title" module="abandonment">
8
+ <title>Abandoned Carts</title>
9
+ <sort_order>50</sort_order>
10
+ <children>
11
+ <list translate="title" module="abandonment">
12
+ <title>List</title>
13
+ <sort_order>10</sort_order>
14
+ <action>abandonment/abandonment/list</action>
15
+ </list>
16
+ </children>
17
+ </abandonment>
18
+ </children>
19
+ </emailvision>
20
+ </menu>
21
+
22
  <acl>
23
  <resources>
24
  <admin>
25
  <children>
26
+ <emailvision>
27
+ <children>
28
+ <abandonment translate="title" module="abandonment">
29
+ <title>Abandonment Carts</title>
30
+ <children>
31
+ <list>
32
+ <title>List</title>
33
+ <sort_order>10</sort_order>
34
+ </list>
35
+ </children>
36
+ </abandonment>
37
+ </children>
38
+ </emailvision>
39
  <system>
40
  <children>
41
  <config>
app/code/community/Emv/CartAlert/etc/config.xml CHANGED
@@ -1,7 +1,7 @@
1
  <config>
2
  <modules>
3
  <Emv_CartAlert>
4
- <version>0.5.2</version>
5
  </Emv_CartAlert>
6
  </modules>
7
  <global>
@@ -46,18 +46,18 @@
46
  <template>
47
  <email>
48
  <abandonment_first_alert_config_template translate="label" module="abandonment">
49
- <label>Abandoned Cart 1</label>
50
- <file>emailvision/abandonment/template1.html</file>
51
  <type>html</type>
52
  </abandonment_first_alert_config_template>
53
  <abandonment_second_alert_config_template translate="label" module="abandonment">
54
- <label>Abandoned Cart 2</label>
55
- <file>emailvision/abandonment/template2.html</file>
56
  <type>html</type>
57
  </abandonment_second_alert_config_template>
58
  <abandonment_third_alert_config_template translate="label" module="abandonment">
59
- <label>Abandoned Cart 3</label>
60
- <file>emailvision/abandonment/template3.html</file>
61
  <type>html</type>
62
  </abandonment_third_alert_config_template>
63
  </email>
@@ -79,14 +79,15 @@
79
  </abandonment>
80
  </observers>
81
  </sales_order_save_after>
 
 
 
 
 
 
 
 
82
  </events>
83
- <layout>
84
- <updates>
85
- <abandonment module="Emv_CartAlert">
86
- <file>emailvision/abandonment.xml</file>
87
- </abandonment>
88
- </updates>
89
- </layout>
90
  </global>
91
  <frontend>
92
  <routers>
@@ -101,7 +102,7 @@
101
  <layout>
102
  <updates>
103
  <abandonment module="Emv_CartAlert">
104
- <file>emailvision/abandonment.xml</file>
105
  </abandonment>
106
  </updates>
107
  </layout>
@@ -141,7 +142,9 @@
141
  <default>
142
  <abandonment>
143
  <general>
 
144
  <image_size>256</image_size>
 
145
  <length>8</length>
146
  <format>Alphanumeric</format>
147
  <dash>4</dash>
@@ -157,4 +160,15 @@
157
  </third_alert_config>
158
  </abandonment>
159
  </default>
 
 
 
 
 
 
 
 
 
 
 
160
  </config>
1
  <config>
2
  <modules>
3
  <Emv_CartAlert>
4
+ <version>0.5.4</version>
5
  </Emv_CartAlert>
6
  </modules>
7
  <global>
46
  <template>
47
  <email>
48
  <abandonment_first_alert_config_template translate="label" module="abandonment">
49
+ <label>SmartFocus Abandoned Cart 1</label>
50
+ <file>smartfocus/abandonment/template1.html</file>
51
  <type>html</type>
52
  </abandonment_first_alert_config_template>
53
  <abandonment_second_alert_config_template translate="label" module="abandonment">
54
+ <label>SmartFocus Abandoned Cart 2</label>
55
+ <file>smartfocus/abandonment/template2.html</file>
56
  <type>html</type>
57
  </abandonment_second_alert_config_template>
58
  <abandonment_third_alert_config_template translate="label" module="abandonment">
59
+ <label>SmartFocus Abandoned Cart 3</label>
60
+ <file>smartfocus/abandonment/template3.html</file>
61
  <type>html</type>
62
  </abandonment_third_alert_config_template>
63
  </email>
79
  </abandonment>
80
  </observers>
81
  </sales_order_save_after>
82
+ <sales_quote_save_after>
83
+ <observers>
84
+ <abandonment>
85
+ <class>abandonment/observer</class>
86
+ <method>handleQuoteSaveAfter</method>
87
+ </abandonment>
88
+ </observers>
89
+ </sales_quote_save_after>
90
  </events>
 
 
 
 
 
 
 
91
  </global>
92
  <frontend>
93
  <routers>
102
  <layout>
103
  <updates>
104
  <abandonment module="Emv_CartAlert">
105
+ <file>smartfocus/abandonment.xml</file>
106
  </abandonment>
107
  </updates>
108
  </layout>
142
  <default>
143
  <abandonment>
144
  <general>
145
+ <lifetime>168</lifetime>
146
  <image_size>256</image_size>
147
+ <limit>500</limit>
148
  <length>8</length>
149
  <format>Alphanumeric</format>
150
  <dash>4</dash>
160
  </third_alert_config>
161
  </abandonment>
162
  </default>
163
+ <admin>
164
+ <routers>
165
+ <abandonment>
166
+ <use>admin</use>
167
+ <args>
168
+ <module>Emv_CartAlert_Adminhtml</module>
169
+ <frontName>abandonment</frontName>
170
+ </args>
171
+ </abandonment>
172
+ </routers>
173
+ </admin>
174
  </config>
app/code/community/Emv/CartAlert/etc/system.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <sections>
4
  <abandonment translate="label" module="abandonment">
5
- <label>Abandonment Cart Alert</label>
6
  <tab>emailvision</tab>
7
  <frontend_type>text</frontend_type>
8
  <sort_order>50</sort_order>
@@ -10,20 +10,54 @@
10
  <show_in_website>1</show_in_website>
11
  <show_in_store>1</show_in_store>
12
  <groups>
 
 
 
 
 
 
 
 
 
13
  <general translate="label" module="abandonment">
14
  <label>General</label>
15
  <expanded>0</expanded>
16
  <frontend_type>text</frontend_type>
17
- <sort_order>0</sort_order>
18
  <show_in_default>1</show_in_default>
19
  <show_in_website>1</show_in_website>
20
  <show_in_store>1</show_in_store>
21
  <fields>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  <email_identity translate="label" module="abandonment">
23
  <label>Email Sender</label>
24
  <frontend_type>select</frontend_type>
25
  <source_model>adminhtml/system_config_source_email_identity</source_model>
26
- <sort_order>1</sort_order>
27
  <show_in_default>1</show_in_default>
28
  <show_in_website>1</show_in_website>
29
  <show_in_store>1</show_in_store>
@@ -31,20 +65,19 @@
31
  <image_size translate="label" module="abandonment">
32
  <label>Image Size</label>
33
  <frontend_type>text</frontend_type>
34
- <sort_order>5</sort_order>
35
  <show_in_default>1</show_in_default>
36
  <show_in_website>1</show_in_website>
37
  <show_in_store>1</show_in_store>
38
  <frontend_class>validate-digits</frontend_class>
39
  </image_size>
40
  <cart_rule translate="label comment" module="abandonment">
41
- <label>Shopping Cart Prices Rule Id</label>
42
- <frontend_type>text</frontend_type>
43
  <sort_order>12</sort_order>
44
  <show_in_default>1</show_in_default>
45
  <show_in_website>1</show_in_website>
46
  <show_in_store>1</show_in_store>
47
- <frontend_class>validate-digits</frontend_class>
48
  </cart_rule>
49
  <length translate="label comment" module="abandonment">
50
  <label>Coupon Code Length</label>
@@ -94,7 +127,7 @@
94
  </fields>
95
  </general>
96
  <first_alert_config translate="label" module="abandonment">
97
- <label>First Alert Configuration</label>
98
  <expanded>0</expanded>
99
  <frontend_type>text</frontend_type>
100
  <sort_order>5</sort_order>
@@ -103,7 +136,7 @@
103
  <show_in_store>1</show_in_store>
104
  <fields>
105
  <enabled translate="label" module="abandonment">
106
- <label>First Email Alert Enable</label>
107
  <frontend_type>select</frontend_type>
108
  <source_model>adminhtml/system_config_source_yesno</source_model>
109
  <sort_order>10</sort_order>
@@ -112,15 +145,16 @@
112
  <show_in_store>1</show_in_store>
113
  </enabled>
114
  <delay translate="label" module="abandonment">
115
- <label>First Email Alert Delay (in hour)</label>
116
  <frontend_type>text</frontend_type>
 
117
  <sort_order>20</sort_order>
118
  <show_in_default>1</show_in_default>
119
  <show_in_website>1</show_in_website>
120
  <show_in_store>1</show_in_store>
121
  </delay>
122
  <template translate="label" module="abandonment">
123
- <label>First Email Alert Template</label>
124
  <frontend_type>select</frontend_type>
125
  <source_model>adminhtml/system_config_source_email_template</source_model>
126
  <sort_order>30</sort_order>
@@ -131,7 +165,7 @@
131
  </fields>
132
  </first_alert_config>
133
  <second_alert_config translate="label" module="abandonment">
134
- <label>Second Alert Configuration</label>
135
  <expanded>0</expanded>
136
  <frontend_type>text</frontend_type>
137
  <sort_order>10</sort_order>
@@ -140,7 +174,7 @@
140
  <show_in_store>1</show_in_store>
141
  <fields>
142
  <enabled translate="label" module="abandonment">
143
- <label>Second Email Alert Enable</label>
144
  <frontend_type>select</frontend_type>
145
  <source_model>adminhtml/system_config_source_yesno</source_model>
146
  <sort_order>10</sort_order>
@@ -149,15 +183,16 @@
149
  <show_in_store>1</show_in_store>
150
  </enabled>
151
  <delay translate="label" module="abandonment">
152
- <label>Second Email Alert Delay (in hour)</label>
153
  <frontend_type>text</frontend_type>
 
154
  <sort_order>20</sort_order>
155
  <show_in_default>1</show_in_default>
156
  <show_in_website>1</show_in_website>
157
  <show_in_store>1</show_in_store>
158
  </delay>
159
  <template translate="label" module="abandonment">
160
- <label>Second Email Template</label>
161
  <frontend_type>select</frontend_type>
162
  <source_model>adminhtml/system_config_source_email_template</source_model>
163
  <sort_order>30</sort_order>
@@ -168,7 +203,7 @@
168
  </fields>
169
  </second_alert_config>
170
  <third_alert_config translate="label" module="abandonment">
171
- <label>Third Alert Configuration</label>
172
  <expanded>0</expanded>
173
  <frontend_type>text</frontend_type>
174
  <sort_order>20</sort_order>
@@ -177,8 +212,9 @@
177
  <show_in_store>1</show_in_store>
178
  <fields>
179
  <enabled translate="label" module="abandonment">
180
- <label>Third Email Alert Enable</label>
181
  <frontend_type>select</frontend_type>
 
182
  <source_model>adminhtml/system_config_source_yesno</source_model>
183
  <sort_order>10</sort_order>
184
  <show_in_default>1</show_in_default>
@@ -186,7 +222,7 @@
186
  <show_in_store>1</show_in_store>
187
  </enabled>
188
  <delay translate="label" module="abandonment">
189
- <label>Third Email Alert Delay (in hour)</label>
190
  <frontend_type>text</frontend_type>
191
  <sort_order>20</sort_order>
192
  <show_in_default>1</show_in_default>
@@ -194,7 +230,7 @@
194
  <show_in_store>1</show_in_store>
195
  </delay>
196
  <template translate="label" module="abandonment">
197
- <label>Third Email Alert Template</label>
198
  <frontend_type>select</frontend_type>
199
  <source_model>adminhtml/system_config_source_email_template</source_model>
200
  <sort_order>30</sort_order>
2
  <config>
3
  <sections>
4
  <abandonment translate="label" module="abandonment">
5
+ <label>Abandoned Cart Reminders</label>
6
  <tab>emailvision</tab>
7
  <frontend_type>text</frontend_type>
8
  <sort_order>50</sort_order>
10
  <show_in_website>1</show_in_website>
11
  <show_in_store>1</show_in_store>
12
  <groups>
13
+ <extension_status translate="label">
14
+ <label>Plugin Status</label>
15
+ <frontend_model>emvcore/adminhtml_config_extensionStatus</frontend_model>
16
+ <sort_order>0</sort_order>
17
+ <frontend_type>text</frontend_type>
18
+ <show_in_default>1</show_in_default>
19
+ <show_in_website>1</show_in_website>
20
+ <show_in_store>1</show_in_store>
21
+ </extension_status>
22
  <general translate="label" module="abandonment">
23
  <label>General</label>
24
  <expanded>0</expanded>
25
  <frontend_type>text</frontend_type>
26
+ <sort_order>1</sort_order>
27
  <show_in_default>1</show_in_default>
28
  <show_in_website>1</show_in_website>
29
  <show_in_store>1</show_in_store>
30
  <fields>
31
+ <test_mode translate="label" module="abandonment">
32
+ <label>Enable test mode (the calculation will be in minutes)</label>
33
+ <source_model>adminhtml/system_config_source_yesno</source_model>
34
+ <frontend_type>select</frontend_type>
35
+ <sort_order>1</sort_order>
36
+ <show_in_default>1</show_in_default>
37
+ <show_in_website>0</show_in_website>
38
+ <show_in_store>0</show_in_store>
39
+ </test_mode>
40
+ <limit translate="label" module="abandonment">
41
+ <label>Maximum Abandoned Carts per One Run</label>
42
+ <frontend_type>text</frontend_type>
43
+ <sort_order>2</sort_order>
44
+ <show_in_default>1</show_in_default>
45
+ <show_in_website>0</show_in_website>
46
+ <show_in_store>0</show_in_store>
47
+ </limit>
48
+ <lifetime translate="label" module="abandonment">
49
+ <label>Cart Lifetime (in hours)</label>
50
+ <frontend_type>text</frontend_type>
51
+ <sort_order>3</sort_order>
52
+ <show_in_default>1</show_in_default>
53
+ <show_in_website>0</show_in_website>
54
+ <show_in_store>0</show_in_store>
55
+ </lifetime>
56
  <email_identity translate="label" module="abandonment">
57
  <label>Email Sender</label>
58
  <frontend_type>select</frontend_type>
59
  <source_model>adminhtml/system_config_source_email_identity</source_model>
60
+ <sort_order>5</sort_order>
61
  <show_in_default>1</show_in_default>
62
  <show_in_website>1</show_in_website>
63
  <show_in_store>1</show_in_store>
65
  <image_size translate="label" module="abandonment">
66
  <label>Image Size</label>
67
  <frontend_type>text</frontend_type>
68
+ <sort_order>8</sort_order>
69
  <show_in_default>1</show_in_default>
70
  <show_in_website>1</show_in_website>
71
  <show_in_store>1</show_in_store>
72
  <frontend_class>validate-digits</frontend_class>
73
  </image_size>
74
  <cart_rule translate="label comment" module="abandonment">
75
+ <label>Shopping Cart Prices Rule</label>
76
+ <frontend_model>abandonment/adminhtml_system_config_promoRule</frontend_model>
77
  <sort_order>12</sort_order>
78
  <show_in_default>1</show_in_default>
79
  <show_in_website>1</show_in_website>
80
  <show_in_store>1</show_in_store>
 
81
  </cart_rule>
82
  <length translate="label comment" module="abandonment">
83
  <label>Coupon Code Length</label>
127
  </fields>
128
  </general>
129
  <first_alert_config translate="label" module="abandonment">
130
+ <label>First Reminder Configuration</label>
131
  <expanded>0</expanded>
132
  <frontend_type>text</frontend_type>
133
  <sort_order>5</sort_order>
136
  <show_in_store>1</show_in_store>
137
  <fields>
138
  <enabled translate="label" module="abandonment">
139
+ <label>First Email Reminder Enable</label>
140
  <frontend_type>select</frontend_type>
141
  <source_model>adminhtml/system_config_source_yesno</source_model>
142
  <sort_order>10</sort_order>
145
  <show_in_store>1</show_in_store>
146
  </enabled>
147
  <delay translate="label" module="abandonment">
148
+ <label>First Email Reminder Delay (in hours)</label>
149
  <frontend_type>text</frontend_type>
150
+ <comment>By default, the calculation will be done in hours. If test mode enabled, it will be in minutes instead.</comment>
151
  <sort_order>20</sort_order>
152
  <show_in_default>1</show_in_default>
153
  <show_in_website>1</show_in_website>
154
  <show_in_store>1</show_in_store>
155
  </delay>
156
  <template translate="label" module="abandonment">
157
+ <label>First Email Reminder Template</label>
158
  <frontend_type>select</frontend_type>
159
  <source_model>adminhtml/system_config_source_email_template</source_model>
160
  <sort_order>30</sort_order>
165
  </fields>
166
  </first_alert_config>
167
  <second_alert_config translate="label" module="abandonment">
168
+ <label>Second Reminder Configuration</label>
169
  <expanded>0</expanded>
170
  <frontend_type>text</frontend_type>
171
  <sort_order>10</sort_order>
174
  <show_in_store>1</show_in_store>
175
  <fields>
176
  <enabled translate="label" module="abandonment">
177
+ <label>Second Email Reminder Enable</label>
178
  <frontend_type>select</frontend_type>
179
  <source_model>adminhtml/system_config_source_yesno</source_model>
180
  <sort_order>10</sort_order>
183
  <show_in_store>1</show_in_store>
184
  </enabled>
185
  <delay translate="label" module="abandonment">
186
+ <label>Second Email Reminder Delay (in hours)</label>
187
  <frontend_type>text</frontend_type>
188
+ <comment>By default, the calculation will be done in hours. If test mode enabled, it will be in minutes instead.</comment>
189
  <sort_order>20</sort_order>
190
  <show_in_default>1</show_in_default>
191
  <show_in_website>1</show_in_website>
192
  <show_in_store>1</show_in_store>
193
  </delay>
194
  <template translate="label" module="abandonment">
195
+ <label>Second Email Reminder Template</label>
196
  <frontend_type>select</frontend_type>
197
  <source_model>adminhtml/system_config_source_email_template</source_model>
198
  <sort_order>30</sort_order>
203
  </fields>
204
  </second_alert_config>
205
  <third_alert_config translate="label" module="abandonment">
206
+ <label>Third Reminder Configuration</label>
207
  <expanded>0</expanded>
208
  <frontend_type>text</frontend_type>
209
  <sort_order>20</sort_order>
212
  <show_in_store>1</show_in_store>
213
  <fields>
214
  <enabled translate="label" module="abandonment">
215
+ <label>Third Email Reminder Enable</label>
216
  <frontend_type>select</frontend_type>
217
+ <comment>By default, the calculation will be done in hours. If test mode enabled, it will be in minutes instead.</comment>
218
  <source_model>adminhtml/system_config_source_yesno</source_model>
219
  <sort_order>10</sort_order>
220
  <show_in_default>1</show_in_default>
222
  <show_in_store>1</show_in_store>
223
  </enabled>
224
  <delay translate="label" module="abandonment">
225
+ <label>Third Email Reminder Delay (in hours)</label>
226
  <frontend_type>text</frontend_type>
227
  <sort_order>20</sort_order>
228
  <show_in_default>1</show_in_default>
230
  <show_in_store>1</show_in_store>
231
  </delay>
232
  <template translate="label" module="abandonment">
233
+ <label>Third Email Reminder Template</label>
234
  <frontend_type>select</frontend_type>
235
  <source_model>adminhtml/system_config_source_email_template</source_model>
236
  <sort_order>30</sort_order>
app/code/community/Emv/CartAlert/sql/abandonment_setup/mysql4-upgrade-0.5.2-0.5.3.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Emv_CartAlert_Model_Resource_Setup */
3
+
4
+ $this->startSetup();
5
+
6
+ $this->getConnection()
7
+ ->addColumn($this->getTable('abandonment/abandonment'), 'updated_at', 'DATETIME NULL');
8
+
9
+ $gmtDate = Mage::getModel('core/date')->gmtDate();
10
+ // update the existing abandonments
11
+ $sql = "UPDATE {$this->getTable('abandonment/abandonment')} AS aband"
12
+ . " SET aband.updated_at = '{$gmtDate}'";
13
+ $this->run($sql);
14
+
15
+ $this->endSetup();
app/code/community/Emv/CartAlert/sql/abandonment_setup/mysql4-upgrade-0.5.3-0.5.4.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Emv_CartAlert_Model_Resource_Setup */
3
+
4
+ $this->startSetup();
5
+
6
+ $this->run("
7
+ ALTER TABLE {$this->getTable('abandonment')}
8
+ MODIFY COLUMN entity_id INT(10) NOT NULL,
9
+
10
+ ADD INDEX `IDX_ABANDONMENT_ENTITY_ID` (`entity_id`),
11
+ ADD INDEX `IDX_ABANDONMENT_TEMPLATE` (`template`)
12
+ ");
13
+
14
+ $this->run("
15
+ ALTER TABLE {$this->getTable('abandonment/stats')}
16
+ ADD INDEX `IDX_ABANDONMENT_STAT_REMINDER_ID` (`reminder_id`),
17
+ ADD INDEX `IDX_ABANDONMENT_STAT_QUOTE_ID` (`quote_id`)
18
+ ");
19
+
20
+ $this->run("
21
+ ALTER TABLE {$this->getTable('abandonment/order_flag')}
22
+ ADD INDEX `IDX_ABANDONMENT_ORDER_FLAG_ENTITY_ID` (`entity_id`),
23
+ ADD INDEX `IDX_ABANDONMENT_ORDER_FLAG_FLAG` (`flag`)
24
+ ");
25
+ $this->endSetup();
app/code/community/Emv/Core/Block/Adminhtml/Account/Edit/AssociatedUrls.php CHANGED
@@ -19,7 +19,7 @@ class Emv_Core_Block_Adminhtml_Account_Edit_AssociatedUrls extends Mage_Adminhtm
19
  */
20
  public function __construct()
21
  {
22
- $this->setTemplate('emailvision/account/associated_urls.phtml');
23
  }
24
 
25
  /**
19
  */
20
  public function __construct()
21
  {
22
+ $this->setTemplate('smartfocus/account/associated_urls.phtml');
23
  }
24
 
25
  /**
app/code/community/Emv/Core/Block/Adminhtml/Config/ExtensionStatus.php ADDED
@@ -0,0 +1,434 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Extension status block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Block_Adminhtml_Config_ExtensionStatus
11
+ extends Mage_Adminhtml_Block_Abstract
12
+ implements Varien_Data_Form_Element_Renderer_Interface
13
+ {
14
+ const BASE_EXTENSION_DIR = 'Emv';
15
+ const BASE_CODE_POOL = 'community';
16
+
17
+ /**
18
+ * Custom template
19
+ *
20
+ * @var string
21
+ */
22
+ protected $_template = 'smartfocus/config/extension_status.phtml';
23
+
24
+ /**
25
+ * Help Link Url
26
+ * @var string
27
+ */
28
+ protected $_helpLink = '';
29
+
30
+ /**
31
+ * PHP minimum version
32
+ *
33
+ * @var string
34
+ */
35
+ protected $_minPhpVersion = '5.2.6';
36
+
37
+ /**
38
+ * List of call back functions to test
39
+ * @var array
40
+ */
41
+ protected $_callbackList = array();
42
+
43
+ /**
44
+ * By default, we require soap, openssl, and curl extensions
45
+ *
46
+ * @var array
47
+ */
48
+ protected $_defaultRequired = array('soap', 'openssl', 'curl');
49
+
50
+ /**
51
+ * You can include more PHP extensions by modifying this array
52
+ *
53
+ * @var array
54
+ */
55
+ protected $_required = array();
56
+
57
+ /**
58
+ * Minimum of memory size in MB
59
+ *
60
+ * @var int
61
+ */
62
+ protected $_minMemory = 512;
63
+
64
+ /**
65
+ * Allowed time difference in Hours
66
+ *
67
+ * @var int
68
+ */
69
+ protected $_allowedTimeDiffJob = 1;
70
+
71
+ /**
72
+ * Render fieldset html
73
+ *
74
+ * @param Varien_Data_Form_Element_Abstract $fieldset
75
+ * @return string
76
+ */
77
+ public function render(Varien_Data_Form_Element_Abstract $fieldset)
78
+ {
79
+ return $this->toHtml();
80
+ }
81
+
82
+ /**
83
+ * @return string
84
+ */
85
+ protected function _getTickImageLink() {
86
+ return sprintf('<img src="%s" width="11" height="11" />',$this->getSkinUrl('images/smartfocus/tick.png'));
87
+ }
88
+
89
+ /**
90
+ * @return string
91
+ */
92
+ protected function _getUnTickImageLink() {
93
+ return sprintf('<img src="%s" width="11" height="11" />',$this->getSkinUrl('images/smartfocus/untick.gif'));
94
+ }
95
+
96
+ /**
97
+ * @return string
98
+ */
99
+ protected function _getWarningTickImageLink() {
100
+ return sprintf('<img src="%s" width="18" height="18" />',$this->getSkinUrl('images/smartfocus/warning.png'));
101
+ }
102
+
103
+ /**
104
+ * Get status of all installed Emv Modules
105
+ * @return string
106
+ */
107
+ public function getEmvModulesVersionStatus()
108
+ {
109
+ $namespacePath = mage::getBaseDir('base') . DS . 'app' . DS . 'code'
110
+ . DS . self::BASE_CODE_POOL . DS . self::BASE_EXTENSION_DIR . DS;
111
+
112
+ $message = '';
113
+ $namespaceDir = @opendir($namespacePath);
114
+ $moduleVersion = array();
115
+ while ($subModule = readdir($namespaceDir)) {
116
+ if ($this->_directoryIsValid($subModule)) {
117
+ //parse modules within namespace
118
+ $modulePath = $namespacePath . $subModule . DS;
119
+ if (is_dir($modulePath)) {
120
+ $configXmlPath = $modulePath . 'etc/config.xml';
121
+ if (file_exists($configXmlPath)) {
122
+ $config = new Varien_Simplexml_Config();
123
+ $config->loadFile($configXmlPath);
124
+ $path = $config->getNode('modules');
125
+ foreach ($path->asArray() as $subModuleName => $version) {
126
+ $moduleVersion[] = $subModuleName . ' : ' . $version['version'];
127
+ }
128
+ }
129
+ }
130
+ }
131
+ }
132
+ closedir($namespaceDir);
133
+
134
+ $message = Mage::helper('emvcore')->__(
135
+ '<span class="icon-status">%s</span> List of installed modules <strong>%s</strong>.',
136
+ $this->_getWarningTickImageLink(),
137
+ implode(', ', $moduleVersion)
138
+ );
139
+
140
+ return $message;
141
+ }
142
+
143
+ /**
144
+ * Check if directory name is valid
145
+ *
146
+ * @param string $dirName
147
+ * @return boolean
148
+ */
149
+ private function _directoryIsValid($dirName) {
150
+ switch ($dirName) {
151
+ case '.':
152
+ case '..':
153
+ case '.DS_Store':
154
+ case '':
155
+ return false;
156
+ break;
157
+ default:
158
+ return true;
159
+ break;
160
+ }
161
+ }
162
+
163
+
164
+ /**
165
+ * Get directory permission status
166
+ *
167
+ * @return string
168
+ */
169
+ public function getDirectoryPermissionStatus()
170
+ {
171
+ $ok = true;
172
+ try {
173
+ $mageFile = new Varien_Io_File();
174
+ $mageFile->checkAndCreateFolder(Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER));
175
+ $mageFile->checkAndCreateFolder(
176
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
177
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
178
+ );
179
+ } catch (Exception $e) {
180
+ $ok = false;
181
+ }
182
+
183
+ $message = '';
184
+ if ($ok) {
185
+ $image = $this->_getTickImageLink();
186
+ $message = Mage::helper('emvcore')->__(
187
+ '<span class="icon-status">%s</span> Write permission is correctly set to <strong>%s</strong>.',
188
+ $image,
189
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
190
+ );
191
+ } else {
192
+ $image = $this->_getUnTickImageLink();
193
+ $message = Mage::helper('emvcore')->__(
194
+ '<span class="icon-status">%s</span> Write permission is not correctly set to <strong>%s</strong>.',
195
+ $image,
196
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
197
+ );
198
+ }
199
+ return $message;
200
+ }
201
+
202
+ /**
203
+ * Get other test list (callable functions)
204
+ *
205
+ * @return array
206
+ */
207
+ public function getOtherTestList()
208
+ {
209
+ return $this->_callbackList;
210
+ }
211
+
212
+ /**
213
+ * Get status for a given test
214
+ *
215
+ * @param $testToHandle
216
+ * @return string / boolean - false
217
+ */
218
+ public function getStatusForTest($testToHandle)
219
+ {
220
+ $status = '';
221
+ if (method_exists($this, $testToHandle)) {
222
+ $status = call_user_func(array($this,$testToHandle));
223
+ }
224
+ return $status;
225
+ }
226
+
227
+ /**
228
+ * @return string
229
+ */
230
+ public function getHelpLink()
231
+ {
232
+ return $this->_helpLink;
233
+ }
234
+
235
+ /**
236
+ * Get extension version
237
+ *
238
+ * @return string
239
+ */
240
+ public function getExtensionVersion()
241
+ {
242
+ return Mage::helper('emvcore')->__("SmartFocus Connector Status (Version %s)", Emv_Core_Helper_Data::getVersion());
243
+ }
244
+
245
+ /**
246
+ * @return string
247
+ */
248
+ public function getMagentoVersionStatus()
249
+ {
250
+ $magentoLabel = '';
251
+ if (method_exists('Mage', "getEdition")) {
252
+ $magentoLabel = Mage::getEdition() . ' ';
253
+ }
254
+ $magentoLabel .= Mage::getVersion();
255
+ return Mage::helper('emvcore')->__(
256
+ '<span class="icon-status">%s</span> Your Magento version is <strong>%s</strong>.',
257
+ $this->_getTickImageLink(),
258
+ $magentoLabel
259
+ );
260
+ }
261
+
262
+ /**
263
+ * Check and get PHP environment status
264
+ *
265
+ * @return string
266
+ */
267
+ public function getPhpEnvironmentStatus()
268
+ {
269
+ $ok = true;
270
+
271
+ if (!version_compare(PHP_VERSION, $this->_minPhpVersion, ">=")) {
272
+ $phpCheck = Mage::helper('emvcore')->__(
273
+ 'Required PHP version is <strong>%s</strong> - current version <strong>%s</strong>.',
274
+ $this->_minPhpVersion,
275
+ PHP_VERSION
276
+ );
277
+ $ok = false;
278
+ } else {
279
+ $phpCheck = Mage::helper('emvcore')->__('Your PHP version (<strong>%s</strong>) is satisfied.', PHP_VERSION);
280
+ }
281
+
282
+ $required = array_merge($this->_defaultRequired, $this->_required);
283
+ $missing = array();
284
+ $loaded = array();
285
+ /*
286
+ * Run through PHP extensions to see if they are loaded
287
+ * if no, add them to the list of missing
288
+ */
289
+ foreach ($required as $extName) {
290
+ if (!extension_loaded($extName)) {
291
+ $missing[] = $extName;
292
+ }
293
+ }
294
+
295
+ if (count($missing)) {
296
+ $ok = false;
297
+ $extensionCheck = Mage::helper('emvcore')->__(
298
+ 'Required Php Extensions are <strong>%s</strong>.',
299
+ implode(', ', $required)
300
+ );
301
+ $extensionCheck .= ' ' . Mage::helper('emvcore')->__(
302
+ 'The followings are missing : <strong>%s</strong>.',
303
+ implode(', ', $missing)
304
+ );
305
+ } else {
306
+ $extensionCheck = Mage::helper('emvcore')->__(
307
+ 'All the required Php Extensions (<strong>%s</strong>) are correctly installed.',
308
+ implode(', ', $required)
309
+ );
310
+ }
311
+
312
+ if ($ok) {
313
+ $image = $this->_getTickImageLink();
314
+ } else {
315
+ $image = $this->_getUnTickImageLink();
316
+ }
317
+
318
+ return Mage::helper('emvcore')->__(
319
+ '<span class="icon-status">%s</span> %s',
320
+ $image,
321
+ $phpCheck . ' ' . $extensionCheck
322
+ );
323
+ }
324
+
325
+ /**
326
+ * Check and get Cron status
327
+ *
328
+ * @return string
329
+ */
330
+ public function getCronStatus()
331
+ {
332
+ // get the last job with status pending or running
333
+ $lastJob = Mage::getModel('cron/schedule')->getCollection()
334
+ ->addFieldToFilter('status', array(
335
+ 'in' => array(
336
+ Mage_Cron_Model_Schedule::STATUS_PENDING,
337
+ Mage_Cron_Model_Schedule::STATUS_RUNNING,
338
+ )
339
+ )
340
+ )
341
+ ->setOrder('scheduled_at', Varien_Data_Collection_Db::SORT_ORDER_DESC)
342
+ ->setPageSize(1)
343
+ ->getFirstItem();
344
+
345
+ // check if last job has been scheduled within allowed interval
346
+ $ok = true;
347
+ if ($lastJob && $lastJob->getId()) {
348
+ $locale = Mage::app()->getLocale();
349
+
350
+ $scheduledAt = $locale->date($lastJob->getScheduledAt(), Varien_Date::DATETIME_INTERNAL_FORMAT);
351
+ $scheduledAt = $locale->utcDate(null, $scheduledAt);
352
+
353
+ // now
354
+ $now = $locale->date(null, Varien_Date::DATETIME_INTERNAL_FORMAT);
355
+ $now = $locale->utcDate(null, $now);
356
+
357
+ // if last job was scheduled before the current time
358
+ if ($now->isLater($scheduledAt)) {
359
+ $allowedTime = $now->subHour($this->_allowedTimeDiffJob);
360
+ if ($allowedTime->isLater($scheduledAt)) {
361
+ $ok = false;
362
+ }
363
+ }
364
+ } else {
365
+ $ok = false;
366
+ }
367
+
368
+ $message = '';
369
+ if ($ok) {
370
+ $image = $this->_getTickImageLink();
371
+ $message = Mage::helper('emvcore')->__(
372
+ '<span class="icon-status">%s</span> Magento Cron Process has been correctly configured!',
373
+ $image
374
+ );
375
+ } else {
376
+ $image = $this->_getUnTickImageLink();
377
+ $message = Mage::helper('emvcore')->__(
378
+ '<span class="icon-status">%s</span> Magento Cron Process has not been correctly activated!',
379
+ $image
380
+ );
381
+ }
382
+
383
+ return $message;
384
+ }
385
+
386
+ /**
387
+ * Check and get memory status
388
+ *
389
+ * @return string
390
+ */
391
+ public function getMemoryStatus()
392
+ {
393
+ $memoryLimit = trim(strtoupper(ini_get('memory_limit')));
394
+
395
+ $ok = true;
396
+ if ($memoryLimit != -1) {
397
+ $memoryLimitInBytes = $memoryLimit;
398
+ if (substr($memoryLimit, -1) == 'K') {
399
+ $memoryLimitInBytes = substr($memoryLimit, 0, -1) * 1024;
400
+ }
401
+ if (substr($memoryLimit, -1) == 'M') {
402
+ $memoryLimitInBytes = substr($memoryLimit, 0, -1) * 1024 * 1024;
403
+ }
404
+ if (substr($memoryLimit, -1) == 'G') {
405
+ $memoryLimitInBytes = substr($memoryLimit, 0, -1) * 1024 * 1024 * 1024;
406
+ }
407
+
408
+ $allowedLimit = $this->_minMemory * 1024 * 1024;
409
+ if ($memoryLimitInBytes < $allowedLimit) {
410
+ $ok = false;
411
+ }
412
+ }
413
+
414
+ $message = '';
415
+ if ($ok) {
416
+ $image = $this->_getTickImageLink();
417
+ $message = Mage::helper('emvcore')->__(
418
+ '<span class="icon-status">%s</span> memory_limit is set to <strong>%s</strong>.',
419
+ $image,
420
+ $memoryLimit
421
+ );
422
+ } else {
423
+ $image = $this->_getWarningTickImageLink();
424
+ $message = Mage::helper('emvcore')->__(
425
+ '<span class="icon-status">%s</span> memory_limit should be set to at least <strong>%s M</strong> (currently %s).',
426
+ $image,
427
+ $this->_minMemory,
428
+ $memoryLimit
429
+ );
430
+ }
431
+ return $message;
432
+ }
433
+
434
+ }
app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process.php ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Data Processing Process Grid Container
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Block_Adminhtml_DataProcessing_Process extends Mage_Adminhtml_Block_Widget_Grid_Container
11
+ {
12
+ /**
13
+ * Construct data process menu
14
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::__construct()
15
+ */
16
+ public function __construct()
17
+ {
18
+ parent::__construct();
19
+ $this->_blockGroup = 'emvcore';
20
+ $this->_controller = 'adminhtml_dataProcessing_process';
21
+ $this->_headerText = Mage::helper('emvcore')->__('SmartFocus Data Process List');
22
+ $this->_removeButton('add');
23
+
24
+ }
25
+ }
app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Data Processing Process Grid
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Block_Adminhtml_DataProcessing_Process_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
+ {
12
+ /**
13
+ * Constructor
14
+ *
15
+ * Set main configuration of grid
16
+ */
17
+ public function __construct()
18
+ {
19
+ parent::__construct();
20
+ $this->setId('dataProcessingGrid');
21
+ $this->setUseAjax(true);
22
+ $this->setDefaultSort('id', 'desc');
23
+ }
24
+
25
+ /**
26
+ * Prepare collection for grid
27
+ *
28
+ * @return Mage_Adminhtml_Block_Widget_Grid
29
+ */
30
+ protected function _prepareCollection()
31
+ {
32
+ $collection = Mage::getResourceSingleton('emvcore/dataProcessing_process_collection');
33
+ $this->setCollection($collection);
34
+
35
+ return parent::_prepareCollection();
36
+ }
37
+
38
+ /**
39
+ * Define grid columns
40
+ *
41
+ * @return void
42
+ */
43
+ protected function _prepareColumns()
44
+ {
45
+ $this->addColumn('id', array(
46
+ 'header' => Mage::helper('newsletter')->__('ID'),
47
+ 'index' => 'id',
48
+ 'width' => '40',
49
+ ));
50
+
51
+ $this->addColumn('type', array(
52
+ 'header' => Mage::helper('newsletter')->__('Type'),
53
+ 'index' => 'type',
54
+ 'type' => 'options',
55
+ 'options' => array(
56
+ Emv_Core_Model_DataProcessing_Process::TYPE_DATA_SYNC => Mage::helper('emvcore')->__('Data Sync')
57
+ )
58
+ ));
59
+
60
+ $this->addColumn('title', array(
61
+ 'header' => Mage::helper('emvcore')->__('Title'),
62
+ 'index' => 'title'
63
+ ));
64
+
65
+ $this->addColumn('state', array(
66
+ 'header' => Mage::helper('emvcore')->__('State'),
67
+ 'index' => 'state',
68
+ 'width' => '80px',
69
+ 'type' => 'options',
70
+ 'options' => array(
71
+ Emv_Core_Model_DataProcessing_Process::STATE_NEW => Mage::helper('emvcore')->__('New'),
72
+ Emv_Core_Model_DataProcessing_Process::STATE_PROCESSING => Mage::helper('emvcore')->__('Processing'),
73
+ Emv_Core_Model_DataProcessing_Process::STATE_FAILED => Mage::helper('emvcore')->__('Failed'),
74
+ Emv_Core_Model_DataProcessing_Process::STATE_SUCCESS => Mage::helper('emvcore')->__('Success'),
75
+ )
76
+ ));
77
+
78
+ $this->addColumn('status', array(
79
+ 'header' => Mage::helper('emvcore')->__('Status (%)'),
80
+ 'index' => 'status',
81
+ 'width' => '40px',
82
+ ));
83
+
84
+ $this->addColumn('created_at', array(
85
+ 'header' => Mage::helper('reports')->__('Created At'),
86
+ 'type' => 'datetime',
87
+ 'align' => 'center',
88
+ 'index' => 'created_at',
89
+ ));
90
+ $this->addColumn('updated_at', array(
91
+ 'header' => Mage::helper('reports')->__('Updated At'),
92
+ 'type' => 'datetime',
93
+ 'align' => 'center',
94
+ 'index' => 'updated_at',
95
+ ));
96
+ $this->addColumn('terminated_at', array(
97
+ 'header' => Mage::helper('emvcore')->__('Terminated At'),
98
+ 'type' => 'datetime',
99
+ 'align' => 'center',
100
+ 'index' => 'terminated_at',
101
+ ));
102
+
103
+ $this->addColumn('output', array(
104
+ 'index' => 'output_information',
105
+ 'filter' => false,
106
+ 'sortable' => false,
107
+ 'renderer' => 'emvcore/adminhtml_dataProcessing_process_grid_column_renderer_output',
108
+ 'header' => Mage::helper('emvcore')->__('Output'),
109
+ ));
110
+
111
+ $this->addColumn(
112
+ 'links',
113
+ array(
114
+ 'header' => Mage::helper('emvcore')->__('Action'),
115
+ 'type' => 'text',
116
+ 'width' => '100px',
117
+ 'filter' => false,
118
+ 'sortable' => false,
119
+ 'renderer' => 'emvcore/adminhtml_dataProcessing_process_grid_column_renderer_links'
120
+ )
121
+ );
122
+
123
+ return parent::_prepareColumns();
124
+ }
125
+
126
+ /**
127
+ * Prepare mass action for grid
128
+ *
129
+ * (non-PHPdoc)
130
+ * @see Mage_Adminhtml_Block_Newsletter_Subscriber_Grid::_prepareMassaction()
131
+ */
132
+ protected function _prepareMassaction()
133
+ {
134
+ $this->setMassactionIdField('id');
135
+ $this->getMassactionBlock()->setFormFieldName('ids');
136
+
137
+ $this->getMassactionBlock()->addItem('remove_queue', array(
138
+ 'label' => Mage::helper('newsletter')->__('Delete'),
139
+ 'url' => $this->getUrl('*/*/massDelete'),
140
+ 'confirm' => $this->__('Are you sure?')
141
+ )
142
+ );
143
+
144
+ return $this;
145
+ }
146
+
147
+ /**
148
+ * Get row class - determine the row class according to state information
149
+ *
150
+ * @param Varien_Object $emvEmt
151
+ * @return string
152
+ */
153
+ public function getRowClass(Varien_Object $row)
154
+ {
155
+ $class = "";
156
+ if ($row->getData('state') == Emv_Core_Model_DataProcessing_Process::STATE_FAILED) {
157
+ $class= "invalid";
158
+ }
159
+ if ($row->getData('state') == Emv_Core_Model_DataProcessing_Process::STATE_PROCESSING) {
160
+ $class= "on-progress";
161
+ }
162
+ return $class;
163
+ }
164
+ }
app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid/Column/Renderer/Links.php ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Links renderer
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Block_Adminhtml_DataProcessing_Process_Grid_Column_Renderer_Links
11
+ extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
12
+ {
13
+ /**
14
+ * Render a link to the log/report/exception files
15
+ *
16
+ * @param Varien_Object $row
17
+ *
18
+ * @return string
19
+ */
20
+ public function render(Varien_Object $row)
21
+ {
22
+ if (!$row instanceof Emv_Core_Model_DataProcessing_Process) {
23
+ return '';
24
+ }
25
+
26
+ $output = '';
27
+ if ($row->checkLogData()) {
28
+ $url = Mage::helper('emvcore')->getLogUrlForProcess($row);
29
+ $output .= sprintf('<a href="%s">%s</a>', $url, $this->helper('emvcore')->__('View Log'));
30
+ }
31
+ return $output;
32
+ }
33
+ }
app/code/community/Emv/Core/Block/Adminhtml/DataProcessing/Process/Grid/Column/Renderer/Output.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Input / output information renderer
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Block_Adminhtml_DataProcessing_Process_Grid_Column_Renderer_Output
11
+ extends Mage_Adminhtml_Block_Widget_Grid_Column_Renderer_Abstract
12
+ {
13
+ /**
14
+ * Retrieve an URL for 'file' function
15
+ *
16
+ * @param array $params
17
+ *
18
+ * @return string
19
+ */
20
+ protected function _getFileDownloadUrl($params)
21
+ {
22
+ return $this->getUrl('*/*/getOutputFile', $params);
23
+ }
24
+
25
+ /**
26
+ * Render a input / output text
27
+ *
28
+ * @param Varien_Object $row
29
+ *
30
+ * @return string
31
+ */
32
+ public function render(Varien_Object $row)
33
+ {
34
+ $index = $this->getColumn()->getIndex();
35
+ $data = $row->getData($index);
36
+
37
+ $label = '';
38
+ if ($data) {
39
+ $data = unserialize($data);
40
+ if (is_array($data) && count($data)) {
41
+ foreach ($data as $output) {
42
+ if (is_readable($output['path'])) {
43
+ $params = array('path' => base64_encode($output['path']),
44
+ 'filename' => base64_encode($output['filename'])
45
+ );
46
+ $downloadUrl = $this->getUrl('*/*/getOutputFile', $params);
47
+
48
+ $label .= '<a href="'.$downloadUrl.'" title="'.htmlentities($output['label']).'">'
49
+ .htmlentities($output['label']).'</a>' . '<br/>';
50
+ } else {
51
+ $label .= htmlentities($output['label']) . '<br/>';
52
+ }
53
+ }
54
+ }
55
+ }
56
+
57
+ return $label;
58
+ }
59
+ }
app/code/community/Emv/Core/Helper/Data.php CHANGED
@@ -9,12 +9,65 @@
9
  */
10
  class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * List of accounts
14
  * @var array
15
  */
16
  protected $_accountList = array();
17
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
18
  /**
19
  * Get account for a given id
20
  *
@@ -40,7 +93,8 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
40
  */
41
  public static function getLockPathDir()
42
  {
43
- return Mage::getBaseDir('export') . DS . 'emailvision' . DS . 'locks';
 
44
  }
45
 
46
  /**
@@ -60,7 +114,7 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
60
  }
61
 
62
  /**
63
- * Create a lock file
64
  *
65
  * @param string $content
66
  * @return number | boolean - false
@@ -68,25 +122,50 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
68
  public function createLockFile($fileName, $content = '')
69
  {
70
  if (!$content) {
71
- $content = Mage::getModel('core/date')->date('Y-m-d H:i:s');
 
 
 
 
 
 
 
 
 
72
  }
 
 
73
 
74
- return $this->_getLockHandler()->write($fileName, $content);
 
 
 
 
 
 
 
 
 
75
  }
76
 
77
  /**
78
- * Remove a lock file
79
  *
80
  * @param string $fileName
81
  * @return boolean
82
  */
83
  public function removeLockFile($fileName)
84
  {
85
- return $this->_getLockHandler()->rm($fileName);
 
 
 
 
86
  }
87
 
88
  /**
89
  * Check if lock file exists
 
90
  * @param string $fileName
91
  * @return boolean
92
  */
@@ -95,6 +174,33 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
95
  return $this->_getLockHandler()->fileExists($fileName, true);
96
  }
97
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
98
  /**
99
  * @param string $path
100
  * @param mixed $store
@@ -110,23 +216,46 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
110
  return $website->getConfig($path);
111
  }
112
 
113
- $action = Mage::app()->getFrontController()->getAction();
114
- if ($action instanceOf Mage_Adminhtml_System_ConfigController) {
115
- if ($storeCode = Mage::app()->getRequest()->getParam('store')) {
116
- $store = Mage::app()->getStore($storeCode);
117
- return $store->getConfig($path);
118
- } elseif ($websiteCode = Mage::app()->getRequest()->getParam('website')){
119
- $website = Mage::app()->getWebsite($websiteCode);
120
- return $website->getConfig($path);
121
- } else if ($groupCode = Mage::app()->getRequest()->getParam('group')){
122
- $website = Mage::app()->getGroup($groupCode)->getWebsite();
123
- return $website->getConfig($path);
124
- }
125
  }
126
 
127
  return Mage::getStoreConfig($path);
128
  }
129
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
130
  /**
131
  * Format number in a given locale
132
  *
@@ -153,4 +282,38 @@ class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
153
  return $number;
154
  }
155
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
156
  }
9
  */
10
  class Emv_Core_Helper_Data extends Mage_Core_Helper_Abstract
11
  {
12
+ /**
13
+ * Gets the detailed Extension version information
14
+ *
15
+ * @return array
16
+ */
17
+ public static function getVersionInfo()
18
+ {
19
+ return array(
20
+ 'major' => '3',
21
+ 'minor' => '1',
22
+ 'revision' => '0',
23
+ 'patch' => '',
24
+ 'stability' => '',
25
+ 'number' => '',
26
+ );
27
+ }
28
+
29
+ /**
30
+ * Gets the current Extension version string
31
+ *
32
+ * @return string
33
+ */
34
+ public static function getVersion()
35
+ {
36
+ $i = self::getVersionInfo();
37
+ return trim("{$i['major']}.{$i['minor']}.{$i['revision']}" . ($i['patch'] != '' ? ".{$i['patch']}" : "")
38
+ . "-{$i['stability']}{$i['number']}", '.-');
39
+ }
40
+
41
+ /**
42
+ * Different constant relative to working directory path
43
+ */
44
+ const BASE_CONTAINER = 'export';
45
+ const BASE_WORKING_DIR = 'emailvision';
46
+ const UPLOADED_FILE_DIR = 'uploaded';
47
+ const TEMPORARY_DIR = 'tmp';
48
+ const LOCK_DIR = 'locks';
49
+
50
  /**
51
  * List of accounts
52
  * @var array
53
  */
54
  protected $_accountList = array();
55
 
56
+ /**
57
+ * Custom error handler
58
+ */
59
+ const CUSTOM_ERROR_HANDLER = 'smartFocusErrorHandler';
60
+
61
+ /**
62
+ * Custom shutdown handler
63
+ */
64
+ const CUSTOM_SHUTDOWN_HANDLER = 'smartFocusShutDownPhpHandler';
65
+
66
+ /**
67
+ * Lock file registry name
68
+ */
69
+ const CREATED_LOCK_FILE_REGISTRY = 'smartfocus_lock_file';
70
+
71
  /**
72
  * Get account for a given id
73
  *
93
  */
94
  public static function getLockPathDir()
95
  {
96
+ return Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
97
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR . DS . Emv_Core_Helper_Data::LOCK_DIR;
98
  }
99
 
100
  /**
114
  }
115
 
116
  /**
117
+ * Create a lock file. Your created lock file path can be found in Emv_Core_Helper_Data::CREATED_LOCK_FILE_REGISTRY
118
  *
119
  * @param string $content
120
  * @return number | boolean - false
122
  public function createLockFile($fileName, $content = '')
123
  {
124
  if (!$content) {
125
+ $content = Mage::getModel('core/date')->gmtDate('Y-m-d H:i:s');
126
+ }
127
+
128
+ $sucess = $this->_getLockHandler()->write($fileName, $content);
129
+ if ($sucess) {
130
+ $fullpathFileName = self::getLockPathDir() . DS . $fileName;
131
+ // register the created file name in order to remove after
132
+ Mage::register(self::CREATED_LOCK_FILE_REGISTRY, $fullpathFileName);
133
+ } else {
134
+ Mage::unregister(self::CREATED_LOCK_FILE_REGISTRY);
135
  }
136
+ return $sucess;
137
+ }
138
 
139
+ /**
140
+ * Remove the last lock file from registry
141
+ */
142
+ public function removeLastLockFileFromRegistry()
143
+ {
144
+ $fullPath = Mage::registry(Emv_Core_Helper_Data::CREATED_LOCK_FILE_REGISTRY);
145
+ if ($fullPath) {
146
+ @unlink($fullPath);
147
+ }
148
+ Mage::unregister(Emv_Core_Helper_Data::CREATED_LOCK_FILE_REGISTRY);
149
  }
150
 
151
  /**
152
+ * Remove a lock file. Empty this registry Emv_Core_Helper_Data::CREATED_LOCK_FILE_REGISTRY
153
  *
154
  * @param string $fileName
155
  * @return boolean
156
  */
157
  public function removeLockFile($fileName)
158
  {
159
+ $sucess = $this->_getLockHandler()->rm($fileName);
160
+ if ($sucess) {
161
+ Mage::unregister(self::CREATED_LOCK_FILE_REGISTRY);
162
+ };
163
+ return $sucess;
164
  }
165
 
166
  /**
167
  * Check if lock file exists
168
+ *
169
  * @param string $fileName
170
  * @return boolean
171
  */
174
  return $this->_getLockHandler()->fileExists($fileName, true);
175
  }
176
 
177
+ /**
178
+ * Set SmartFocus Error Handler
179
+ *
180
+ * @return string previous error handler
181
+ */
182
+ public function setSmartFocusErrorHandler()
183
+ {
184
+ include_once Mage::getBaseDir('code') . DS . 'community'
185
+ . DS . 'Emv' . DS . 'Core' . DS . 'functions.php';
186
+
187
+ // set register shutdown function in order to remove lock file
188
+ register_shutdown_function(self::CUSTOM_SHUTDOWN_HANDLER);
189
+ return set_error_handler(self::CUSTOM_ERROR_HANDLER);
190
+ }
191
+
192
+ /**
193
+ * Reset Error Handler to Magento default one
194
+ *
195
+ * @return string previous error handler
196
+ */
197
+ public function resetErrorHandler()
198
+ {
199
+ // reset shut down function
200
+ register_shutdown_function(function(){});
201
+ return set_error_handler(Mage_Core_Model_App::DEFAULT_ERROR_HANDLER);
202
+ }
203
+
204
  /**
205
  * @param string $path
206
  * @param mixed $store
216
  return $website->getConfig($path);
217
  }
218
 
219
+ if ($storeCode = Mage::app()->getRequest()->getParam('store')) {
220
+ $store = Mage::app()->getStore($storeCode);
221
+ return $store->getConfig($path);
222
+ } elseif ($websiteCode = Mage::app()->getRequest()->getParam('website')){
223
+ $website = Mage::app()->getWebsite($websiteCode);
224
+ return $website->getConfig($path);
225
+ } else if ($groupCode = Mage::app()->getRequest()->getParam('group')){
226
+ $website = Mage::app()->getGroup($groupCode)->getWebsite();
227
+ return $website->getConfig($path);
 
 
 
228
  }
229
 
230
  return Mage::getStoreConfig($path);
231
  }
232
 
233
+ /**
234
+ * Get admin scope in order to store config data
235
+ *
236
+ * @return array admin scope
237
+ * - scope
238
+ * - scope_id
239
+ * - scope_code
240
+ */
241
+ public function getAdminScope()
242
+ {
243
+ $scope = 'default';
244
+ $scopeId = 0;
245
+ $scopeCode = '';
246
+ if ($storeCode = Mage::app()->getRequest()->getParam('store')) {
247
+ $scope = 'stores';
248
+ $scopeId = (int)Mage::getConfig()->getNode('stores/' . $storeCode . '/system/store/id');
249
+ $scopeCode = $storeCode;
250
+ } elseif ($websiteCode = Mage::app()->getRequest()->getParam('website')) {
251
+ $scope = 'websites';
252
+ $scopeId = (int)Mage::getConfig()->getNode('websites/' . $websiteCode . '/system/website/id');
253
+ $scopeCode = $websiteCode;
254
+ }
255
+
256
+ return array('scope' => $scope, 'scope_id' => $scopeId, 'scope_code' => $scopeCode);
257
+ }
258
+
259
  /**
260
  * Format number in a given locale
261
  *
282
  return $number;
283
  }
284
 
285
+ /**
286
+ * Check and get url for a given url type.
287
+ *
288
+ * @param Emv_Core_Model_Account $account
289
+ * @param string $type
290
+ * @throws Mage_Core_Exception if we can't find a corresponding url
291
+ * @return string
292
+ */
293
+ public function checkAndGetUrlForType(Emv_Core_Model_Account $account, $type)
294
+ {
295
+ // get service label
296
+ $labels = Emv_Core_Model_Account::getUrlTypesAndLabels();
297
+ $serviceLabel = $type;
298
+ if (isset($labels[$type])) {
299
+ $serviceLabel = $labels[$type];
300
+ }
301
+
302
+ // check url
303
+ $url = $account->getUrlForType($type);
304
+ if (!$url) {
305
+ Mage::throwException(Mage::helper('emvcore')->__('Please define a valid url for %s !', $serviceLabel));
306
+ }
307
+
308
+ return $url;
309
+ }
310
+
311
+ /**
312
+ * @param Emv_Core_Model_DataProcessing_Process $process
313
+ * @return string
314
+ */
315
+ public function getLogUrlForProcess(Emv_Core_Model_DataProcessing_Process $process)
316
+ {
317
+ return Mage::getModel('adminhtml/url')->getUrl('emv_core/dataProcessing/log', array('id' => $process->getId()));
318
+ }
319
  }
app/code/community/Emv/Core/Model/Account.php CHANGED
@@ -18,6 +18,22 @@ class Emv_Core_Model_Account extends Mage_Core_Model_Abstract
18
  const URL_BATCH_MEMBER_SERVICE_TYPE = 'batch_member';
19
  const URL_MEMBER_SERVICE_TYPE = 'member';
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * Constructor
23
  *
18
  const URL_BATCH_MEMBER_SERVICE_TYPE = 'batch_member';
19
  const URL_MEMBER_SERVICE_TYPE = 'member';
20
 
21
+ /**
22
+ * Prefix of model events names
23
+ *
24
+ * @var string
25
+ */
26
+ protected $_eventPrefix = 'emv_account';
27
+
28
+ /**
29
+ * Parameter name in event
30
+ *
31
+ * In observe method you can use $observer->getEvent()->getObject() in this case
32
+ *
33
+ * @var string
34
+ */
35
+ protected $_eventObject = 'emv_account';
36
+
37
  /**
38
  * Constructor
39
  *
app/code/community/Emv/Core/Model/Adminhtml/System/Config/Backend/Account/Abstract.php CHANGED
@@ -89,19 +89,6 @@ abstract class Emv_Core_Model_Adminhtml_System_Config_Backend_Account_Abstract e
89
  */
90
  protected function _checkAndGetUrlForType(Emv_Core_Model_Account $account, $type)
91
  {
92
- // get service label
93
- $labels = Emv_Core_Model_Account::getUrlTypesAndLabels();
94
- $serviceLabel = $type;
95
- if (isset($labels[$type])) {
96
- $serviceLabel = $labels[$type];
97
- }
98
-
99
- // check url
100
- $url = $account->getUrlForType($type);
101
- if (!$url) {
102
- Mage::throwException(Mage::helper('emvcore')->__('Please define a valid url for %s !', $serviceLabel));
103
- }
104
-
105
- return $url;
106
  }
107
  }
89
  */
90
  protected function _checkAndGetUrlForType(Emv_Core_Model_Account $account, $type)
91
  {
92
+ return Mage::helper('emvcore')->checkAndGetUrlForType($account, $type);
 
 
 
 
 
 
 
 
 
 
 
 
 
93
  }
94
  }
app/code/community/Emv/Core/Model/Adminhtml/System/Config/Backend/Cron.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Cron Expression Backend Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ */
9
+ class Emv_Core_Model_Adminhtml_System_Config_Backend_Cron extends Mage_Core_Model_Config_Data
10
+ {
11
+ /**
12
+ * Crontab expression path - please define an appropriate path in order to make this backend work
13
+ * @var string
14
+ */
15
+ protected $_crontabPath = '';
16
+
17
+ /**
18
+ * Save a formated crontime in core_config_data
19
+ *
20
+ * @see Mage_Core_Model_Abstract::_afterSave()
21
+ */
22
+ protected function _afterSave()
23
+ {
24
+ if ($this->_crontabPath) {
25
+ $cronConfigModel = Mage::getModel('core/config_data')
26
+ ->load($this->_crontabPath, 'path');
27
+
28
+ // if the cron is disabled, we remove the cron expression to avoid launching it again
29
+ $enabled = (bool)$this->getFieldsetDataValue('enabled');
30
+ if (!$enabled) {
31
+ if ($cronConfigModel->getConfigId()) {
32
+ $cronConfigModel->delete();
33
+ }
34
+ return false;
35
+ }
36
+
37
+ $frequencyDaily = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_DAILY;
38
+ $frequencyWeekly = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_WEEKLY;
39
+ $frequencyMonthly = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_MONTHLY;
40
+
41
+ // get time and frequency
42
+ $time = $this->getFieldsetDataValue('time');
43
+ $frequency = $this->getFieldsetDataValue('frequency');
44
+
45
+ $monthlySetting = '*';
46
+ if ($frequency == $frequencyMonthly) {
47
+ $dateSetting = (int)$this->getFieldsetDataValue('date');
48
+ if ($dateSetting) {
49
+ $monthlySetting = $dateSetting;
50
+ } else {
51
+ // trigger cron process at the first day of the month
52
+ $monthlySetting = 1;
53
+ }
54
+ }
55
+
56
+ $weeklySetting = '*';
57
+ if ($frequency == $frequencyWeekly) {
58
+ $daySetting = (int)$this->getFieldsetDataValue('day');
59
+ if ($daySetting) {
60
+ $weeklySetting = $daySetting;
61
+ } else {
62
+ // trigger cron process at the first day of the week
63
+ $weeklySetting = 1;
64
+ }
65
+ }
66
+
67
+ // build cron expression string
68
+ $cronExprArray = array(
69
+ intval($time[1]), // Minute
70
+ intval($time[0]), // Hour
71
+ $monthlySetting, // Day of the Month
72
+ '*', // Month of the Year
73
+ $weeklySetting, // Day of the Week
74
+ );
75
+ $cronExprString = join(' ', $cronExprArray);
76
+
77
+ try {
78
+ $cronConfigModel
79
+ ->setValue($cronExprString)
80
+ ->setPath($this->_crontabPath)
81
+ ->save();
82
+ } catch (Exception $e) {
83
+ Mage::throwException(Mage::helper('emvdatasync')->__('Unable to save the cron expression for scheduled exports'));
84
+ }
85
+ }
86
+ }
87
+ }
app/code/community/Emv/Core/Model/{System → Adminhtml/System}/Config/Source/Account.php RENAMED
@@ -7,7 +7,7 @@
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
- class Emv_Core_Model_System_Config_Source_Account
11
  {
12
  public function toOptionArray()
13
  {
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
+ class Emv_Core_Model_Adminhtml_System_Config_Source_Account
11
  {
12
  public function toOptionArray()
13
  {
app/code/community/Emv/Core/Model/Adminhtml/System/Config/Source/CronDate.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Date of the month source for Cron configuration
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ *
10
+ */
11
+ class Emv_Core_Model_Adminhtml_System_Config_Source_CronDate
12
+ {
13
+
14
+ /**
15
+ * @var array
16
+ */
17
+ protected static $_options;
18
+
19
+ /**
20
+ * @return array
21
+ */
22
+ public function toOptionArray()
23
+ {
24
+ if (!self::$_options) {
25
+ self::$_options = array();
26
+
27
+ for ($i = 1; $i < 32; $i++) {
28
+ self::$_options[] = array(
29
+ 'label' => $i,
30
+ 'value' => $i,
31
+ );
32
+ }
33
+ }
34
+ return self::$_options;
35
+ }
36
+ }
app/code/community/Emv/Core/Model/Adminhtml/System/Config/Source/CronDay.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Day of the week source for cron configuration
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ *
10
+ */
11
+ class Emv_Core_Model_Adminhtml_System_Config_Source_CronDay
12
+ {
13
+
14
+ /**
15
+ * @var array
16
+ */
17
+ protected static $_options;
18
+
19
+ /**
20
+ * @return array
21
+ */
22
+ public function toOptionArray()
23
+ {
24
+ if (!self::$_options) {
25
+ self::$_options = array(
26
+ array(
27
+ 'label' => Mage::helper('cron')->__('Monday'),
28
+ 'value' => 1,
29
+ ),
30
+ array(
31
+ 'label' => Mage::helper('cron')->__('Tuesday'),
32
+ 'value' => 2,
33
+ ),
34
+ array(
35
+ 'label' => Mage::helper('cron')->__('Wednesday'),
36
+ 'value' => 3,
37
+ ),
38
+ array(
39
+ 'label' => Mage::helper('cron')->__('Thursday'),
40
+ 'value' => 4,
41
+ ),
42
+ array(
43
+ 'label' => Mage::helper('cron')->__('Friday'),
44
+ 'value' => 5,
45
+ ),
46
+ array(
47
+ 'label' => Mage::helper('cron')->__('Saturday'),
48
+ 'value' => 6,
49
+ ),
50
+ array(
51
+ 'label' => Mage::helper('cron')->__('Sunday'),
52
+ 'value' => 0,
53
+ ),
54
+ );
55
+ }
56
+ return self::$_options;
57
+ }
58
+ }
app/code/community/Emv/Core/Model/DataProcessing/Exception.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Data Process Exception
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Model_DataProcessing_Exception extends Zend_Exception
11
+ {
12
+ }
app/code/community/Emv/Core/Model/DataProcessing/Process.php ADDED
@@ -0,0 +1,335 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Process Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Model_DataProcessing_Process extends Mage_Core_Model_Abstract
11
+ {
12
+ /**
13
+ * State constants
14
+ */
15
+ const STATE_NEW = 0;
16
+ const STATE_PROCESSING = 3;
17
+ const STATE_FAILED = 5;
18
+ const STATE_SUCCESS = 10;
19
+
20
+ /**
21
+ * Working dir constant
22
+ */
23
+ const DATAPROCESSING_DIR = 'dataprocessing';
24
+
25
+ /**
26
+ * Type Constant
27
+ */
28
+ const TYPE_DATA_SYNC = 'data_sync';
29
+
30
+ /**
31
+ * Process log
32
+ * @var Emv_Core_Model_DataProcessing_Process_Log
33
+ */
34
+ protected $_log = null;
35
+
36
+ /**
37
+ * Get base directory for the module
38
+ *
39
+ * @return string
40
+ */
41
+ public static function getBaseDir()
42
+ {
43
+ $path = Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
44
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
45
+ . DS . self::DATAPROCESSING_DIR;
46
+
47
+ $args = array(
48
+ 'path' => $path,
49
+ );
50
+ $mageFile = new Varien_Io_File();
51
+ $mageFile->setAllowCreateFolders(true);
52
+ $mageFile->open($args);
53
+
54
+ return $path;
55
+ }
56
+
57
+ /**
58
+ * Retrieve relative path by given file name
59
+ *
60
+ * @param string $fileName file name
61
+ *
62
+ * @return string
63
+ */
64
+ public static function getRelativePath($fileName)
65
+ {
66
+ $baseDir = self::getBaseDir();
67
+ if (substr($fileName, 0, strlen($baseDir)) == $baseDir) {
68
+ $fileName = substr($fileName, strlen($baseDir) - strlen($fileName));
69
+ }
70
+ return $fileName;
71
+ }
72
+
73
+ /**
74
+ * Init resource model
75
+ *
76
+ * @return void
77
+ */
78
+ protected function _construct()
79
+ {
80
+ $this->_init('emvcore/dataProcessing_process');
81
+ $this->setState(self::STATE_NEW);
82
+ $this->setCreatedAt(Mage::getModel('core/date')->gmtDate());
83
+ }
84
+
85
+ /**
86
+ * Update status of the process
87
+ *
88
+ * @param int $status
89
+ *
90
+ * @return void
91
+ */
92
+ public function updateStatus($status)
93
+ {
94
+ $this->setStatus($status);
95
+ $this->setUpdatedAt(Mage::getModel('core/date')->gmtDate());
96
+ $this->save();
97
+ }
98
+
99
+ /**
100
+ * Change state of the process
101
+ *
102
+ * @param int $state
103
+ *
104
+ * @return void
105
+ */
106
+ public function changeState($state)
107
+ {
108
+ if (in_array($state, array_keys($this->getStatesArray()))) {
109
+ $this->setState($state);
110
+ $this->setUpdatedAt(Mage::getModel('core/date')->gmtDate());
111
+ $this->save();
112
+ }
113
+ }
114
+
115
+ /**
116
+ * Run process
117
+ *
118
+ * @return void
119
+ */
120
+ public function run()
121
+ {
122
+ $this->setState(self::STATE_PROCESSING);
123
+ $this->setStatus(0);
124
+ $this->save();
125
+ }
126
+
127
+ /**
128
+ * Finalize process
129
+ *
130
+ * @param Exception $exception
131
+ * @param int $state
132
+ *
133
+ * @return void
134
+ */
135
+ public function finalize(Exception $exception = null, $state = null)
136
+ {
137
+ if (is_null($state) || !in_array($state, array_keys($this->getStatesArray()))) {
138
+ if (is_null($exception)) {
139
+ $this->setState(self::STATE_SUCCESS);
140
+ } else {
141
+ $this->setState(self::STATE_FAILED);
142
+ }
143
+ } else {
144
+ $this->setState($state);
145
+ }
146
+ $this->setTerminatedAt(Mage::getModel('core/date')->gmtDate());
147
+ $this->setStatus(100);
148
+ $this->save();
149
+ }
150
+
151
+ /**
152
+ * Kill process in case of exception
153
+ *
154
+ * @return void
155
+ */
156
+ public function kill()
157
+ {
158
+ $this->setState(self::STATE_FAILED);
159
+ $this->setTerminatedAt(Mage::getModel('core/date')->gmtDate());
160
+ $this->setStatus(100);
161
+ $this->save();
162
+ }
163
+
164
+ /**
165
+ * Get states array
166
+ *
167
+ * @return array
168
+ */
169
+ public function getStatesArray()
170
+ {
171
+ return array(
172
+ self::STATE_NEW => Mage::helper('emvcore')->__('New'),
173
+ self::STATE_PROCESSING => Mage::helper('emvcore')->__('Processing'),
174
+ self::STATE_FAILED => Mage::helper('emvcore')->__('Failed'),
175
+ self::STATE_SUCCESS => Mage::helper('emvcore')->__('Success')
176
+ );
177
+ }
178
+
179
+ /**
180
+ * Get base process dir
181
+ *
182
+ * @return string
183
+ */
184
+ public function getProcessDir()
185
+ {
186
+ $processDir = self::getBaseDir() . DS . $this->getId();
187
+ if (!is_dir($processDir)) {
188
+ mkdir($processDir);
189
+ }
190
+ return $processDir;
191
+ }
192
+
193
+ /**
194
+ * Get log file name
195
+ *
196
+ * @return string
197
+ */
198
+ public function getLogFileName()
199
+ {
200
+ return $this->getProcessDir().DS.'log.txt';
201
+ }
202
+
203
+ /**
204
+ * Set log object
205
+ *
206
+ * @param Emv_Core_Model_DataProcessing_Process_Log $log
207
+ *
208
+ * @return void
209
+ */
210
+ protected function _setLog(Emv_Core_Model_DataProcessing_Process_Log $log)
211
+ {
212
+ $this->_log = $log;
213
+ }
214
+
215
+ /**
216
+ * Get report log object
217
+ *
218
+ * @return Emv_Core_Model_DataProcessing_Process_Log
219
+ */
220
+ public function getLog()
221
+ {
222
+ return $this->_log;
223
+ }
224
+
225
+ /**
226
+ * Get log content
227
+ *
228
+ * @return string
229
+ */
230
+ public function getLogContent()
231
+ {
232
+ return file_get_contents($this->getLogFileName());
233
+ }
234
+
235
+ /**
236
+ * Init log object
237
+ *
238
+ * @param string $className
239
+ *
240
+ * @return void
241
+ * @throws Emv_Core_Model_DataProcessing_Exception
242
+ */
243
+ public function initLog($className = null)
244
+ {
245
+ if (is_null($className)) {
246
+ $className = 'emvcore/dataProcessing_process_log';
247
+ }
248
+ $log = Mage::getModel($className);
249
+ if (!($log instanceof Emv_Core_Model_DataProcessing_Process_Log)) {
250
+ throw new Emv_Core_Model_DataProcessing_Exception('Can not initialize a log');
251
+ }
252
+ $logFileName = $this->getLogFileName();
253
+ file_put_contents($logFileName, '');
254
+ $log->init($logFileName);
255
+ $this->_setLog($log);
256
+ }
257
+
258
+ /**
259
+ * Check if log data can be retrieved
260
+ *
261
+ * @return boolean
262
+ */
263
+ public function checkLogData()
264
+ {
265
+ return is_readable($this->getLogFileName());
266
+ }
267
+
268
+ /**
269
+ * Delete process with related resources
270
+ *
271
+ * @return void
272
+ * @see Mage_Core_Model_Abstract::delete()
273
+ */
274
+ public function delete()
275
+ {
276
+ try {
277
+ $resources = array(
278
+ $this->getLogFileName(),
279
+ $this->getProcessDir()
280
+ );
281
+
282
+ foreach ($resources as $resource) {
283
+ if (file_exists($resource)) {
284
+ if (is_dir($resource)) {
285
+ rmdir($resource);
286
+ } else {
287
+ unlink($resource);
288
+ }
289
+ }
290
+ }
291
+ } catch (Exception $e) {
292
+ Mage::logException($e);
293
+ Mage::throwException(
294
+ Mage::helper('emvcore')->__(
295
+ 'Unable to delete resources related to the process'
296
+ )
297
+ );
298
+ }
299
+
300
+ parent::delete();
301
+ }
302
+
303
+ /**
304
+ * Set output information
305
+ * @param array $output
306
+ * @return Emv_Core_Model_DataProcessing_Process
307
+ */
308
+ public function setOutputInformation(array $output)
309
+ {
310
+ foreach ($output as $dataInfo) {
311
+ $this->addOutputInformation($output);
312
+ }
313
+ return $this;
314
+ }
315
+
316
+ /**
317
+ * @param array $output
318
+ * @throws Emv_Core_Model_DataProcessing_Exception
319
+ * @return Emv_Core_Model_DataProcessing_Process
320
+ */
321
+ public function addOutputInformation(array $output)
322
+ {
323
+ if (!isset($output['filename']) || !isset($output['path']) || !isset($output['label']) ) {
324
+ throw new Emv_Core_Model_DataProcessing_Exception('Your output information is not correct');
325
+ }
326
+
327
+ if (!isset($this->_data['output_information'])) {
328
+ $this->_data['output_information'] = array();
329
+ }
330
+
331
+ $this->_data['output_information'][] = $output;
332
+
333
+ return $this;
334
+ }
335
+ }
app/code/community/Emv/Core/Model/DataProcessing/Process/Log.php ADDED
@@ -0,0 +1,102 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Process Log Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Model_DataProcessing_Process_Log
11
+ {
12
+ /**
13
+ * Log filename
14
+ * @var string
15
+ */
16
+ protected $_filename;
17
+
18
+ /**
19
+ * Log object
20
+ * @var Zend_Log
21
+ */
22
+ private $_log = null;
23
+
24
+ /**
25
+ * Init log with a name for a log file
26
+ *
27
+ * @param string $filename
28
+ *
29
+ * @return void
30
+ * @throws Exception
31
+ */
32
+ public function init($filename)
33
+ {
34
+ if (empty($filename) || !is_writeable($filename)) {
35
+ throw new Exception('Log file is empty or not writeable');
36
+ }
37
+ $this->_filename = $filename;
38
+ $format = '%timestamp% %priorityName% : %message%' . PHP_EOL;
39
+ $writer = new Zend_Log_Writer_Stream($this->_filename);
40
+ $writer->setFormatter(new Zend_Log_Formatter_Simple($format));
41
+ $this->_log = new Zend_Log($writer);
42
+ }
43
+
44
+ /**
45
+ * Get filename
46
+ *
47
+ * @return string
48
+ */
49
+ public function getFileName()
50
+ {
51
+ return $this->_filename;
52
+ }
53
+
54
+ /**
55
+ * Put log message
56
+ *
57
+ * @param string $message
58
+ * @param int $level
59
+ *
60
+ * @return void
61
+ */
62
+ public function log($message, $level = null)
63
+ {
64
+ $this->_log->log(print_r($message, 1), $level, $this->_filename);
65
+ }
66
+
67
+ /**
68
+ * Put error message
69
+ *
70
+ * @param string $message
71
+ *
72
+ * @return void
73
+ */
74
+ public function error($message)
75
+ {
76
+ $this->log($message, Zend_Log::ERR);
77
+ }
78
+
79
+ /**
80
+ * Put warning message
81
+ *
82
+ * @param string $message
83
+ *
84
+ * @return void
85
+ */
86
+ public function warning($message)
87
+ {
88
+ $this->log($message, Zend_Log::WARN);
89
+ }
90
+
91
+ /**
92
+ * Put info message
93
+ *
94
+ * @param string $message
95
+ *
96
+ * @return void
97
+ */
98
+ public function info($message)
99
+ {
100
+ $this->log($message, Zend_Log::INFO);
101
+ }
102
+ }
app/code/community/Emv/Core/Model/DataProcessing/Profile.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Abstract Profile
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ abstract class Emv_Core_Model_DataProcessing_Profile
11
+ implements Emv_Core_Model_DataProcessing_Profile_Interface
12
+ {
13
+ /**
14
+ * Profile type
15
+ * @var string
16
+ */
17
+ protected $_type = 'profile';
18
+
19
+ /**
20
+ * Profile title
21
+ * @var string
22
+ */
23
+ protected $_title = 'Profile';
24
+
25
+ /**
26
+ * Current process
27
+ * @var Emv_Core_Model_DataProcessing_Process
28
+ */
29
+ protected $_process = null;
30
+
31
+ /**
32
+ * Process class name
33
+ * @var string
34
+ */
35
+ protected $_processClassName = 'emvcore/dataProcessing_process';
36
+
37
+ /**
38
+ * Class name for log
39
+ * @var string
40
+ */
41
+ protected $_logClassName = null;
42
+
43
+ protected $_inputData = array();
44
+
45
+ protected $_isInitialized = false;
46
+
47
+ /**
48
+ * Init profile
49
+ *
50
+ * @param Emv_Core_Model_DataProcessing_Process $process
51
+ *
52
+ * @return void
53
+ * @throws Exception
54
+ */
55
+ public function init(Emv_Core_Model_DataProcessing_Process $process = null)
56
+ {
57
+ $this->_validateInit($process);
58
+ $process->initLog($this->_logClassName);
59
+ $this->_process = $process;
60
+ $this->_isInitialized = true;
61
+ Mage::dispatchEvent('smartfocus_dataprocessing_profile_after_init', array('profile' => $this));
62
+ }
63
+
64
+ /**
65
+ * (non-PHPdoc)
66
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::getInputData()
67
+ */
68
+ public function getInputData()
69
+ {
70
+ return $this->_inputData;
71
+ }
72
+
73
+ /**
74
+ * (non-PHPdoc)
75
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::setInputData()
76
+ */
77
+ public function setInputData(array $input)
78
+ {
79
+ $this->_inputData = $input;
80
+ return $this;
81
+ }
82
+
83
+ /**
84
+ * (non-PHPdoc)
85
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::getProcess()
86
+ */
87
+ public function getProcess()
88
+ {
89
+ return $this->_process;
90
+ }
91
+
92
+ /**
93
+ * Validate process used to profile init
94
+ *
95
+ * @param Emv_Core_Model_DataProcessing_Process $process
96
+ *
97
+ * @return void
98
+ * @throws Emv_Core_Model_DataProcessing_Exception
99
+ */
100
+ private function _validateInit(Emv_Core_Model_DataProcessing_Process $process = null)
101
+ {
102
+ if ($this->_isInitialized) {
103
+ throw new Emv_Core_Model_DataProcessing_Exception('Profile is already intialized');
104
+ }
105
+ if (is_null($process)) {
106
+ throw new Emv_Core_Model_DataProcessing_Exception('Process can not be null');
107
+ }
108
+ if (!($process instanceof Varien_Object)) {
109
+ throw new Emv_Core_Model_DataProcessing_Exception('Process must be an instance of Varien_Object class');
110
+ }
111
+ if (($process instanceof Emv_Core_Model_DataProcessing_Process) && (!$process->getId())) {
112
+ throw new Emv_Core_Model_DataProcessing_Exception('Process should be registered before profile execution');
113
+ }
114
+ }
115
+
116
+ /**
117
+ * Get default profile process
118
+ *
119
+ * @return Emv_Core_Model_DataProcessing_Process $process
120
+ */
121
+ public function initProcess()
122
+ {
123
+ $process = Mage::getModel($this->_processClassName);
124
+ $process->setTitle($this->_title);
125
+ $process->setType($this->_type);
126
+
127
+ $process->save();
128
+ return $process;
129
+ }
130
+
131
+ /**
132
+ * Run profile
133
+ *
134
+ * @return void
135
+ * @throws Emv_Core_Model_DataProcessing_Exception
136
+ */
137
+ public function run()
138
+ {
139
+ Mage::dispatchEvent('smartfocus_dataprocessing_profile_before_run', array('profile' => $this));
140
+ $this->checkLocks();
141
+ try {
142
+ if (!$this->_isInitialized) {
143
+ $this->init($this->getDefaultProcess());
144
+ }
145
+ } catch (Exception $e) {
146
+ $this->_finalize($e);
147
+ throw $e;
148
+ }
149
+
150
+ try {
151
+ $this->getProcess()->run();
152
+ $this->_run();
153
+ } catch (Exception $e) {
154
+ $this->_finalize($e);
155
+ Mage::dispatchEvent('smartfocus_dataprocessing_profile_after_failure', array('profile' => $this));
156
+ throw $e;
157
+ }
158
+ $this->_finalize();
159
+ Mage::dispatchEvent('smartfocus_dataprocessing_profile_after_success', array('profile' => $this));
160
+ }
161
+
162
+ /**
163
+ * General finalize function
164
+ *
165
+ * @param Exception $exception
166
+ *
167
+ * @return void
168
+ */
169
+ protected function _finalize(Exception $exception = null)
170
+ {
171
+ $this->getProcess()->finalize($exception);
172
+ $this->_afterFinalize($exception);
173
+ Mage::dispatchEvent('smartfocus_dataprocessing_profile_after_finalize', array('profile' => $this));
174
+ }
175
+
176
+ /**
177
+ * Custom _finalization function.
178
+ * Allows to add some logic or manage the exception in some special way.
179
+ * Implementation is not required.
180
+ *
181
+ * @param Exception $exception
182
+ *
183
+ * @return void
184
+ */
185
+ protected function _afterFinalize(Exception $exception = null)
186
+ {
187
+ }
188
+
189
+ /**
190
+ * Main profile function. Launch a profile
191
+ *
192
+ * @return void
193
+ */
194
+ abstract protected function _run();
195
+ }
app/code/community/Emv/Core/Model/DataProcessing/Profile/Interface.php ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Data Processing Profile interface
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ interface Emv_Core_Model_DataProcessing_Profile_Interface
11
+ {
12
+ /**
13
+ * Intialize Process
14
+ * @return Emv_Core_Model_DataProcessing_Process
15
+ */
16
+ public function initProcess();
17
+
18
+ /**
19
+ * Initialize Profile
20
+ * @param Emv_Core_Model_DataProcessing_Process $process
21
+ */
22
+ public function init(Emv_Core_Model_DataProcessing_Process $process = null);
23
+
24
+ /**
25
+ * Get input data has been set up
26
+ * @return array
27
+ */
28
+ public function getInputData();
29
+
30
+ /**
31
+ * Set input data for profile
32
+ * @param array $input
33
+ */
34
+ public function setInputData(array $input);
35
+
36
+ /**
37
+ * Get associated process
38
+ * @return null | Emv_Core_Model_DataProcessing_Process
39
+ */
40
+ public function getProcess();
41
+
42
+ /**
43
+ * Run Profile
44
+ */
45
+ public function run();
46
+ }
app/code/community/Emv/Core/Model/Mysql4/DataProcessing/Process.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Process Resource Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Model_Mysql4_DataProcessing_Process extends Mage_Core_Model_Mysql4_Abstract
11
+ {
12
+ /**
13
+ * Serializeable field: output_information
14
+ *
15
+ * @var array
16
+ */
17
+ protected $_serializableFields = array(
18
+ 'output_information' => array(array(), array())
19
+ );
20
+
21
+ /**
22
+ * (non-PHPdoc)
23
+ * @see Mage_Core_Model_Resource_Abstract::_construct()
24
+ */
25
+ protected function _construct()
26
+ {
27
+ $this->_init('emvcore/dataprocessing_process','id');
28
+ }
29
+ }
app/code/community/Emv/Core/Model/Mysql4/DataProcessing/Process/Collection.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Process Resource Collection
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Model_Mysql4_DataProcessing_Process_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
11
+ {
12
+ protected function _construct()
13
+ {
14
+ $this->_init('emvcore/dataProcessing_process','emvcore/dataProcessing_process');
15
+ }
16
+ }
app/code/community/Emv/Core/Model/Service/Abstract.php CHANGED
@@ -119,6 +119,7 @@ abstract class Emv_Core_Model_Service_Abstract extends Mage_Core_Model_Abstract
119
  /**
120
  * Check if API credential is valid. Return the token if success
121
  *
 
122
  * @throws Exception - in case of errors
123
  * @return string
124
  */
119
  /**
120
  * Check if API credential is valid. Return the token if success
121
  *
122
+ * @throws EmailVision_Api_Exception $exception api error
123
  * @throws Exception - in case of errors
124
  * @return string
125
  */
app/code/community/Emv/Core/Model/Service/Notification.php CHANGED
@@ -54,7 +54,7 @@ class Emv_Core_Model_Service_Notification extends Mage_Core_Model_Abstract
54
  }
55
 
56
  /**
57
- * Send Email with given template.
58
  *
59
  * @param string $encrypt
60
  * @param string $notificationId
54
  }
55
 
56
  /**
57
+ * Send Email with given template. The rest api will be used
58
  *
59
  * @param string $encrypt
60
  * @param string $notificationId
app/code/community/Emv/Core/Model/Service/Transactional.php CHANGED
@@ -42,9 +42,9 @@ class Emv_Core_Model_Service_Transactional extends Emv_Core_Model_Service_Abstra
42
  public function getTemplateById($templateId)
43
  {
44
  $emvTemplate = null;
45
- $serivce = $this->getApiService();
46
  try {
47
- $emvTemplate = $serivce->getTemplateById($templateId);
48
  } catch (Exception $e) {
49
  // log errors
50
  Mage::logException($e);
42
  public function getTemplateById($templateId)
43
  {
44
  $emvTemplate = null;
45
+ $service = $this->getApiService();
46
  try {
47
+ $emvTemplate = $service->getTemplateById($templateId);
48
  } catch (Exception $e) {
49
  // log errors
50
  Mage::logException($e);
app/code/community/Emv/Core/controllers/Adminhtml/AccountController.php CHANGED
@@ -3,7 +3,7 @@
3
  * This controller is used to manage all account view (grid list, edit/new form)
4
  *
5
  * @category Emv
6
- * @package Emv_Emt
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
3
  * This controller is used to manage all account view (grid list, edit/new form)
4
  *
5
  * @category Emv
6
+ * @package Emv_Core
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
app/code/community/Emv/Core/controllers/Adminhtml/DataProcessingController.php ADDED
@@ -0,0 +1,175 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * This controller is used to manage all Data Processing Process view (grid list, edit/new form)
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Core
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Core_Adminhtml_DataProcessingController extends Mage_Adminhtml_Controller_Action
11
+ {
12
+ /**
13
+ * Current process
14
+ * @var Emv_Core_Model_DataProcessing_Process
15
+ */
16
+ protected $_process = null;
17
+
18
+ /**
19
+ * Initialise action
20
+ * - load all layout
21
+ * - set active menu SmartFocus
22
+ */
23
+ protected function _initAction()
24
+ {
25
+ $this->loadLayout();
26
+ $this->_setActiveMenu('emailvision/emvcore');
27
+ // Define module dependent translate
28
+ $this->setUsedModuleName('Emv_Core');
29
+ $this->_title(Mage::helper('emvcore')->__('SmartFocus'))
30
+ ->_title(Mage::helper('emvcore')->__('Data Process'));
31
+ }
32
+
33
+ /**
34
+ * Action to display Data Processing Porcess grid
35
+ */
36
+ public function indexAction()
37
+ {
38
+ if ($this->getRequest()->getParam('ajax')) {
39
+ $this->_forward('grid');
40
+ return;
41
+ }
42
+
43
+ // save all messages from session
44
+ $this->getLayout()->getMessagesBlock()->setMessages(
45
+ $this->_getSession()->getMessages()
46
+ );
47
+
48
+ $this->_initAction();
49
+ $this->_addContent(
50
+ $this->getLayout()->createBlock('emvcore/adminhtml_dataProcessing_process','process')
51
+ );
52
+ $this->renderLayout();
53
+ }
54
+
55
+ /**
56
+ * Data Processing Process Grid action for ajax request
57
+ */
58
+ public function gridAction()
59
+ {
60
+ $this->loadLayout();
61
+ $this->getResponse()->setBody(
62
+ $this->getLayout()->createBlock('emvcore/adminhtml_dataProcessing_process_grid')->toHtml()
63
+ );
64
+ }
65
+
66
+ /**
67
+ * Get output file content
68
+ *
69
+ * @return void
70
+ */
71
+ public function getOutputFileAction()
72
+ {
73
+ try {
74
+ $fullFileName = base64_decode($this->getRequest()->get('path'));
75
+ $fileName = base64_decode($this->getRequest()->get('filename'));
76
+ if (is_readable($fullFileName)) {
77
+ $content = file_get_contents($fullFileName);
78
+ return $this->_prepareDownloadResponse($fileName, $content);
79
+ }
80
+ } catch (Exception $e) {
81
+ $this->_getSession()->addError(Mage::helper('emvcore')->__('Error during get output file'));
82
+ Mage::logException($e);
83
+ }
84
+ $this->_redirect('*/dataProcessing/');
85
+ }
86
+
87
+ /**
88
+ * Get log content
89
+ *
90
+ * @return void
91
+ */
92
+ public function logAction()
93
+ {
94
+ try {
95
+ $content = $this->_getProcess()->getLogContent();
96
+ return $this->_prepareDownloadResponse($this->_getProcess()->getId().'-log.txt', $content);
97
+ } catch (Exception $e) {
98
+ $this->_getSession()->addError(Mage::helper('emvcore')->__('Error during get process log'));
99
+ Mage::logException($e);
100
+ }
101
+ $this->_redirect('*/dataProcessing/');
102
+ }
103
+
104
+ /**
105
+ * Get current process
106
+ *
107
+ * @return Emv_Core_Model_DataProcessing_Process
108
+ */
109
+ protected function _getProcess()
110
+ {
111
+ if (is_null($this->_process)) {
112
+ $processId = $this->getRequest()->get('id');
113
+ if (empty($processId)) {
114
+ Mage::throwException('Process is empty');
115
+ }
116
+ $process = Mage::getModel('emvcore/dataProcessing_process')->load($processId);
117
+ if (!$process->getId()) {
118
+ Mage::throwException('Process does not exist : ' . $processId);
119
+ }
120
+ $this->_process = $process;
121
+ }
122
+ return $this->_process;
123
+ }
124
+
125
+ /**
126
+ * Delete mass action
127
+ *
128
+ * @return void
129
+ */
130
+ public function massDeleteAction()
131
+ {
132
+ $processIds = $this->getRequest()->getParam('ids');
133
+ if (!is_array($processIds)) {
134
+ $this->_getSession()->addError(Mage::helper('emvcore')->__('Please select something!'));
135
+ } else {
136
+ $deleted = 0;
137
+ foreach ($processIds as $processId) {
138
+ try {
139
+ $process = Mage::getSingleton('emvcore/dataProcessing_process')->load($processId);
140
+ $process->delete();
141
+ $deleted++;
142
+ } catch (Mage_Core_Exception $e) {
143
+ $this->_getSession()->addError(
144
+ Mage::helper('emvcore')->__('Unable to delete the process #%s. Reason: %s', $processId, $e->getMessage())
145
+ );
146
+ } catch (Exception $e) {
147
+ $this->_getSession()->addError(
148
+ Mage::helper('emvcore')->__('Unable to delete the process #%s', $processId)
149
+ );
150
+ Mage::logException($e);
151
+ }
152
+ }
153
+ }
154
+ if ($deleted > 1) {
155
+ $this->_getSession()->addSuccess(
156
+ Mage::helper('emvcore')->__('%s records were successfully deleted', $deleted)
157
+ );
158
+ } elseif ($deleted == 1) {
159
+ $this->_getSession()->addSuccess(
160
+ Mage::helper('emvcore')->__('One record was successfully deleted')
161
+ );
162
+ }
163
+ $this->_redirect('*/*/');
164
+ }
165
+
166
+ /**
167
+ * Check if having a correct permission
168
+ *
169
+ * @return boolean
170
+ */
171
+ protected function _isallowed()
172
+ {
173
+ return Mage::getSingleton('admin/session')->isAllowed('emailvision/emvdataprocessing');
174
+ }
175
+ }
app/code/community/Emv/Core/etc/adminhtml.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
  <menu>
4
- <!-- EmailVision menu in the back office -->
5
  <emailvision translate="title" module="adminhtml">
6
  <title>SmartFocus</title>
7
  <sort_order>999</sort_order>
@@ -11,6 +11,11 @@
11
  <sort_order>10</sort_order>
12
  <action>emv_core/account</action>
13
  </emvcore>
 
 
 
 
 
14
  </children>
15
  </emailvision>
16
  </menu>
@@ -19,15 +24,19 @@
19
  <resources>
20
  <admin>
21
  <children>
22
- <!-- EmailVision acl -->
23
  <emailvision translate="title" module="emvcore">
24
  <title>SmartFocus</title>
25
  <sort_order>90</sort_order>
26
  <children>
27
  <emvcore translate="title" module="emvcore">
28
  <title>Accounts</title>
29
- <sort_order>1000</sort_order>
30
  </emvcore>
 
 
 
 
31
  </children>
32
  </emailvision>
33
  </children>
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
  <menu>
4
+ <!-- SmartFocus menu in the back office -->
5
  <emailvision translate="title" module="adminhtml">
6
  <title>SmartFocus</title>
7
  <sort_order>999</sort_order>
11
  <sort_order>10</sort_order>
12
  <action>emv_core/account</action>
13
  </emvcore>
14
+ <emvdataprocessing translate="title" module="emvcore">
15
+ <title>Data Process List</title>
16
+ <sort_order>15</sort_order>
17
+ <action>emv_core/dataProcessing</action>
18
+ </emvdataprocessing>
19
  </children>
20
  </emailvision>
21
  </menu>
24
  <resources>
25
  <admin>
26
  <children>
27
+ <!-- SmartFocus acl -->
28
  <emailvision translate="title" module="emvcore">
29
  <title>SmartFocus</title>
30
  <sort_order>90</sort_order>
31
  <children>
32
  <emvcore translate="title" module="emvcore">
33
  <title>Accounts</title>
34
+ <sort_order>100</sort_order>
35
  </emvcore>
36
+ <emvdataprocessing>
37
+ <title>Data Process List</title>
38
+ <sort_order>200</sort_order>
39
+ </emvdataprocessing>
40
  </children>
41
  </emailvision>
42
  </children>
app/code/community/Emv/Core/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Emv_Core>
5
- <version>0.2.0</version>
6
  </Emv_Core>
7
  </modules>
8
  <global>
@@ -27,6 +27,9 @@
27
  <account>
28
  <table>emv_account</table>
29
  </account>
 
 
 
30
  </entities>
31
  </emvcore_mysql4>
32
  </models>
@@ -54,6 +57,13 @@
54
  </Emv_Core>
55
  </modules>
56
  </translate>
 
 
 
 
 
 
 
57
  </adminhtml>
58
  <admin>
59
  <routers>
2
  <config>
3
  <modules>
4
  <Emv_Core>
5
+ <version>0.3.0</version>
6
  </Emv_Core>
7
  </modules>
8
  <global>
27
  <account>
28
  <table>emv_account</table>
29
  </account>
30
+ <dataprocessing_process>
31
+ <table>emv_dataprocessing_process</table>
32
+ </dataprocessing_process>
33
  </entities>
34
  </emvcore_mysql4>
35
  </models>
57
  </Emv_Core>
58
  </modules>
59
  </translate>
60
+ <layout>
61
+ <updates>
62
+ <emvcore>
63
+ <file>smartfocus/core.xml</file>
64
+ </emvcore>
65
+ </updates>
66
+ </layout>
67
  </adminhtml>
68
  <admin>
69
  <routers>
app/code/community/Emv/Core/functions.php ADDED
@@ -0,0 +1,118 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Custom error handler
4
+ * Overwrite Magento standard error handler in order to remove lock file in case of fatal error
5
+ *
6
+ * @param integer $errno
7
+ * @param string $errstr
8
+ * @param string $errfile
9
+ * @param integer $errline
10
+ * @throws Exception
11
+ */
12
+ function smartFocusErrorHandler($errno, $errstr, $errfile, $errline){
13
+ if (strpos($errstr, 'DateTimeZone::__construct')!==false) {
14
+ // there's no way to distinguish between caught system exceptions and warnings
15
+ return false;
16
+ }
17
+
18
+ $errno = $errno & error_reporting();
19
+ if ($errno == 0) {
20
+ return false;
21
+ }
22
+ if (!defined('E_STRICT')) {
23
+ define('E_STRICT', 2048);
24
+ }
25
+ if (!defined('E_RECOVERABLE_ERROR')) {
26
+ define('E_RECOVERABLE_ERROR', 4096);
27
+ }
28
+ if (!defined('E_DEPRECATED')) {
29
+ define('E_DEPRECATED', 8192);
30
+ }
31
+
32
+ // PEAR specific message handling
33
+ if (stripos($errfile.$errstr, 'pear') !== false) {
34
+ // ignore strict and deprecated notices
35
+ if (($errno == E_STRICT) || ($errno == E_DEPRECATED)) {
36
+ return true;
37
+ }
38
+ // ignore attempts to read system files when open_basedir is set
39
+ if ($errno == E_WARNING && stripos($errstr, 'open_basedir') !== false) {
40
+ return true;
41
+ }
42
+ }
43
+
44
+ $errorMessage = '';
45
+
46
+ switch($errno){
47
+ case E_ERROR:
48
+ $errorMessage .= "Error";
49
+ break;
50
+ case E_WARNING:
51
+ $errorMessage .= "Warning";
52
+ break;
53
+ case E_PARSE:
54
+ $errorMessage .= "Parse Error";
55
+ break;
56
+ case E_NOTICE:
57
+ $errorMessage .= "Notice";
58
+ break;
59
+ case E_CORE_ERROR:
60
+ $errorMessage .= "Core Error";
61
+ break;
62
+ case E_CORE_WARNING:
63
+ $errorMessage .= "Core Warning";
64
+ break;
65
+ case E_COMPILE_ERROR:
66
+ $errorMessage .= "Compile Error";
67
+ break;
68
+ case E_COMPILE_WARNING:
69
+ $errorMessage .= "Compile Warning";
70
+ break;
71
+ case E_USER_ERROR:
72
+ $errorMessage .= "User Error";
73
+ break;
74
+ case E_USER_WARNING:
75
+ $errorMessage .= "User Warning";
76
+ break;
77
+ case E_USER_NOTICE:
78
+ $errorMessage .= "User Notice";
79
+ break;
80
+ case E_STRICT:
81
+ $errorMessage .= "Strict Notice";
82
+ break;
83
+ case E_RECOVERABLE_ERROR:
84
+ $errorMessage .= "Recoverable Error";
85
+ break;
86
+ case E_DEPRECATED:
87
+ $errorMessage .= "Deprecated functionality";
88
+ break;
89
+ default:
90
+ $errorMessage .= "Unknown error ($errno)";
91
+ break;
92
+ }
93
+
94
+ $errorMessage .= ": {$errstr} in {$errfile} on line {$errline}";
95
+ if (Mage::getIsDeveloperMode()) {
96
+ throw new Exception($errorMessage);
97
+ } else {
98
+ Mage::log($errorMessage, Zend_Log::ERR);
99
+
100
+ // this is specifically to our connector
101
+ Mage::helper('emvcore')->removeLastLockFileFromRegistry();
102
+ }
103
+ }
104
+
105
+ /**
106
+ * Customer shut down PHP handler in order to remove lock file
107
+ */
108
+ function smartFocusShutDownPhpHandler()
109
+ {
110
+ $error = error_get_last();
111
+ if (null !== $error)
112
+ {
113
+ Mage::log($error, Zend_Log::ERR);
114
+
115
+ // this is specifically to our connector
116
+ Mage::helper('emvcore')->removeLastLockFileFromRegistry();
117
+ }
118
+ }
app/code/community/Emv/Core/sql/emvcore_setup/mysql4-upgrade-0.2.0-0.3.0.php ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $this Emv_Emt_Model_Resource_Setup */
3
+ $this->startSetup();
4
+
5
+ $this->run("
6
+ DROP TABLE IF EXISTS `{$this->getTable('emvcore/dataprocessing_process')}`;
7
+ CREATE TABLE `{$this->getTable('emvcore/dataprocessing_process')}` (
8
+
9
+ `id` int(10) unsigned NOT NULL AUTO_INCREMENT,
10
+ `type` varchar(255) NOT NULL,
11
+ `title` TEXT NOT NULL,
12
+ `created_at` datetime NOT NULL,
13
+ `updated_at` datetime NULL,
14
+ `terminated_at` datetime NULL,
15
+ `state` int(10) DEFAULT '0',
16
+ `status` int(1) DEFAULT '0',
17
+ `output_information` TEXT NULL,
18
+
19
+ PRIMARY KEY (`id`),
20
+ INDEX `IDX_PROCESS_STATE` (`state`),
21
+ INDEX `IDX_PROCESS_TYPE` (`type`)
22
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8;
23
+
24
+ ");
25
+
26
+ $this->endSetup();
app/code/community/Emv/DataSync/Block/Adminhtml/Form/Field/CustomerAttributes.php CHANGED
@@ -9,48 +9,14 @@
9
  class Emv_DataSync_Block_Adminhtml_Form_Field_CustomerAttributes extends Mage_Core_Block_Html_Select
10
  {
11
  /**
12
- * @var array
 
 
13
  */
14
- protected $_customerAttributes;
15
-
16
- /**
17
- * Get customer attributes array
18
- * @param string $attributeId
19
- * @return NULL|Ambigous <multitype:, string>
20
- */
21
- protected function _getCustomerAttributes($attributeId = null)
22
  {
23
- if (is_null($this->_customerAttributes)) {
24
- $this->_customerAttributes = array();
25
- $customerEntityTypeId = Mage::getModel('eav/entity')->setType('customer')->getTypeId();
26
- $customerAddressEntityTypeId = Mage::getModel('eav/entity')->setType('customer_address')->getTypeId();
27
- $collection = Mage::getResourceModel('eav/entity_attribute_collection')
28
- ->addFieldToFilter(
29
- 'entity_type_id',
30
- array(
31
- 'in' => array($customerEntityTypeId, $customerAddressEntityTypeId)
32
- )
33
- );
34
-
35
- if ($collection && $collection->count()>0) {
36
- foreach ($collection as $item) {
37
- if ($item->getEntityTypeId() == $customerAddressEntityTypeId) {
38
- $this->_customerAttributes[$item->getAttributeId()] = 'customer_address_'
39
- . $item->getAttributeCode();
40
- }
41
- else {
42
- $this->_customerAttributes[$item->getAttributeId()] = $item->getAttributeCode();
43
- }
44
- }
45
- asort($this->_customerAttributes);
46
- }
47
- }
48
-
49
- if (!is_null($attributeId)) {
50
- return isset($this->_customerAttributes[$attributeId]) ? $this->_customerAttributes[$attributeId] : null;
51
- }
52
-
53
- return $this->_customerAttributes;
54
  }
55
 
56
  /**
@@ -69,8 +35,8 @@ class Emv_DataSync_Block_Adminhtml_Form_Field_CustomerAttributes extends Mage_Co
69
  public function _toHtml()
70
  {
71
  if (!$this->getOptions()) {
72
- foreach ($this->_getCustomerAttributes() as $attributeId => $attributeCode) {
73
- $this->addOption($attributeId, addslashes($attributeCode));
74
  }
75
  }
76
 
9
  class Emv_DataSync_Block_Adminhtml_Form_Field_CustomerAttributes extends Mage_Core_Block_Html_Select
10
  {
11
  /**
12
+ * Get available attributes array
13
+ *
14
+ * @return array
15
  */
16
+ protected function _getCustomerAttributes()
 
 
 
 
 
 
 
17
  {
18
+ $config = Mage::getModel('emvdatasync/attributeProcessing_config');
19
+ return $config->toOptionArray();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
20
  }
21
 
22
  /**
35
  public function _toHtml()
36
  {
37
  if (!$this->getOptions()) {
38
+ foreach ($this->_getCustomerAttributes() as $type => $optionValue) {
39
+ $this->addOption($optionValue['value'], addslashes($optionValue['label']));
40
  }
41
  }
42
 
app/code/community/Emv/DataSync/Block/Adminhtml/Newsletter/Subscriber.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Subscriber Queue grid container
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_DataSync_Block_Adminhtml_Newsletter_Subscriber extends Mage_Adminhtml_Block_Widget_Grid_Container
11
+ {
12
+ /**
13
+ * Construct Newsletter Subscriber Queue menu
14
+ * @see Mage_Adminhtml_Block_Widget_Grid_Container::__construct()
15
+ */
16
+ public function __construct()
17
+ {
18
+ parent::__construct();
19
+ $this->_blockGroup = 'emvdatasync';
20
+ $this->_controller = 'adminhtml_newsletter_subscriber';
21
+ $this->_headerText = Mage::helper('emvdatasync')->__('Newsletter Subscriber Queue');
22
+ $this->_removeButton('add');
23
+ }
24
+ }
app/code/community/Emv/DataSync/Block/Adminhtml/Newsletter/Subscriber/Grid.php ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Block to manage the subscriber queue
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_DataSync_Block_Adminhtml_Newsletter_Subscriber_Grid extends Mage_Adminhtml_Block_Newsletter_Subscriber_Grid
11
+ {
12
+ /**
13
+ * Constructor
14
+ *
15
+ * Set main configuration of grid
16
+ */
17
+ public function __construct()
18
+ {
19
+ Mage_Adminhtml_Block_Widget_Grid::__construct();
20
+ $this->setId('subscriberGrid');
21
+ $this->setUseAjax(true);
22
+ $this->setDefaultSort('queued', 'desc');
23
+ }
24
+
25
+ /**
26
+ * Prepare collection for grid
27
+ *
28
+ * @return Mage_Adminhtml_Block_Widget_Grid
29
+ */
30
+ protected function _prepareCollection()
31
+ {
32
+ $collection = Mage::getResourceSingleton('newsletter/subscriber_collection');
33
+ /* @var $collection Mage_Newsletter_Model_Mysql4_Subscriber_Collection */
34
+ $collection
35
+ ->showCustomerInfo(true)
36
+ ->addSubscriberTypeField()
37
+ ->showStoreInfo();
38
+
39
+ if (Mage::getSingleton('emvdatasync/service_dataProcess')->enabledPurchaseInformation()) {
40
+ $expression = sprintf("IF(%s, %s, %s)", 'purchase.updated_at > main_table.date_last_purchase', 1, 0);
41
+ $checkSql = new Zend_Db_Expr($expression);
42
+
43
+ $tableName = Mage::getSingleton('core/resource')->getTableName('emvdatasync/purchase_info');
44
+
45
+ $collection->getSelect()
46
+ ->joinLeft(
47
+ array('purchase' => $tableName),
48
+ 'purchase.customer_id = main_table.customer_id',
49
+ array('purchase_validity' => $checkSql)
50
+ )
51
+ ;
52
+ $collection->addFilterToMap('purchase_validity', $checkSql);
53
+ }
54
+
55
+ $this->setCollection($collection);
56
+
57
+ Mage_Adminhtml_Block_Widget_Grid::_prepareCollection();
58
+ return $this;
59
+ }
60
+
61
+ /**
62
+ * Prepare columns for grid
63
+ * (non-PHPdoc)
64
+ * @see Mage_Adminhtml_Block_Newsletter_Subscriber_Grid::_prepareColumns()
65
+ */
66
+ protected function _prepareColumns()
67
+ {
68
+ $this->addColumn('subscriber_id', array(
69
+ 'header' => Mage::helper('newsletter')->__('ID'),
70
+ 'index' => 'subscriber_id',
71
+ 'width' => '10px',
72
+ 'type' => 'number'
73
+ ));
74
+
75
+ $this->addColumn('queued', array(
76
+ 'header' => Mage::helper('emvdatasync')->__('Scheduled'),
77
+ 'width' => '10',
78
+ 'index' => 'queued',
79
+ 'default' => Mage::helper('core')->__('No'),
80
+ 'type' => 'options',
81
+ 'options' => array(
82
+ 1 => Mage::helper('core')->__('Yes'),
83
+ 0 => Mage::helper('core')->__('No'),
84
+ ),
85
+ ));
86
+
87
+ $this->addColumn('email', array(
88
+ 'header' => Mage::helper('newsletter')->__('Email'),
89
+ 'index' => 'subscriber_email',
90
+ 'width' => '30',
91
+ ));
92
+
93
+ $this->addColumn('type', array(
94
+ 'header' => Mage::helper('newsletter')->__('Type'),
95
+ 'index' => 'type',
96
+ 'type' => 'options',
97
+ 'options' => array(
98
+ 1 => Mage::helper('newsletter')->__('Guest'),
99
+ 2 => Mage::helper('newsletter')->__('Customer')
100
+ ),
101
+ 'width' => '30',
102
+ ));
103
+
104
+ $this->addColumn('firstname', array(
105
+ 'header' => Mage::helper('newsletter')->__('Customer First Name'),
106
+ 'index' => 'customer_firstname',
107
+ 'default' => '----'
108
+ ));
109
+
110
+ $this->addColumn('lastname', array(
111
+ 'header' => Mage::helper('newsletter')->__('Customer Last Name'),
112
+ 'index' => 'customer_lastname',
113
+ 'default' => '----'
114
+ ));
115
+
116
+ $this->addColumn('status', array(
117
+ 'header' => Mage::helper('newsletter')->__('Status'),
118
+ 'index' => 'subscriber_status',
119
+ 'type' => 'options',
120
+ 'options' => array(
121
+ Mage_Newsletter_Model_Subscriber::STATUS_NOT_ACTIVE => Mage::helper('newsletter')->__('Not Activated'),
122
+ Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED => Mage::helper('newsletter')->__('Subscribed'),
123
+ Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED => Mage::helper('newsletter')->__('Unsubscribed'),
124
+ Mage_Newsletter_Model_Subscriber::STATUS_UNCONFIRMED => Mage::helper('newsletter')->__('Unconfirmed'),
125
+ )
126
+ ));
127
+
128
+ $this->addColumn('member_last_update_date', array(
129
+ 'header' => Mage::helper('emvdatasync')->__('Last Sync'),
130
+ 'type' => 'datetime',
131
+ 'width' => '120',
132
+ 'align' => 'center',
133
+ 'index' => Emv_DataSync_Helper_Service::FIELD_MEMBER_LAST_UPDATE,
134
+ ));
135
+ $this->addColumn('data_last_update_date', array(
136
+ 'header' => Mage::helper('emvdatasync')->__('Last Data Update'),
137
+ 'type' => 'datetime',
138
+ 'width' => '120',
139
+ 'align' => 'center',
140
+ 'index' => Emv_DataSync_Helper_Service::FIELD_DATA_LAST_UPDATE,
141
+ ));
142
+
143
+ $this->addColumn('date_unjoin', array(
144
+ 'header' => Mage::helper('emvdatasync')->__('Last Unsubscription'),
145
+ 'type' => 'datetime',
146
+ 'width' => '120',
147
+ 'align' => 'center',
148
+ 'index' => Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN,
149
+ ));
150
+
151
+ $this->addColumn('store', array(
152
+ 'header' => Mage::helper('newsletter')->__('Store View'),
153
+ 'index' => 'store_id',
154
+ 'type' => 'options',
155
+ 'options' => $this->_getStoreOptions()
156
+ ));
157
+ $this->addColumn('group', array(
158
+ 'header' => Mage::helper('newsletter')->__('Store'),
159
+ 'index' => 'group_id',
160
+ 'type' => 'options',
161
+ 'options' => $this->_getStoreGroupOptions()
162
+ ));
163
+
164
+ $this->addColumn('website', array(
165
+ 'header' => Mage::helper('newsletter')->__('Website'),
166
+ 'index' => 'website_id',
167
+ 'type' => 'options',
168
+ 'options' => $this->_getWebsiteOptions()
169
+ ));
170
+
171
+ if (Mage::getSingleton('emvdatasync/service_dataProcess')->enabledPurchaseInformation()) {
172
+ $this->addColumn(
173
+ 'links',
174
+ array(
175
+ 'header' => Mage::helper('emvcore')->__('Purchase History'),
176
+ 'width' => '100px',
177
+ 'type' => 'options',
178
+ 'sortable' => false,
179
+ 'index' => 'purchase_validity',
180
+ 'options' => array(
181
+ 1 => Mage::helper('emvdatasync')->__('Yes'),
182
+ 0 => Mage::helper('emvdatasync')->__('No')
183
+ )
184
+ )
185
+ );
186
+ }
187
+
188
+ $this->addExportType('*/*/exportCsv', Mage::helper('customer')->__('CSV'));
189
+ $this->addExportType('*/*/exportXml', Mage::helper('customer')->__('Excel XML'));
190
+ return Mage_Adminhtml_Block_Widget_Grid::_prepareColumns();
191
+ }
192
+
193
+ /**
194
+ * Prepare mass action for grid
195
+ *
196
+ * (non-PHPdoc)
197
+ * @see Mage_Adminhtml_Block_Newsletter_Subscriber_Grid::_prepareMassaction()
198
+ */
199
+ protected function _prepareMassaction()
200
+ {
201
+ $this->setMassactionIdField('subscriber_id');
202
+ $this->getMassactionBlock()->setFormFieldName('subscriber');
203
+
204
+ $this->getMassactionBlock()->addItem('queue', array(
205
+ 'label' => Mage::helper('emvdatasync')->__('Schedule'),
206
+ 'confirm' => $this->__('Are you sure?'),
207
+ 'url' => $this->getUrl(
208
+ '*/*/massQueue',
209
+ array(
210
+ 'scheduled' => Emv_DataSync_Helper_Service::SCHEDULED_VALUE)
211
+ )
212
+ )
213
+ );
214
+
215
+ $this->getMassactionBlock()->addItem('remove_queue', array(
216
+ 'label' => Mage::helper('newsletter')->__('Stop'),
217
+ 'confirm' => $this->__('Are you sure?'),
218
+ 'url' => $this->getUrl(
219
+ '*/*/massQueue',
220
+ array(
221
+ 'scheduled' => Emv_DataSync_Helper_Service::NOT_SCHEDULED_VALUE)
222
+ )
223
+ )
224
+ );
225
+ $this->getMassactionBlock()->addItem('dry_test',
226
+ array(
227
+ 'label' => Mage::helper('emvdatasync')->__('Get Csv File(s)'),
228
+ 'url' => $this->getUrl('*/*/massDryTest')
229
+ )
230
+ );
231
+ $this->getMassactionBlock()->addItem('send_test',
232
+ array(
233
+ 'label' => Mage::helper('emvdatasync')->__('Manual Sync'),
234
+ 'confirm' => $this->__('Are you sure?'),
235
+ 'url' => $this->getUrl('*/*/sendTest')
236
+ )
237
+ );
238
+ return $this;
239
+ }
240
+
241
+ /**
242
+ * Get row class - determine the row class according to state information
243
+ *
244
+ * @param Varien_Object $emvEmt
245
+ * @return string
246
+ */
247
+ public function getRowClass(Varien_Object $row)
248
+ {
249
+ $class = "";
250
+ if ($row->getData('purchase_validity') == 1) {
251
+ $class= "on-progress";
252
+ }
253
+ return $class;
254
+ }
255
+ }
app/code/community/Emv/DataSync/Block/Adminhtml/System/Config/CustomerAttributes.php CHANGED
@@ -21,7 +21,7 @@ class Emv_DataSync_Block_Adminhtml_System_Config_CustomerAttributes
21
 
22
  public function __construct()
23
  {
24
- $this->setTemplate('emailvision/datasync/system/config/form/field/array.phtml');
25
  parent::__construct();
26
  }
27
 
21
 
22
  public function __construct()
23
  {
24
+ $this->setTemplate('smartfocus/datasync/system/config/form/field/array.phtml');
25
  parent::__construct();
26
  }
27
 
app/code/community/Emv/DataSync/Block/Adminhtml/System/Config/GetFields.php CHANGED
@@ -11,13 +11,13 @@ class Emv_DataSync_Block_Adminhtml_System_Config_GetFields extends Mage_Adminhtm
11
  /**
12
  * Set template to itself
13
  *
14
- * @return Auguria_EmailVision_Block_Adminhtml_System_Config_GetFields
15
  */
16
  protected function _prepareLayout()
17
  {
18
  parent::_prepareLayout();
19
  if (!$this->getTemplate()) {
20
- $this->setTemplate('emailvision/datasync/system/config/getfields.phtml');
21
  }
22
  return $this;
23
  }
@@ -33,4 +33,21 @@ class Emv_DataSync_Block_Adminhtml_System_Config_GetFields extends Mage_Adminhtm
33
  {
34
  return $this->_toHtml();
35
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
36
  }
11
  /**
12
  * Set template to itself
13
  *
14
+ * @return Emv_DataSync_Block_Adminhtml_System_Config_GetFields
15
  */
16
  protected function _prepareLayout()
17
  {
18
  parent::_prepareLayout();
19
  if (!$this->getTemplate()) {
20
+ $this->setTemplate('smartfocus/datasync/system/config/getfields.phtml');
21
  }
22
  return $this;
23
  }
33
  {
34
  return $this->_toHtml();
35
  }
36
+
37
+ /**
38
+ * Get field url
39
+ *
40
+ * @return string
41
+ */
42
+ public function getGetFieldsUrl()
43
+ {
44
+ $website = $this->getRequest()->getParam('website');
45
+ $store = $this->getRequest()->getParam('store');
46
+ $url = Mage::getSingleton('adminhtml/url')->getUrl(
47
+ 'emv_datasync/dataSync/getMemberFields',
48
+ array('website'=>$website, 'store'=>$store)
49
+ );
50
+
51
+ return $url;
52
+ }
53
  }
app/code/community/Emv/DataSync/Helper/Data.php CHANGED
@@ -4,7 +4,8 @@
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
- * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
 
8
  */
9
  class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
10
  {
@@ -13,8 +14,16 @@ class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
13
  const XML_PATH_EMAIL_SYNC = 'emvdatasync/customer_mapping/email_enabled';
14
 
15
  const XML_PATH_ACCOUNT_FOR_MEMBER = 'emvdatasync/apimember/account';
 
 
16
  const XML_PATH_ACCOUNT_FOR_BATCH_MEMBER = 'emvdatasync/batchmember/account';
 
 
17
  const XML_PATH_CUSTOMER_MAPPING_ATTRIBUTES = 'emvdatasync/customer_mapping/attributes';
 
 
 
 
18
 
19
  /**
20
  * Is created folder for export data
@@ -25,7 +34,14 @@ class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
25
  /**
26
  * Lock file name pattern
27
  */
28
- const LOCK_FILE_NAME_PATTERN = 'cron_process.lock';
 
 
 
 
 
 
 
29
 
30
  /**
31
  * Check and create need folders
@@ -35,10 +51,23 @@ class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
35
  public function checkAndCreatFolder()
36
  {
37
  if ($this->_createdFolder == false) {
38
- $mageFile = new Varien_Io_File();
39
- $mageFile->checkAndCreateFolder(Mage::getBaseDir('export'));
40
- $mageFile->checkAndCreateFolder(Mage::getBaseDir('export'). DS . 'emailvision');
41
- $mageFile->checkAndCreateFolder(Mage::getBaseDir('export'). DS . 'emailvision' . DS . 'uploaded');
 
 
 
 
 
 
 
 
 
 
 
 
 
42
  $this->_createdFolder = true;
43
  }
44
  }
@@ -109,66 +138,132 @@ class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
109
  */
110
  public function saveEmailVisionFieldsInConfig($fields = array())
111
  {
 
 
112
  $config = Mage::getModel('core/config');
113
  $config->saveConfig(
114
- self::XML_PATH_EMAILVISION_FIELDS, Mage::helper('core')->jsonEncode($fields)
 
 
 
115
  );
 
116
  return $this;
117
  }
118
 
119
  /**
 
 
120
  * @return array
121
  */
122
- public function getEmailVisionFieldsFromConfig()
123
  {
124
  $fields = array();
125
- $encodedString = Mage::getStoreConfig(self::XML_PATH_EMAILVISION_FIELDS);
 
 
 
 
 
 
126
  if ($encodedString) {
 
127
  $fields = Mage::helper('core')->jsonDecode($encodedString);
128
  }
129
  return $fields;
130
  }
131
 
132
  /**
133
- * Save mapped EmailVision Entity Id
134
  *
135
- * @param string $field
136
- * @return Emv_DataSync_Helper_Data
137
- */
138
- public function saveMappedEntityId($field)
139
- {
140
- $config = Mage::getModel('core/config');
141
- $config->saveConfig(self::XML_PATH_MAPPED_ENTITY_ID, $field);
142
- return $this;
143
- }
144
-
145
- /**
146
  * @return string
147
  */
148
- public function getMappedEntityId()
149
  {
150
- return Mage::getStoreConfig(self::XML_PATH_MAPPED_ENTITY_ID);
151
  }
152
 
153
  /**
 
 
154
  * @param string $type
155
  * @param string $storeId
156
  * @return Emv_Core_Model_Account
157
  */
158
- public function getEmvAccountForStore($type = "member", $storeId = null)
159
  {
160
  $path = self::XML_PATH_ACCOUNT_FOR_MEMBER;
 
161
  if ($type == 'batch') {
162
  $path = self::XML_PATH_ACCOUNT_FOR_BATCH_MEMBER;
 
163
  }
164
 
165
- $accountId = Mage::getStoreConfig($path, $storeId);
166
  $account = Mage::getModel('emvcore/account');
167
- $account->load($accountId);
 
 
 
168
 
169
  return $account;
170
  }
171
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
172
  /**
173
  * Get mapped attributes from config
174
  *
@@ -190,4 +285,89 @@ class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
190
  {
191
  return (bool)Mage::getStoreConfig(self::XML_PATH_EMAIL_SYNC, $storeId);
192
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
193
  }
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_DataSync_Helper_Data extends Mage_Core_Helper_Abstract
11
  {
14
  const XML_PATH_EMAIL_SYNC = 'emvdatasync/customer_mapping/email_enabled';
15
 
16
  const XML_PATH_ACCOUNT_FOR_MEMBER = 'emvdatasync/apimember/account';
17
+ const XML_PATH_ENABLED_FOR_MEMBER = 'emvdatasync/apimember/enabled';
18
+
19
  const XML_PATH_ACCOUNT_FOR_BATCH_MEMBER = 'emvdatasync/batchmember/account';
20
+ const XML_PATH_ENABLED_FOR_BATCH_MEMBER = 'emvdatasync/batchmember/enabled';
21
+
22
  const XML_PATH_CUSTOMER_MAPPING_ATTRIBUTES = 'emvdatasync/customer_mapping/attributes';
23
+ const XML_PATH_ALLOWED_NUMBER_TEST = 'emvdatasync/general/test_members';
24
+
25
+ const TYPE_BATCH = 'batch';
26
+ const TYPE_MEMBER = 'member';
27
 
28
  /**
29
  * Is created folder for export data
34
  /**
35
  * Lock file name pattern
36
  */
37
+ const LOCK_FILE_NAME_PATTERN = 'data_sync_process';
38
+
39
+ /**
40
+ * Array of accounts sorted by stores
41
+ *
42
+ * @var array
43
+ */
44
+ protected $_storesAndAccounts = array();
45
 
46
  /**
47
  * Check and create need folders
51
  public function checkAndCreatFolder()
52
  {
53
  if ($this->_createdFolder == false) {
54
+ $mageFile = new Varien_Io_File();
55
+ // check and create base container dir
56
+ $mageFile->checkAndCreateFolder(Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER));
57
+
58
+ // check and create base working dir
59
+ $mageFile->checkAndCreateFolder(
60
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
61
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
62
+ );
63
+
64
+ // check and create uploaded dir
65
+ $mageFile->checkAndCreateFolder(
66
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
67
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
68
+ . DS . Emv_Core_Helper_Data::UPLOADED_FILE_DIR
69
+ );
70
+
71
  $this->_createdFolder = true;
72
  }
73
  }
138
  */
139
  public function saveEmailVisionFieldsInConfig($fields = array())
140
  {
141
+ $scopeData = Mage::helper('emvcore')->getAdminScope();
142
+
143
  $config = Mage::getModel('core/config');
144
  $config->saveConfig(
145
+ self::XML_PATH_EMAILVISION_FIELDS,
146
+ Mage::helper('core')->jsonEncode($fields),
147
+ $scopeData['scope'],
148
+ $scopeData['scope_id']
149
  );
150
+
151
  return $this;
152
  }
153
 
154
  /**
155
+ * Get SmartFocus fields from configuration
156
+ *
157
  * @return array
158
  */
159
+ public function getEmailVisionFieldsFromConfig($fromAdminScopeConfig = true, $storeId = null)
160
  {
161
  $fields = array();
162
+
163
+ if ($fromAdminScopeConfig) {
164
+ $encodedString = Mage::helper('emvcore')->getAdminScopedConfig(self::XML_PATH_EMAILVISION_FIELDS);
165
+ } else {
166
+ $encodedString = Mage::getStoreConfig(self::XML_PATH_EMAILVISION_FIELDS, $storeId);
167
+ }
168
+
169
  if ($encodedString) {
170
+ // the fields are serialized in JSON format
171
  $fields = Mage::helper('core')->jsonDecode($encodedString);
172
  }
173
  return $fields;
174
  }
175
 
176
  /**
177
+ * Get mapped entity id
178
  *
179
+ * @param string $storeId
 
 
 
 
 
 
 
 
 
 
180
  * @return string
181
  */
182
+ public function getMappedEntityId($storeId = null)
183
  {
184
+ return Mage::getStoreConfig(self::XML_PATH_MAPPED_ENTITY_ID, $storeId);
185
  }
186
 
187
  /**
188
+ * Get only activate account for store (if enabled is set to yes) for a type
189
+ *
190
  * @param string $type
191
  * @param string $storeId
192
  * @return Emv_Core_Model_Account
193
  */
194
+ public function getEmvAccountForStore($type = self::TYPE_MEMBER, $storeId = null)
195
  {
196
  $path = self::XML_PATH_ACCOUNT_FOR_MEMBER;
197
+ $enabledPath = self::XML_PATH_ENABLED_FOR_MEMBER;
198
  if ($type == 'batch') {
199
  $path = self::XML_PATH_ACCOUNT_FOR_BATCH_MEMBER;
200
+ $enabledPath = self::XML_PATH_ENABLED_FOR_BATCH_MEMBER;
201
  }
202
 
 
203
  $account = Mage::getModel('emvcore/account');
204
+ if (Mage::getStoreConfig($enabledPath, $storeId)) {
205
+ $accountId = Mage::getStoreConfig($path, $storeId);
206
+ $account->load($accountId);
207
+ }
208
 
209
  return $account;
210
  }
211
 
212
+ /**
213
+ * Get all active SmartFocus accounts sorted by stores for a type
214
+ *
215
+ * @param string $type (member or batch)
216
+ * @return array
217
+ */
218
+ public function getActiveEmvAccountsForStore($type = self::TYPE_MEMBER)
219
+ {
220
+ if (!isset($this->_storesAndAccounts[$type])) {
221
+ // init array
222
+ $this->_storesAndAccounts[$type] = array();
223
+
224
+ // get XML path
225
+ $path = self::XML_PATH_ACCOUNT_FOR_MEMBER;
226
+ $enabledPath = self::XML_PATH_ENABLED_FOR_MEMBER;
227
+ if ($type == 'batch') {
228
+ $path = self::XML_PATH_ACCOUNT_FOR_BATCH_MEMBER;
229
+ $enabledPath = self::XML_PATH_ENABLED_FOR_BATCH_MEMBER;
230
+ }
231
+
232
+ // also get admin store
233
+ $stores = Mage::app()->getStores(true);
234
+ $storeIds = array_keys($stores);
235
+ $treatedAccounts = array();
236
+
237
+ foreach ($storeIds as $storeId) {
238
+ // check if this account is enabled
239
+ if (Mage::getStoreConfig($enabledPath, $storeId)) {
240
+
241
+ $accountId = Mage::getStoreConfig($path, $storeId);
242
+ if (!isset($treatedAccounts[$accountId])) {
243
+ $accountId = Mage::getStoreConfig($path, $storeId);
244
+ $account = Mage::getModel('emvcore/account');
245
+ $account->load($accountId);
246
+ if ($account->getId() && $account->getId() == $accountId) {
247
+ $this->_storesAndAccounts[$type][$accountId] = array(
248
+ 'model' => $account, 'stores' => array($storeId)
249
+ );
250
+
251
+ $treatedAccounts[$accountId] = true;
252
+ } else {
253
+ $treatedAccounts[$accountId] = false;
254
+ }
255
+ } else {
256
+ if ($treatedAccounts[$accountId]) {
257
+ $this->_storesAndAccounts[$type][$accountId]['stores'][] = $storeId;
258
+ }
259
+ }
260
+ }
261
+ }
262
+ }
263
+
264
+ return $this->_storesAndAccounts[$type];
265
+ }
266
+
267
  /**
268
  * Get mapped attributes from config
269
  *
285
  {
286
  return (bool)Mage::getStoreConfig(self::XML_PATH_EMAIL_SYNC, $storeId);
287
  }
288
+
289
+ /**
290
+ * Mass schedule a list of subscribers
291
+ *
292
+ * @param array $subscriberIds
293
+ * @param string $scheduled (take 2 values
294
+ * Emv_DataSync_Helper_Service::SCHEDULED_VALUE,
295
+ * Emv_DataSync_Helper_Service::NOT_SCHEDULED_VALUE)
296
+ * @return true
297
+ * @throws Mage_Core_Exception
298
+ */
299
+ public function massScheduleSubscriber($subscriberIds, $scheduled = Emv_DataSync_Helper_Service::SCHEDULED_VALUE)
300
+ {
301
+ if (is_array($subscriberIds) && count($subscriberIds)) {
302
+ $resource = Mage::getModel('core/resource');
303
+
304
+ $writeConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE);
305
+ $condition = $writeConnection->quoteInto('IN (?)', $subscriberIds);
306
+ $queuedField = Emv_DataSync_Helper_Service::FIELD_QUEUED;
307
+ $writeConnection->query("
308
+ UPDATE {$resource->getTableName('newsletter/subscriber')}
309
+ SET {$queuedField} = {$scheduled}
310
+ WHERE subscriber_id {$condition}
311
+ ");
312
+ } else {
313
+ Mage::throwException(Mage::helper('newsletter')->__('Please select subscriber(s)'));
314
+ }
315
+
316
+ return true;
317
+ }
318
+
319
+ /**
320
+ * Set last update purchase data for a given subscriber
321
+ *
322
+ * @param Mage_Newsletter_Model_Subscriber $subscriber
323
+ * @param string $time - GMT time
324
+ */
325
+ public function setLastUpdatePurchaseDate(Mage_Newsletter_Model_Subscriber $subscriber, $time)
326
+ {
327
+ if ($subscriber->getCustomerId() && $subscriber->getId()) {
328
+ $resource = Mage::getModel('core/resource');
329
+ $writeConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE);
330
+ $setValue = $writeConnection->quoteInto('date_last_purchase = ?', $time);
331
+
332
+ try {
333
+ $writeConnection->query("
334
+ UPDATE {$resource->getTableName('newsletter/subscriber')} subscriber
335
+ JOIN {$resource->getTableName('sales/order')} flat_order
336
+ ON subscriber.customer_id = flat_order.customer_id
337
+ SET {$setValue}
338
+ ");
339
+ } catch (Exception $e) {
340
+ Mage::logException($e);
341
+ }
342
+ }
343
+ }
344
+
345
+ /**
346
+ * Does a given customer have any order ?
347
+ *
348
+ * @param int $customerId
349
+ * @return boolean
350
+ * @throws Exception $e
351
+ */
352
+ public function doesCustomerHaveOrder($customerId)
353
+ {
354
+ $haveOrder = false;
355
+ if ($customerId && (int)$customerId > 0) {
356
+ $resource = Mage::getModel('core/resource');
357
+ $readConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_READ_RESOURCE);
358
+ $select = $readConnection->select();
359
+
360
+ $select
361
+ ->from(array('main_table' => $resource->getTableName('sales/order')), array('COUNT(*)'))
362
+ ->where("customer_id = ?", $customerId);
363
+
364
+ $orderCount = $readConnection->fetchCol($select);
365
+ if (is_array($orderCount) && count($orderCount) && $orderCount[0] > 0) {
366
+ $haveOrder = true;
367
+ }
368
+ }
369
+
370
+ return $haveOrder;
371
+ }
372
+
373
  }
app/code/community/Emv/DataSync/Helper/Service.php CHANGED
@@ -4,21 +4,11 @@
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
- * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
 
8
  */
9
  class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
10
  {
11
- /**
12
- * @var Varien_Data_Collection_Db
13
- */
14
- protected $_entityFieldsToSelect;
15
-
16
- /**
17
- * Attribute Join list
18
- * @var array
19
- */
20
- protected $_joinFactory = null;
21
-
22
  /**
23
  * @var string
24
  */
@@ -29,9 +19,20 @@ class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
29
  */
30
  protected $_customerAddressTypeId = null;
31
 
32
- const FIELD_MEMBER_LAST_UPDATE = 'member_last_update_date';
33
- const FIELD_DATA_LAST_UPDATE = 'data_last_update_date';
34
- const FIELD_DATE_UNJOIN = 'date_unjoin';
 
 
 
 
 
 
 
 
 
 
 
35
 
36
  /**
37
  * Get magento attribute for the given attribute ids
@@ -39,7 +40,7 @@ class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
39
  * @param array $attributeIds
40
  * @return Mage_Eav_Model_Resource_Entity_Attribute_Collection
41
  */
42
- public function getMagentoAttributes($attributeIds = array())
43
  {
44
  $magentoAttributes = array();
45
  $customerTypeId = $this->getCustomerTypeId();
@@ -49,189 +50,23 @@ class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
49
  ->addFieldToFilter(
50
  'entity_type_id',
51
  array('in' => array($customerTypeId, $customerAddressEntityTypeId))
52
- )
53
- ->addFieldToFilter(
54
- 'attribute_id',
55
- array('in' => $attributeIds)
56
- )
57
- ;
58
-
59
- return $collection;
60
- }
61
-
62
- /**
63
- * Prepare and get mapped customer attributes
64
- *
65
- * @return Varien_Data_Collection_Db
66
- */
67
- public function prepareAndGetMappedCustomerAttributes()
68
- {
69
- if ($this->_entityFieldsToSelect == null) {
70
- // init $this->_entityFieldsToSelect
71
- $this->_entityFieldsToSelect = new Varien_Data_Collection_Db();
72
-
73
- $mappedFields = Mage::helper('emvdatasync')->getEmvMappedCustomerAttributes();
74
- if (count($mappedFields)) {
75
- // retreive magento attribute ids
76
- $attributeIds = array();
77
- foreach ($mappedFields as $field) {
78
- $attributeIds[] = $field['magento_fields'] ;
79
- }
80
-
81
- if (count($attributeIds)) {
82
- $collection = $this->getMagentoAttributes($attributeIds);
83
- if ($collection && $collection->count() > 0) {
84
- foreach($mappedFields as $field) {
85
- $attribute = $collection->getItemById($field['magento_fields']);
86
- if ($attribute) {
87
- // need to know which SmartFocus attribute has been mapped to magento one
88
- $attribute->setEmailVisionKey($field['emailvision_fields']);
89
- }
90
- }
91
-
92
- $this->_entityFieldsToSelect = $collection;
93
- }
94
- }
95
- }
96
- }
97
-
98
- return $this->_entityFieldsToSelect;
99
- }
100
-
101
- /**
102
- * Add customer and address attributes into subscriber select
103
- *
104
- * @param Mage_Newsletter_Model_Resource_Subscriber_Collection $collection
105
- * @return Mage_Newsletter_Model_Resource_Subscriber_Collection
106
- */
107
- public function addCustomerAndAddressAttributes(Varien_Data_Collection_Db $collection)
108
- {
109
- /* @var $customerModel Mage_Customer_Model_Customer */
110
- /* @var $addressModel Mage_Customer_Model_Address */
111
- // Get connection from collection
112
- $adapter = $collection->getConnection();
113
-
114
- // Prepare required table data (id, etc...)
115
- $tablePrefix = (string)Mage::getConfig()->getTablePrefix();
116
- $customerEntityTable = $tablePrefix . 'customer_entity';
117
- $customerEavIntTable = $tablePrefix . 'customer_entity_int';
118
- $addressEntityTable = $tablePrefix . 'customer_address_entity';
119
-
120
- // Prepare Default billing attribute (customer eav, required to get only one address)
121
- $defaultBillingAttribute = Mage::getModel('customer/customer')->getAttribute('default_billing');
122
-
123
- // Get address entity type
124
- $customerAddressEntityTypeId = $this->getCustomerAddressTypeId();
125
-
126
- if (!isset($this->_joinFactory)) {
127
- // Prepare empty joinBuilder array
128
- // (customer entity must be joined in order to be able of getting address)
129
- $this->_joinFactory = array(
130
- 'entity_table' => array(
131
- $customerEntityTable => array($customerEntityTable . '.entity_id'),
132
- $addressEntityTable => array($addressEntityTable . '.entity_id')
133
- ),
134
- 'eav_tables' => array()
135
  );
136
 
137
- // Prepare a join builder array (to avoid to do a join per attribute, even on a unique table)
138
- foreach ($this->prepareAndGetMappedCustomerAttributes() as $attribute) {
139
- $tableName = $attribute->getBackend()->getTable();
140
- $tableType = 'eav_tables';
141
- $fieldPrefix = '';
142
- $preparedAttributeCode = $attribute->getAttributeCode();
143
-
144
- if ($attribute->getEntityTypeId() == $customerAddressEntityTypeId) {
145
- if (strpos($tableName, $addressEntityTable) !== false) {
146
- $preparedAttributeCode = 'customer_address_' . $preparedAttributeCode;
147
- }
148
- } else {
149
- // Check table type (entity or eav)
150
- if ($tableName == $customerEntityTable) {
151
- $tableType = 'entity_table';
152
- $fieldPrefix = $tableName . '.';
153
- }
154
-
155
- // only get store_id from newsletter subscriber table
156
- if ($attribute->getAttributeCode() == 'store_id') {
157
- continue;
158
- }
159
- }
160
-
161
- // Add current attribute as field to join
162
- $this->_joinFactory[$tableType][$tableName][$attribute->getId()]
163
- = $fieldPrefix . $attribute->getAttributeCode();
164
-
165
- // !!! use final_attribute_code to get value
166
- $attribute->setFinalAttributeCode($preparedAttributeCode);
167
- }
168
  }
169
-
170
- // Manage entities fields
171
- $collection->getSelect()
172
- // Add customer_entity fields (no aliases, an only call for all customer entity fields)
173
- ->joinLeft(
174
- $customerEntityTable,
175
- $customerEntityTable . '.entity_id = main_table.customer_id',
176
- $this->_joinFactory['entity_table'][$customerEntityTable]
177
- )
178
- // Join default billing attributes (limit address results to 1)
179
- ->joinLeft(
180
- array('default_billing_id_table' => $customerEavIntTable),
181
- $adapter->quoteInto(
182
- 'default_billing_id_table.entity_id = main_table.customer_id'
183
- . ' AND default_billing_id_table.attribute_id = ?',
184
- (int)$defaultBillingAttribute->getAttributeId()
185
- ),
186
- array('default_billing_id' => 'default_billing_id_table.value')
187
- )
188
- // Add customer address entity fields
189
- ->joinLeft(
190
- $addressEntityTable,
191
- $adapter->quoteInto(
192
- $customerEntityTable . '.entity_id = '. $addressEntityTable . '.parent_id'
193
- . ' AND '. $addressEntityTable . '.entity_id = default_billing_id_table.value'
194
- . ' AND default_billing_id_table.attribute_id = ?',
195
- (int)$defaultBillingAttribute->getAttributeId()
196
- ),
197
- $this->_joinFactory['entity_table'][$addressEntityTable]
198
- );
199
-
200
- // Join a table foreach eav attributes. Two ways, customer eav or address eav
201
- foreach ($this->_joinFactory['eav_tables'] as $tableName => $fields) {
202
- // Address eav attributes
203
- if (strpos($tableName, 'customer_address') !== false) {
204
- foreach ($fields as $fieldId => $fieldSql) {
205
- $collection->getSelect()
206
- ->joinLeft(
207
- array('customer_address_' . $fieldSql . '_table' => $tableName),
208
- $adapter->quoteInto(
209
- 'customer_address_' . $fieldSql . '_table' . '.entity_id = ' . $addressEntityTable . '.entity_id'
210
- . ' AND customer_address_' . $fieldSql . '_table' . '.attribute_id = ?',
211
- $fieldId
212
- ),
213
- array('customer_address_' . $fieldSql => 'customer_address_' . $fieldSql . '_table' . '.value')
214
- );
215
- }
216
- } else {// Customer eav attributes
217
- foreach ($fields as $fieldId => $fieldSql) {
218
- $collection->getSelect()
219
- ->joinLeft(
220
- array($fieldSql . '_table' => $tableName),
221
- $adapter->quoteInto(
222
- $fieldSql . '_table' . '.entity_id = main_table.customer_id'
223
- . ' AND ' . $fieldSql . '_table' . '.attribute_id = ?',
224
- $fieldId
225
- ),
226
- array($fieldSql => $fieldSql . '_table' . '.value')
227
- );
228
- }
229
- }
230
  }
231
 
232
- // dispatch a new event in order to add additional data if needed
233
- Mage::dispatchEvent('member_collection_load_after', array('members' => $collection));
234
-
235
  return $collection;
236
  }
237
 
@@ -273,19 +108,27 @@ class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
273
  }
274
 
275
  /**
 
 
276
  * @param array $updatedSubscribers
277
  * @param array $rejoinedSubscribers
278
  * @param string $time
279
  * @return boolean
280
  */
281
- public function massSetMemberLastUpdateDate($updatedSubscribers = array(), $rejoinedSubscribers = array(), $time = null)
 
 
 
 
282
  {
283
  $error = true;
284
 
285
- if (!empty($updatedSubscribers)) {
286
  /* @var $write Varien_Db_Adapter_Pdo_Mysql */
287
- $write = Mage::getSingleton('core/resource')->getConnection('core_write');
288
- $subscriberTable = Mage::getResourceModel('newsletter/subscriber')->getMainTable();
 
 
289
  // date should be store ind GMT timezone
290
  $now = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
291
  if ($time == null) {
@@ -293,22 +136,26 @@ class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
293
  }
294
 
295
  try {
296
- // Update memberLastUpdateDate
297
- $fieldMemberLastUpdate = self::FIELD_MEMBER_LAST_UPDATE;
298
- $sqlQuery = "UPDATE $subscriberTable SET {$fieldMemberLastUpdate} = '$time'
299
- WHERE subscriber_id IN(" . implode(',', $updatedSubscribers) . ');';
300
- $write->query($sqlQuery);
301
-
302
- if (!empty($rejoinedSubscribers)) {
303
- // Reset UnjoinDate for Rejoined subscribers
304
- $fieldUnjoinDate = self::FIELD_DATE_UNJOIN;
305
- $sqlQuery = "UPDATE $subscriberTable SET $fieldUnjoinDate = null
306
- WHERE subscriber_id IN(" . implode(',', $rejoinedSubscribers) . ');';
307
- $write->query($sqlQuery);
 
 
 
308
  }
309
  } catch (Exception $e) {
310
  Mage::logException($e);
311
- $error = 'Exception while processing massSetMemberLastUpdateDate with exceptionMessage:\n ' . $e->getMessage();
 
312
  $error .= '\n Subscribers ids detail: ' . implode(', ', $updatedSubscribers);
313
  }
314
  }
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_DataSync_Helper_Service extends Mage_Core_Helper_Abstract
11
  {
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * @var string
14
  */
19
  */
20
  protected $_customerAddressTypeId = null;
21
 
22
+ /**
23
+ * Newsletter Subscriber Additional Fields
24
+ */
25
+ const FIELD_MEMBER_LAST_UPDATE = 'member_last_update_date';
26
+ const FIELD_DATA_LAST_UPDATE = 'data_last_update_date';
27
+ const FIELD_PURCHASE_LAST_UPDATE = 'date_last_purchase';
28
+ const FIELD_DATE_UNJOIN = 'date_unjoin';
29
+ const FIELD_QUEUED = 'queued';
30
+
31
+ /**
32
+ * Values for "Queued" Field
33
+ */
34
+ const SCHEDULED_VALUE = 1;
35
+ const NOT_SCHEDULED_VALUE = 0;
36
 
37
  /**
38
  * Get magento attribute for the given attribute ids
40
  * @param array $attributeIds
41
  * @return Mage_Eav_Model_Resource_Entity_Attribute_Collection
42
  */
43
+ public function getMagentoAttributes($attributeIds = array(), $attributeCodes = array())
44
  {
45
  $magentoAttributes = array();
46
  $customerTypeId = $this->getCustomerTypeId();
50
  ->addFieldToFilter(
51
  'entity_type_id',
52
  array('in' => array($customerTypeId, $customerAddressEntityTypeId))
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
53
  );
54
 
55
+ if (count($attributeIds)) {
56
+ $collection->addFieldToFilter(
57
+ 'attribute_id',
58
+ array('in' => $attributeIds)
59
+ )
60
+ ;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
61
  }
62
+ if (count($attributeCodes)) {
63
+ $collection->addFieldToFilter(
64
+ 'attribute_code',
65
+ array('in' => $attributeCodes)
66
+ )
67
+ ;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  }
69
 
 
 
 
70
  return $collection;
71
  }
72
 
108
  }
109
 
110
  /**
111
+ * Set member last update date for a list of members (perform sql query directly)
112
+ *
113
  * @param array $updatedSubscribers
114
  * @param array $rejoinedSubscribers
115
  * @param string $time
116
  * @return boolean
117
  */
118
+ public function massSetMemberLastUpdateDate(
119
+ array $updatedSubscribers = array(),
120
+ array $rejoinedSubscribers = array(),
121
+ $time = null
122
+ )
123
  {
124
  $error = true;
125
 
126
+ if (count($updatedSubscribers) > 0) {
127
  /* @var $write Varien_Db_Adapter_Pdo_Mysql */
128
+ $resource = Mage::getSingleton('core/resource');
129
+ $write = $resource->getConnection('core_write');
130
+ $subscriberTable = $resource->getTableName('newsletter/subscriber');
131
+
132
  // date should be store ind GMT timezone
133
  $now = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
134
  if ($time == null) {
136
  }
137
 
138
  try {
139
+ // updated subscriber treatment
140
+ $set = array(
141
+ self::FIELD_MEMBER_LAST_UPDATE => $time,
142
+ self::FIELD_QUEUED => self::NOT_SCHEDULED_VALUE
143
+ );
144
+ $where = array('subscriber_id IN (?)' => $updatedSubscribers);
145
+ $write->update($subscriberTable, $set, $where);
146
+
147
+ if (count($rejoinedSubscribers) > 0) {
148
+ // rejoined subscriber treatment
149
+ $set = array(
150
+ self::FIELD_DATE_UNJOIN => null,
151
+ );
152
+ $where = array('subscriber_id IN (?)' => $rejoinedSubscribers);
153
+ $write->update($subscriberTable, $set, $where);
154
  }
155
  } catch (Exception $e) {
156
  Mage::logException($e);
157
+ $error = 'Exception while processing massSetMemberLastUpdateDate with exceptionMessage:\n '
158
+ . $e->getMessage();
159
  $error .= '\n Subscribers ids detail: ' . implode(', ', $updatedSubscribers);
160
  }
161
  }
app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/BatchMember/Cron.php CHANGED
@@ -6,57 +6,11 @@
6
  * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
- class Emv_DataSync_Model_Adminhtml_System_Config_Backend_BatchMember_Cron extends Mage_Core_Model_Config_Data
10
  {
11
  /**
 
12
  * @var string
13
  */
14
  protected $_crontabPath = 'crontab/jobs/emailvision_batchmember_export/schedule/cron_expr';
15
-
16
- /**
17
- * Save a formated crontime in core_config_data
18
- *
19
- * @see Mage_Core_Model_Abstract::_afterSave()
20
- */
21
- protected function _afterSave()
22
- {
23
- $cronConfigModel = Mage::getModel('core/config_data')
24
- ->load($this->_crontabPath, 'path');
25
-
26
- // if the cron is disabled, we remove the cron expression to avoid launching it again
27
- $enabled = $this->getFieldsetDataValue('enabled');
28
- if (!$enabled) {
29
- if ($cronConfigModel->getConfigId()) {
30
- $cronConfigModel->delete();
31
- }
32
- return;
33
- }
34
-
35
- $frequencyDaily = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_DAILY;
36
- $frequencyWeekly = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_WEEKLY;
37
- $frequencyMonthly = Mage_Adminhtml_Model_System_Config_Source_Cron_Frequency::CRON_MONTHLY;
38
-
39
- // get time and frequency
40
- $time = $this->getFieldsetDataValue('time');
41
- $frequency = $this->getFieldsetDataValue('frequency');
42
-
43
- // build cron expression string
44
- $cronExprArray = array(
45
- intval($time[1]), // Minute
46
- intval($time[0]), // Hour
47
- ($frequency == $frequencyMonthly) ? '1' : '*', // Day of the Month
48
- '*', // Month of the Year
49
- ($frequency == $frequencyWeekly) ? '1' : '*', // Day of the Week
50
- );
51
- $cronExprString = join(' ', $cronExprArray);
52
-
53
- try {
54
- $cronConfigModel
55
- ->setValue($cronExprString)
56
- ->setPath($this->_crontabPath)
57
- ->save();
58
- } catch (Exception $e) {
59
- Mage::throwException(Mage::helper('emvdatasync')->__('Unable to save the cron expression for scheduled exports'));
60
- }
61
- }
62
  }
6
  * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
+ class Emv_DataSync_Model_Adminhtml_System_Config_Backend_BatchMember_Cron extends Emv_Core_Model_Adminhtml_System_Config_Backend_Cron
10
  {
11
  /**
12
+ * Crontab expression path - please define an appropriate path in order to make this backend work
13
  * @var string
14
  */
15
  protected $_crontabPath = 'crontab/jobs/emailvision_batchmember_export/schedule/cron_expr';
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/Clean/Cron.php CHANGED
@@ -6,10 +6,11 @@
6
  * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
- class Emv_DataSync_Model_Adminhtml_System_Config_Backend_Clean_Cron extends Emv_DataSync_Model_Adminhtml_System_Config_Backend_BatchMember_Cron
 
10
  {
11
  /**
12
  * @var string
13
  */
14
- protected $_crontabPath = 'crontab/jobs/emailvision_clean/schedule/cron_expr';
15
  }
6
  * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  */
9
+ class Emv_DataSync_Model_Adminhtml_System_Config_Backend_Clean_Cron
10
+ extends Emv_Core_Model_Adminhtml_System_Config_Backend_Cron
11
  {
12
  /**
13
  * @var string
14
  */
15
+ protected $_crontabPath = 'crontab/jobs/emailvision_batchmember_cleanning/schedule/cron_expr';
16
  }
app/code/community/Emv/DataSync/Model/Adminhtml/System/Config/Backend/PurchaseProcess/Cron.php ADDED
@@ -0,0 +1,59 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Cron Expression for Triggered Export
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ */
9
+ class Emv_DataSync_Model_Adminhtml_System_Config_Backend_PurchaseProcess_Cron extends Mage_Core_Model_Config_Data
10
+ {
11
+ /**
12
+ * @var string
13
+ */
14
+ protected $_crontabPath = 'crontab/jobs/emailvision_purchase_process/schedule/cron_expr';
15
+
16
+ /**
17
+ * Save a formated crontime in core_config_data
18
+ *
19
+ * @see Mage_Core_Model_Abstract::_afterSave()
20
+ */
21
+ protected function _afterSave()
22
+ {
23
+ $cronConfigModel = Mage::getModel('core/config_data')
24
+ ->load($this->_crontabPath, 'path');
25
+
26
+ // if the cron is disabled, we remove the cron expression to avoid launching it again
27
+ $enabled = $this->getFieldsetDataValue('enabled');
28
+ if (!$enabled) {
29
+ if ($cronConfigModel->getConfigId()) {
30
+ $cronConfigModel->delete();
31
+ }
32
+ return;
33
+ }
34
+
35
+ $cronExprArray = array(
36
+ 'quarter_hour' => '*/15 * * * *',
37
+ 'half_hour' => '*/30 * * * *',
38
+ 'hour' => '0 * * * *',
39
+ 'two_hours' => '0 */2 * * *',
40
+ 'four_hours' => '0 */4 * * *',
41
+ 'six_hours' => '0 */6 * * *',
42
+ 'twelve_hours' => '0 */12 * * *',
43
+ 'daily' => '0 0 * * *',
44
+ );
45
+
46
+ $cronExprString = $cronExprArray[$this->getValue()];
47
+ try {
48
+ $cronConfigModel
49
+ ->setValue($cronExprString)
50
+ ->setPath($this->_crontabPath)
51
+ ->save();
52
+ } catch (Exception $e) {
53
+ Mage::throwException(Mage::helper('emvdatasync')->__('Unable to save the cron expression for purchase process'));
54
+ }
55
+
56
+ parent::_afterSave();
57
+ }
58
+
59
+ }
app/code/community/Emv/DataSync/Model/AttributeProcessing/Config.php ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Attribute handler config for data sync
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_DataSync_Model_AttributeProcessing_Config
11
+ {
12
+ const XML_PATH_ATTRIBUTE_CONFIG = 'global/smartfocus_attribute_processing';
13
+
14
+ /**
15
+ * Default attribute handler model
16
+ */
17
+ const DEFAULT_HANDLER_MODEL = 'emvdatasync/attributeProcessing_handler_customer';
18
+
19
+ /**
20
+ * Config node that stores available attribute handlers
21
+ *
22
+ * @var Mage_Core_Model_Config_Element
23
+ */
24
+ protected $_configNode;
25
+
26
+ /**
27
+ * List of attribute handlers
28
+ * @var array
29
+ */
30
+ protected $_handlerList = array();
31
+
32
+ /**
33
+ * Attributes to be selected
34
+ *
35
+ * @var array
36
+ */
37
+ protected $_attributesToSelect = array();
38
+
39
+ /**
40
+ * Attributes, fields sorted by handlers
41
+ *
42
+ * @var array
43
+ */
44
+ protected $_attributesByHandlers = array();
45
+
46
+ /**
47
+ * Store information
48
+ * @var array
49
+ */
50
+ protected $_stores;
51
+
52
+ /**
53
+ * constructor
54
+ *
55
+ * @return void
56
+ */
57
+ public function __construct()
58
+ {
59
+ $this->_loadHandlerConfig();
60
+ }
61
+
62
+ /**
63
+ * Load all attribute handler from config xml
64
+ */
65
+ protected function _loadHandlerConfig()
66
+ {
67
+ $this->_handlerList = array();
68
+ $this->_handlerList['default'] = Mage::getSingleton(self::DEFAULT_HANDLER_MODEL);
69
+ foreach($this->getConfigNode()->children() as $code => $modelClassName)
70
+ {
71
+ $model = Mage::getSingleton($modelClassName);
72
+ if ($model instanceof Emv_DataSync_Model_AttributeProcessing_Handler_Abstract) {
73
+ $this->_handlerList[$code] = $model;
74
+ }
75
+ }
76
+ }
77
+
78
+ /**
79
+ * Get handler list
80
+ *
81
+ * @return array
82
+ */
83
+ public function getHandlerList()
84
+ {
85
+ return $this->_handlerList;
86
+ }
87
+
88
+ /**
89
+ * Get config node that contains available attribute handlers from config xml
90
+ *
91
+ * @return Mage_Core_Model_Config_Element
92
+ */
93
+ public function getConfigNode()
94
+ {
95
+ if (is_null($this->_configNode)) {
96
+ $this->_configNode = Mage::app()->getConfig()->getNode(self::XML_PATH_ATTRIBUTE_CONFIG);
97
+ }
98
+ return $this->_configNode;
99
+ }
100
+
101
+ /**
102
+ * Get all attribute option array
103
+ *
104
+ * @return array
105
+ */
106
+ public function toOptionArray()
107
+ {
108
+ $arrayReturn = array();
109
+ foreach($this->getHandlerList() as $model) {
110
+ $arrayReturn = array_merge($arrayReturn, $model->toOptionArray());
111
+ }
112
+ return $arrayReturn;
113
+ }
114
+
115
+ /**
116
+ * @param string $default
117
+ * @return string
118
+ */
119
+ public static function getArrayKey($default)
120
+ {
121
+ $arrayKey = $default;
122
+ if ($arrayKey === null) {
123
+ $arrayKey = 'undefined';
124
+ }
125
+ return $arrayKey;
126
+ }
127
+
128
+ /**
129
+ * Prepare and get mapped customer attributes for a given store
130
+ *
131
+ * @param string $storeId
132
+ * @return array
133
+ */
134
+ public function prepareAndGetMappedCustomerAttributes($storeId = null)
135
+ {
136
+ // by default the key will be store id, else will be set to undefined
137
+ $arrayKey = self::getArrayKey($storeId);
138
+
139
+ if (!isset($this->_attributesToSelect[$arrayKey])) {
140
+ // init $this->_entityFieldsToSelect
141
+ $this->_attributesToSelect[$arrayKey] = array();
142
+ $this->_attributesByHandlers[$arrayKey] = array();
143
+
144
+ $mappedAttributes = Mage::helper('emvdatasync')->getEmvMappedCustomerAttributes($storeId);
145
+ if (count($mappedAttributes)) {
146
+ $preparedArray = $this->_prepareAttributes($mappedAttributes, $storeId);
147
+ $this->_attributesToSelect[$arrayKey] = $preparedArray['mapped_attributes'];
148
+ $this->_attributesByHandlers[$arrayKey] = $preparedArray['attributes_by_handler'];
149
+ }
150
+ }
151
+
152
+ return $this->_attributesToSelect[$arrayKey];
153
+ }
154
+
155
+ /**
156
+ * @param array $mappedAttributes
157
+ * @param int $storeId
158
+ * @return array - associative array
159
+ * mapped_attributes => all mapped attributes
160
+ * attributes_by_handler => attributes sorted by handlers
161
+ */
162
+ protected function _prepareAttributes($mappedAttributes, $storeId)
163
+ {
164
+ $attributesByHandlers = array();
165
+
166
+ foreach ($mappedAttributes as $key => $field) {
167
+ // the field follows one of these patterns :
168
+ // billing|1, shipping|2, customer|1, newsletter|subscriber_email
169
+ $info = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::getAttributeConfigParts(
170
+ $field['magento_fields']
171
+ );
172
+
173
+ // create a new object
174
+ $fieldObject = new Varien_Object();
175
+
176
+ // !!! use final_attribute_code to get value
177
+ $fieldObject->setFinalAttributeCode($info['name']);
178
+
179
+ // need to know which SmartFocus attribute has been mapped to magento one
180
+ $fieldObject->setMappedEmailVisionKey($field['emailvision_fields']);
181
+ $fieldObject->setMappedAttributeId($info['name']);
182
+ $fieldObject->setMappedEntityType($info['prefix']);
183
+ $fieldObject->setMappedMagentoFields($field['magento_fields']);
184
+ $mappedAttributes[$key] = $fieldObject;
185
+
186
+ foreach ($this->getHandlerList() as $name => $handler) {
187
+ // test handler can handle this mapped attribute
188
+ if ($handler->canHandle($info, $storeId)) {
189
+ if (!isset($attributesByHandlers[$name])) {
190
+ $attributesByHandlers[$name] = array();
191
+ }
192
+ $attributesByHandlers[$name][$info['name']] = $fieldObject;
193
+ }
194
+ }
195
+ }
196
+
197
+ foreach ($this->getHandlerList() as $name => $handler) {
198
+ if (isset($attributesByHandlers[$name])) {
199
+ $handler->postPrepareAttribute($attributesByHandlers[$name]);
200
+ }
201
+ }
202
+
203
+ return array('mapped_attributes' => $mappedAttributes, 'attributes_by_handler' => $attributesByHandlers);
204
+ }
205
+
206
+ /**
207
+ * Prepare subscriber collection according to mapped attributes. A event called member_collection_load_after will
208
+ * be dispatched with collection and store id data
209
+ *
210
+ * @param Varien_Data_Collection_Db $collection
211
+ * @param string $storeId
212
+ * @return Varien_Data_Collection_Db
213
+ */
214
+ public function prepareSubscriberCollection(
215
+ Varien_Data_Collection_Db $collection,
216
+ $storeId = null
217
+ )
218
+ {
219
+ // by default the key will be store id, else will be set to undefined
220
+ $arrayKey = self::getArrayKey($storeId);
221
+ $this->prepareAndGetMappedCustomerAttributes($storeId);
222
+ foreach ($this->getHandlerList() as $name => $handler) {
223
+ if (
224
+ isset($this->_attributesByHandlers[$arrayKey])
225
+ && isset($this->_attributesByHandlers[$arrayKey][$name])
226
+ ) {
227
+ $handler->prepareSubscriberCollection(
228
+ $collection,
229
+ $this->_attributesByHandlers[$arrayKey][$name],
230
+ $storeId
231
+ );
232
+ }
233
+ }
234
+
235
+ // dispatch a new event in order to add additional data if needed
236
+ Mage::dispatchEvent('member_collection_load_after', array('members' => $collection, 'store_id' => $storeId));
237
+
238
+ return $collection;
239
+ }
240
+
241
+ /**
242
+ * Get subscriber data according to mapped attributes
243
+ *
244
+ * @param Varien_Object $subscriber
245
+ * @param string $storeId
246
+ * @return array
247
+ */
248
+ public function getSubscriberData(Varien_Object $subscriber, $storeId = null)
249
+ {
250
+ // Get mapped SmartFocus entity id
251
+ $entityId = strtoupper(Mage::helper('emvdatasync')->getMappedEntityId($storeId));
252
+
253
+ if (is_null($this->_stores)) {
254
+ $this->_stores = Mage::app()->getStores(true);
255
+ }
256
+
257
+ // Prepare and add a customer's data row
258
+ $subscriberData = array();
259
+
260
+ // retreive all maped attribute values from subscriber, build them into array
261
+ $fieldsToSelect = $this->prepareAndGetMappedCustomerAttributes($storeId);
262
+
263
+ foreach ($fieldsToSelect as $attribute) {
264
+ $emailVisionKey = strtoupper($attribute->getMappedEmailVisionKey());
265
+
266
+ $fieldCode = ($attribute->getFinalAttributeCode())
267
+ ? $attribute->getFinalAttributeCode() : $attribute->getAttributeCode();
268
+ $fieldValue = '';
269
+
270
+ if ($attribute->getMappedDataType() == 'datetime') {
271
+ if ($subscriber->getData($fieldCode)) {
272
+ // date time should be in EmailVision format
273
+ $fieldValue = Mage::helper('emvdatasync/service')
274
+ ->getEmailVisionDate($subscriber->getData($fieldCode));
275
+ }
276
+ } else {
277
+ $fieldValue = $subscriber->getData($fieldCode);
278
+ if ($fieldCode == 'store_id' && isset($stores[$fieldValue])) {
279
+ $fieldValue = $stores[$fieldValue]->getName();
280
+ }
281
+ }
282
+
283
+ $subscriberData[$emailVisionKey] = $fieldValue;
284
+ }
285
+
286
+ // entity id field
287
+ $subscriberData[$entityId] = $subscriber->getId();
288
+
289
+ // If is unjoined
290
+ $unjoinedDate = '';
291
+ if ($subscriber->getData('subscriber_status') == Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED) {
292
+ if ($subscriber->getData(Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN)) {
293
+ // date time should be in EmailVision format
294
+ $unjoinedDate = Mage::helper('emvdatasync/service')
295
+ ->getEmailVisionDate($subscriber->getData(Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN));
296
+ }
297
+ }
298
+ $subscriberData[strtoupper(Emv_Core_Model_Service_Member::FIELD_UNJOIN)] = $unjoinedDate;
299
+
300
+ return $subscriberData;
301
+ }
302
+
303
+ /**
304
+ * Clean mapped customer attributes
305
+ *
306
+ * @param string $storeId
307
+ */
308
+ public function cleanMappedCustomerAttributes($storeId = null)
309
+ {
310
+ // by default the key will be store id, else will be set to undefined
311
+ $arrayKey = $this->getArrayKey($storeId);
312
+ foreach ($this->_attributesToSelect[$arrayKey] as $key => $attribute)
313
+ {
314
+ if ($attribute->getAttributeObject()) {
315
+ $attribute->getAttributeObject()->unsetData()->unsetOldData();
316
+ }
317
+ $attribute->unsetData()->unsetOldData();
318
+ }
319
+ unset($this->_attributesToSelect[$arrayKey]);
320
+ }
321
+ }
app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Abstract.php ADDED
@@ -0,0 +1,106 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Attribute handler abstract
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_DataSync_Model_AttributeProcessing_Handler_Abstract
11
+ {
12
+ const SEPARATOR_ATTR = '|';
13
+
14
+ /**
15
+ * List of customer attribute options (html select element)
16
+ * @var array
17
+ */
18
+ protected $_optionCustomerAttributes;
19
+
20
+ /**
21
+ * Get attribute config parts
22
+ *
23
+ * @param string $mappedAttributeName
24
+ * @return array
25
+ * prefix -> prefix part
26
+ * name -> name part
27
+ */
28
+ public static function getAttributeConfigParts($mappedAttributeName)
29
+ {
30
+ $prefixPart = '';
31
+ $name = $mappedAttributeName;
32
+
33
+ $parts = explode(self::SEPARATOR_ATTR, $mappedAttributeName);
34
+ if (is_array($parts) && count($parts) == 2) {
35
+ $prefixPart = $parts[0];
36
+ $name = $parts[1];
37
+ }
38
+ return array('prefix' => $prefixPart, 'name' => $name);
39
+ }
40
+
41
+ /**
42
+ * @param string $prefix
43
+ * @param string $name
44
+ * @return string
45
+ */
46
+ public static function buildAttributeName($prefix, $name)
47
+ {
48
+ // the field follows one of these patterns :
49
+ // billing|1, shipping|2, customer|1, newsletter|subscriber_email
50
+ return $prefix . self::SEPARATOR_ATTR . $name;
51
+ }
52
+
53
+ /**
54
+ * Generic method needs to be implemented in Child class. The method indicates whether the handler
55
+ * can treat a given attribute
56
+ *
57
+ * @param array $attributeData
58
+ * @param int $storeId
59
+ * @return boolean
60
+ */
61
+ public function canHandle($attributeData, $storeId)
62
+ {
63
+ return false;
64
+ }
65
+
66
+ /**
67
+ * Apply post treatments for a given attribute list
68
+ *
69
+ * @param array $attributeList
70
+ * @return Emv_DataSync_Model_AttributeProcessing_Handler_Abstract
71
+ */
72
+ public function postPrepareAttribute(array $attributeList)
73
+ {
74
+ return $this;
75
+ }
76
+
77
+ /**
78
+ * Return a list of customer attribute options (html select element)
79
+ * Generic method needs to be implemented in Child class.
80
+ *
81
+ * @return array
82
+ */
83
+ public function toOptionArray()
84
+ {
85
+ $this->_optionCustomerAttributes = array();
86
+ return $this->_optionCustomerAttribute;
87
+ }
88
+
89
+ /**
90
+ * Prepare subscriber collection according to mapped attribute list
91
+ * Generic method needs to be implemented in Child class.
92
+ *
93
+ * @param Varien_Data_Collection_Db $collection
94
+ * @param array $attributeList
95
+ * @param string $storeId
96
+ * @return Varien_Data_Collection_Db
97
+ */
98
+ public function prepareSubscriberCollection(
99
+ Varien_Data_Collection_Db $collection,
100
+ array $attributeList,
101
+ $storeId = null
102
+ )
103
+ {
104
+ return $collection;
105
+ }
106
+ }
app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Customer.php ADDED
@@ -0,0 +1,321 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Customer Attribute handler (customer and customer address attributes)
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_DataSync_Model_AttributeProcessing_Handler_Customer
11
+ extends Emv_DataSync_Model_AttributeProcessing_Handler_Abstract
12
+ {
13
+ /**
14
+ * List of prefixes for different support entities
15
+ */
16
+ const PREFIX_CUSTOMER_ATTR = 'customer';
17
+ const PREFIX_SHIPPING_ATTR = 'shipping';
18
+ const PREFIX_BILLING_ATTR = 'billing';
19
+
20
+ const PREFIX_LABEL_CUSTOMER = 'Customer';
21
+ const PREFIX_LABEL_BILLING = 'Billing';
22
+ const PREFIX_LABEL_SHIPPING = 'Shipping';
23
+ const SEPARATOR_LABEL = ' - ';
24
+
25
+ /**
26
+ * Prohibited attributes
27
+ * @var Array
28
+ */
29
+ protected $_prohibitedAttributes = array('store_id');
30
+ protected $_joinFactory = array();
31
+
32
+ /**
33
+ * Default billing and shipping attribute id
34
+ * @var string
35
+ */
36
+ protected $_defaultBillingAttrId;
37
+ protected $_defaultShippingAttrId;
38
+
39
+ /**
40
+ * Prepare default billing and shipping attribute ids
41
+ */
42
+ public function prepareDefaultBillingAndShippingAttrId()
43
+ {
44
+ if ($this->_defaultBillingAttrId == null || $this->_defaultShippingAttrId == null) {
45
+ $attributes = Mage::helper('emvdatasync/service')->getMagentoAttributes(
46
+ array(),
47
+ array('default_billing','default_shipping')
48
+ );
49
+ foreach ($attributes as $attr) {
50
+ if ($attr->getAttributeCode() == 'default_billing') {
51
+ $this->_defaultBillingAttrId = $attr->getId();
52
+ }
53
+ if ($attr->getAttributeCode() == 'default_shipping') {
54
+ $this->_defaultShippingAttrId = $attr->getId();
55
+ }
56
+
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * (non-PHPdoc)
63
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::toOptionArray()
64
+ */
65
+ public function toOptionArray()
66
+ {
67
+ if (is_null($this->_optionCustomerAttributes)) {
68
+ $this->_optionCustomerAttributes = array();
69
+
70
+ $addressLabel = Mage::helper('emvdatasync')->__('Customer Billing Address');
71
+ $shippingAddressLabel = Mage::helper('emvdatasync')->__('Customer Shipping Address');
72
+ $customerLabel = Mage::helper('emvdatasync')->__('Customer');
73
+
74
+ $customerEntityTypeId = Mage::helper('emvdatasync/service')->getCustomerTypeId();
75
+ $customerAddressEntityTypeId = Mage::helper('emvdatasync/service')->getCustomerAddressTypeId();
76
+ $collection = Mage::helper('emvdatasync/service')->getMagentoAttributes();
77
+
78
+ if ($collection && $collection->count()>0) {
79
+ foreach ($collection as $item) {
80
+ // only take attribute isn't prohibited
81
+ if (in_array($item->getAttributeCode(),$this->_prohibitedAttributes)) {
82
+ continue;
83
+ }
84
+
85
+ // only display attributes that have a correct label
86
+ if ($item->getFrontendLabel() && $item->getFrontendInput() !== 'hidden') {
87
+ if ($item->getEntityTypeId() == $customerAddressEntityTypeId) {
88
+ if (!isset($this->_optionCustomerAttributes['customer_address'])) {
89
+ // initialize customer address attribute array
90
+ $this->_optionCustomerAttributes['customer_address'] = array(
91
+ 'value' => array(),
92
+ 'label' => $addressLabel
93
+ );
94
+ // initialize customer address attribute array
95
+ $this->_optionCustomerAttributes['customer_shipping_address'] = array(
96
+ 'value' => array(),
97
+ 'label' => $shippingAddressLabel
98
+ );
99
+ }
100
+
101
+ // billing address attribute
102
+ $finalAttributeId = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::buildAttributeName(
103
+ self::PREFIX_BILLING_ATTR,
104
+ $item->getAttributeId()
105
+ );
106
+ $this->_optionCustomerAttributes['customer_address']['value'][$finalAttributeId]
107
+ = self::PREFIX_LABEL_BILLING . self::SEPARATOR_LABEL . $item->getFrontendLabel();
108
+
109
+ // shipping address attribute
110
+ $finalAttributeId = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::buildAttributeName(
111
+ self::PREFIX_SHIPPING_ATTR,
112
+ $item->getAttributeId()
113
+ );
114
+ $this->_optionCustomerAttributes['customer_shipping_address']['value'][$finalAttributeId]
115
+ = self::PREFIX_LABEL_SHIPPING . self::SEPARATOR_LABEL . $item->getFrontendLabel();
116
+ } else {
117
+ if (!isset($this->_optionCustomerAttributes['customer'])) {
118
+ // initialize customer attribute array
119
+ $this->_optionCustomerAttributes['customer'] = array(
120
+ 'value' => array(),
121
+ 'label' => $customerLabel
122
+ );
123
+ }
124
+
125
+ $finalAttributeId = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::buildAttributeName(
126
+ self::PREFIX_CUSTOMER_ATTR,
127
+ $item->getAttributeId()
128
+ );
129
+ $this->_optionCustomerAttributes['customer']['value'][$finalAttributeId]
130
+ = self::PREFIX_LABEL_CUSTOMER . self::SEPARATOR_LABEL . $item->getFrontendLabel();
131
+ }
132
+ }
133
+ }
134
+ }
135
+ }
136
+
137
+ return $this->_optionCustomerAttributes;
138
+ }
139
+
140
+ /**
141
+ * For each customer/customer address attribute, provide an eav attribute model
142
+ *
143
+ * (non-PHPdoc)
144
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::postPrepareAttribute()
145
+ */
146
+ public function postPrepareAttribute(array $attributeList)
147
+ {
148
+ $attributeIds = array_keys($attributeList);
149
+ if (count($attributeIds)) {
150
+ $collection = Mage::helper('emvdatasync/service')->getMagentoAttributes($attributeIds);
151
+ if ($collection && $collection->count() > 0) {
152
+ foreach($attributeList as $key => $fieldObject) {
153
+ $attribute = $collection->getItemById($fieldObject->getMappedAttributeId());
154
+ if ($attribute) {
155
+ $fieldObject->setAttributeObject($attribute);
156
+ $fieldObject->setMappedDataType($attribute->getBackendType());
157
+ }
158
+ }
159
+ }
160
+ }
161
+
162
+ return $this;
163
+ }
164
+
165
+ /**
166
+ * (non-PHPdoc)
167
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::canHandle()
168
+ */
169
+ public function canHandle($attributeData, $storeId)
170
+ {
171
+ $ok = false;
172
+ if (isset($attributeData['prefix'])) {
173
+ $allowedPrefix = array(self::PREFIX_BILLING_ATTR, self::PREFIX_CUSTOMER_ATTR, self::PREFIX_SHIPPING_ATTR);
174
+ if (in_array($attributeData['prefix'], $allowedPrefix)) {
175
+ $ok = true;
176
+ }
177
+ }
178
+
179
+ return $ok;
180
+ }
181
+
182
+
183
+ /**
184
+ * Apply customer and customer address attribute to select
185
+ *
186
+ * (non-PHPdoc)
187
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::prepareSubscriberCollection()
188
+ */
189
+ public function prepareSubscriberCollection(
190
+ Varien_Data_Collection_Db $collection,
191
+ array $attributeList,
192
+ $storeId = null
193
+ )
194
+ {
195
+ $this->prepareDefaultBillingAndShippingAttrId();
196
+ $joinFactory = array();
197
+ // Get connection from collection
198
+ $adapter = $collection->getConnection();
199
+
200
+ // Prepare required table data (id, etc...)
201
+ $tablePrefix = (string)Mage::getConfig()->getTablePrefix();
202
+ $customerEntityTable = $tablePrefix . 'customer_entity';
203
+ $customerEavIntTable = $tablePrefix . 'customer_entity_int';
204
+
205
+ // Get address entity type
206
+ $customerAddressEntityTypeId = Mage::helper('emvdatasync/service')->getCustomerAddressTypeId();
207
+
208
+ $joinFactory = array(
209
+ 'entity_table' => array(
210
+ $customerEntityTable => array($customerEntityTable . '.entity_id'),
211
+ ),
212
+ 'eav_tables' => array(
213
+ self::PREFIX_CUSTOMER_ATTR => array(),
214
+ self::PREFIX_BILLING_ATTR => array(),
215
+ self::PREFIX_SHIPPING_ATTR => array(),
216
+ )
217
+ );
218
+ foreach ($attributeList as $mappedField) {
219
+ // the attribute needs to have a backend table
220
+ if ($mappedField->getAttributeObject() && $mappedField->getAttributeObject()->getBackend()) {
221
+ // get attribute object
222
+ $attribute = $mappedField->getAttributeObject();
223
+ $preparedAttributeCode = $attribute->getAttributeCode();
224
+
225
+ $tableName = $attribute->getBackend()->getTable();
226
+ // if the attribute value is retrieved from customer entity table
227
+ if ($tableName == $customerEntityTable) {
228
+ $joinFactory['entity_table']
229
+ [$customerEntityTable][$attribute->getId()]
230
+ = $customerEntityTable . '.' . $attribute->getAttributeCode();
231
+ } else {
232
+ $preparedAttributeCode = $mappedField->getMappedEntityType()
233
+ . '_'. $attribute->getAttributeCode();
234
+ $joinFactory['eav_tables']
235
+ [$mappedField->getMappedEntityType()][$tableName][$attribute->getId()]
236
+ = $preparedAttributeCode;
237
+ }
238
+
239
+ // !!! use final_attribute_code to get value
240
+ $mappedField->setFinalAttributeCode($preparedAttributeCode);
241
+ }
242
+ }
243
+
244
+ // Manage entities fields
245
+ $collection->getSelect()
246
+ // Add customer_entity fields (no aliases, an only call for all customer entity fields)
247
+ ->joinLeft(
248
+ $customerEntityTable,
249
+ $customerEntityTable . '.entity_id = main_table.customer_id',
250
+ $joinFactory['entity_table'][$customerEntityTable]
251
+ )
252
+ // find default billing address entity id
253
+ ->joinLeft(
254
+ array('default_billing_id_table' => $customerEavIntTable),
255
+ $adapter->quoteInto(
256
+ 'default_billing_id_table.entity_id = main_table.customer_id'
257
+ . ' AND default_billing_id_table.attribute_id = ?',
258
+ $this->_defaultBillingAttrId
259
+ ),
260
+ array('default_billing_id' => 'default_billing_id_table.value')
261
+ )
262
+ // find default shipping address entity id
263
+ ->joinLeft(
264
+ array('default_shipping_id_table' => $customerEavIntTable),
265
+ $adapter->quoteInto(
266
+ 'default_shipping_id_table.entity_id = main_table.customer_id'
267
+ . ' AND default_shipping_id_table.attribute_id = ?',
268
+ $this->_defaultShippingAttrId
269
+ ),
270
+ array('default_shipping_id' => 'default_shipping_id_table.value')
271
+ )
272
+ ;
273
+
274
+ // retrieve different attributes from different tables
275
+ foreach ($joinFactory['eav_tables'] as $type => $tables) {
276
+ if ($type == self::PREFIX_CUSTOMER_ATTR) {
277
+ foreach($tables as $tableName => $fields) {
278
+ foreach ($fields as $fieldId => $fieldSql) {
279
+ $collection->getSelect()
280
+ ->joinLeft(
281
+ array($fieldSql . '_table' => $tableName),
282
+ $adapter->quoteInto(
283
+ $fieldSql . '_table' . '.entity_id = main_table.customer_id'
284
+ . ' AND ' . $fieldSql . '_table' . '.attribute_id = ?',
285
+ $fieldId
286
+ ),
287
+ array($fieldSql => $fieldSql . '_table' . '.value')
288
+ );
289
+ }
290
+ }
291
+ } else {
292
+ foreach($tables as $tableName => $fields) {
293
+ foreach ($fields as $fieldId => $fieldSql) {
294
+ if ($type == self::PREFIX_SHIPPING_ATTR) {
295
+ $condition = $adapter->quoteInto(
296
+ $fieldSql . '_table' . '.entity_id = default_shipping_id_table.value'
297
+ . ' AND ' . $fieldSql . '_table' . '.attribute_id = ?',
298
+ $fieldId
299
+ );
300
+ } else {
301
+ $condition = $adapter->quoteInto(
302
+ $fieldSql . '_table' . '.entity_id = default_billing_id_table.value'
303
+ . ' AND ' . $fieldSql . '_table' . '.attribute_id = ?',
304
+ $fieldId
305
+ );
306
+ }
307
+
308
+ $collection->getSelect()
309
+ ->joinLeft(
310
+ array($fieldSql . '_table' => $tableName),
311
+ $condition,
312
+ array($fieldSql => $fieldSql . '_table' . '.value')
313
+ );
314
+ }
315
+ }
316
+ }
317
+ }
318
+
319
+ return $collection;
320
+ }
321
+ }
app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/Newsletter.php ADDED
@@ -0,0 +1,99 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Newslleter Attribute handler
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_DataSync_Model_AttributeProcessing_Handler_Newsletter
11
+ extends Emv_DataSync_Model_AttributeProcessing_Handler_Abstract
12
+ {
13
+ const PREFIX_NEWSLETTER_FIELD = 'newsletter';
14
+
15
+ protected $_tableName = 'newsletter/subscriber';
16
+ protected $_tableDefintion = array();
17
+ protected $_isLoaded = false;
18
+
19
+ /**
20
+ * @return array
21
+ */
22
+ public function getTableDefinition()
23
+ {
24
+ if (!$this->_isLoaded) {
25
+ // add subscriber's column definition into array
26
+ $readAdaptator = Mage::getSingleton('core/resource')->getConnection('core_read');
27
+ $this->_tableDefintion = $readAdaptator
28
+ ->describeTable(Mage::getSingleton('core/resource')->getTableName($this->_tableName));
29
+ $this->_isLoaded = true;
30
+ }
31
+ return $this->_tableDefintion;
32
+ }
33
+
34
+ /**
35
+ * (non-PHPdoc)
36
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::toOptionArray()
37
+ */
38
+ public function toOptionArray()
39
+ {
40
+ if (is_null($this->_optionCustomerAttributes)) {
41
+ $this->_optionCustomerAttributes = array();
42
+ if ($this->getTableDefinition() && is_array($this->getTableDefinition())) {
43
+ foreach ($this->getTableDefinition() as $columnName => $columnDefintion) {
44
+ if (!isset($this->_optionCustomerAttributes['newsletter_subscriber'])) {
45
+ $this->_optionCustomerAttributes['newsletter_subscriber'] = array(
46
+ 'value' => array(),
47
+ 'label' => Mage::helper('emvdatasync')->__('Newsletter Subscriber')
48
+ );
49
+ }
50
+ $finalAttributeId = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::buildAttributeName(
51
+ self::PREFIX_NEWSLETTER_FIELD,
52
+ $columnName
53
+ );
54
+ $this->_optionCustomerAttributes['newsletter_subscriber']['value'][$finalAttributeId] = $columnName;
55
+ }
56
+ }
57
+ }
58
+
59
+ return $this->_optionCustomerAttributes;
60
+ }
61
+
62
+ /**
63
+ * (non-PHPdoc)
64
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::canHandle()
65
+ */
66
+ public function canHandle($attributeData, $storeId)
67
+ {
68
+ $ok = false;
69
+ if (isset($attributeData['prefix'])) {
70
+ $allowedPrefix = array(self::PREFIX_NEWSLETTER_FIELD);
71
+ if (in_array($attributeData['prefix'], $allowedPrefix)) {
72
+ $ok = true;
73
+ }
74
+ }
75
+
76
+ return $ok;
77
+ }
78
+
79
+ /**
80
+ * (non-PHPdoc)
81
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::postPrepareAttribute()
82
+ */
83
+ public function postPrepareAttribute(array $attributeList)
84
+ {
85
+ $tableDefinition = $this->getTableDefinition();
86
+ if ($tableDefinition && is_array($tableDefinition)) {
87
+ foreach($attributeList as $key => $fieldObject) {
88
+ if (
89
+ isset($tableDefinition[$fieldObject->getMappedAttributeId()])
90
+ && isset($tableDefinition[$fieldObject->getMappedAttributeId()]['DATA_TYPE'])
91
+ ) {
92
+ $fieldObject->setMappedDataType($tableDefinition[$fieldObject->getMappedAttributeId()]['DATA_TYPE']);
93
+ }
94
+ }
95
+ }
96
+
97
+ return $this;
98
+ }
99
+ }
app/code/community/Emv/DataSync/Model/AttributeProcessing/Handler/PurchaseInformation.php ADDED
@@ -0,0 +1,154 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Purchase Information Attribute handler
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_DataSync_Model_AttributeProcessing_Handler_PurchaseInformation
11
+ extends Emv_DataSync_Model_AttributeProcessing_Handler_Newsletter
12
+ {
13
+ const PREFIX_PURCHASE_FIELD = 'purchase';
14
+
15
+ /**
16
+ * Table name
17
+ *
18
+ * @var string
19
+ */
20
+ protected $_tableName = 'emvdatasync/purchase_info';
21
+
22
+ /**
23
+ * Prohibited fields (in the attribute mapping list)
24
+ * @var array
25
+ */
26
+ protected $_prohibitedFields = array('id', 'customer_id');
27
+
28
+ /**
29
+ * Field Labels
30
+ *
31
+ * @var array
32
+ */
33
+ protected $_fieldLabels = array(
34
+ 'email' => 'Used Email Addresses',
35
+ 'order_list' => 'List of Order #' ,
36
+
37
+ 'created_at' => 'Created At',
38
+ 'updated_at' => 'Updated At' ,
39
+
40
+ 'base_currency_code' => 'Base Currency Code',
41
+
42
+ 'total_order' => 'Total Orders Purchased',
43
+
44
+ 'total_ordered_item_qty' => 'Total Items Purchased',
45
+ 'avg_item_qty' => 'Average Items Purchased per Order',
46
+ 'order_amount_total' => 'Total Order Amount Spent',
47
+ 'avg_order_amount_total' => 'Average Order Amount Spent per Purchase',
48
+ 'discount_amount_total' => 'Total Discount Amount',
49
+ 'avg_discount_amount_total' => 'Average Discount Amount per Purchase',
50
+ 'shipping_amount_total' => 'Total Shipping Amount',
51
+ 'avg_shipping_amount_total' => 'Average Shipping Amount per Purchase',
52
+
53
+ 'min_order_amount_total' => 'Minimum Purchase Total',
54
+ 'max_order_amount_total' => 'Maximum Purchase Total',
55
+ 'first_order_date' => 'First Purchase',
56
+ 'last_order_date' => 'Last Purchase',
57
+ 'min_total_ordered_item_qty' => 'Minimum Items Purchased',
58
+ 'max_total_ordered_item_qty' => 'Maximum Items Purchased',
59
+
60
+ 'shipping_list' => 'Shipping Methods',
61
+ 'payment_methods' => 'Payment Methods',
62
+ 'coupon_list' => 'Used Coupons',
63
+ 'nb_order_having_discount' => 'Total Purchases With Discount'
64
+ );
65
+
66
+ /**
67
+ * (non-PHPdoc)
68
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::toOptionArray()
69
+ */
70
+ public function toOptionArray()
71
+ {
72
+ if (is_null($this->_optionCustomerAttributes)) {
73
+ $this->_optionCustomerAttributes = array();
74
+
75
+ if ($this->getTableDefinition() && is_array($this->getTableDefinition())) {
76
+ foreach ($this->getTableDefinition() as $columnName => $columnDefintion) {
77
+ if (!in_array($columnName, $this->_prohibitedFields)) {
78
+ if (!isset($this->_optionCustomerAttributes['purchase_information'])) {
79
+ $this->_optionCustomerAttributes['purchase_information'] = array(
80
+ 'value' => array(),
81
+ 'label' => Mage::helper('emvdatasync')->__('Purchase Information')
82
+ );
83
+ }
84
+ $finalAttributeId = Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::buildAttributeName(
85
+ self::PREFIX_PURCHASE_FIELD,
86
+ $columnName
87
+ );
88
+
89
+ $label = $columnName;
90
+ if (isset($this->_fieldLabels[$label])) {
91
+ $label = $this->_fieldLabels[$label];
92
+ }
93
+ $this->_optionCustomerAttributes['purchase_information']['value'][$finalAttributeId] = 'Purchase - ' . $label;
94
+ }
95
+ }
96
+ }
97
+
98
+ }
99
+
100
+ return $this->_optionCustomerAttributes;
101
+ }
102
+
103
+ /**
104
+ * (non-PHPdoc)
105
+ * @see Emv_DataSync_Model_AttributeProcessing_Handler_Abstract::canHandle()
106
+ */
107
+ public function canHandle($attributeData, $storeId)
108
+ {
109
+ $ok = false;
110
+ if (Mage::getSingleton('emvdatasync/service_dataProcess')->enabledPurchaseInformation()) {
111
+ if (isset($attributeData['prefix'])) {
112
+ $allowedPrefix = array(self::PREFIX_PURCHASE_FIELD);
113
+ if (in_array($attributeData['prefix'], $allowedPrefix)) {
114
+ $ok = true;
115
+ }
116
+ }
117
+ }
118
+
119
+ return $ok;
120
+ }
121
+
122
+ /**
123
+ * Prepare subscriber collection according to mapped attribute list
124
+ * Generic method needs to be implemented in Child class.
125
+ *
126
+ * @param Varien_Data_Collection_Db $collection
127
+ * @param array $attributeList
128
+ * @param string $storeId
129
+ * @return Varien_Data_Collection_Db
130
+ */
131
+ public function prepareSubscriberCollection(
132
+ Varien_Data_Collection_Db $collection,
133
+ array $attributeList,
134
+ $storeId = null
135
+ )
136
+ {
137
+ $tableName = Mage::getSingleton('core/resource')->getTableName($this->_tableName);
138
+
139
+ $collection->getSelect()
140
+ ->joinLeft(
141
+ array('purchase' => $tableName),
142
+ 'purchase.customer_id = main_table.customer_id'
143
+ )
144
+ ->where('
145
+ main_table.date_last_purchase IS NULL
146
+ OR (
147
+ purchase.updated_at > main_table.date_last_purchase
148
+ )
149
+ ')
150
+ ;
151
+
152
+ return $collection;
153
+ }
154
+ }
app/code/community/Emv/DataSync/Model/Cron.php CHANGED
@@ -4,7 +4,8 @@
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
- * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
 
8
  */
9
  class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
10
  {
@@ -71,7 +72,6 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
71
  public function batchMemberExport()
72
  {
73
  $helper = Mage::helper('emvdatasync');
74
- $exportDone = false;
75
 
76
  if (!Mage::getStoreConfigFlag(self::XML_PATH_EMAILVISION_BATCH_ENABLED)) {
77
  return $this;
@@ -80,6 +80,8 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
80
  $this->_errors = array();
81
 
82
  $startRunTime = $helper->getFormattedGmtDateTime();
 
 
83
 
84
  $processErrors = array();
85
  $createdLock = false;
@@ -87,14 +89,13 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
87
  // check and create lock
88
  if (!$helper->checkLockFile()) {
89
  $service = Mage::getModel('emvdatasync/service_batchMember');
90
- $account = Mage::helper('emvdatasync')->getEmvAccountForStore('batch');
91
- $service->setAccount($account);
92
 
93
  // create lock file => do not allow several process at the same time
94
  $helper->createLockFile('Batch member synchronization cron process running at GMT timezone ' . $startRunTime);
95
  $createdLock = true;
96
 
97
- $exportDone = $service->massExportCustomers();
 
98
 
99
  // If non-blocking errors occurs
100
  $processErrors = $service->getErrors();
@@ -121,19 +122,20 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
121
  }
122
  }
123
 
 
 
 
124
  // if some errors occur, we should inform the client
125
  if (count($this->_errors)) {
126
  $this->_sendCustomerExportErrors();
127
  }
128
 
129
- if ($exportDone) {
130
- $config = Mage::getModel('core/config');
131
- $config->saveConfig(
132
- 'emvdatasync/last_successful_synchronization/customers',
133
- Mage::helper('emvdatasync')->getFormattedGmtDateTime()
134
- );
135
- $config->removeCache();
136
- }
137
 
138
  return $this;
139
  }
@@ -154,6 +156,8 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
154
 
155
  // gmt date time
156
  $startRunTime = $helper->getFormattedGmtDateTime();
 
 
157
 
158
  $processErrors = array();
159
  $createdLock = false;
@@ -161,8 +165,6 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
161
  // check and create lock
162
  if (!$helper->checkLockFile()) {
163
  $service = Mage::getModel('emvdatasync/service_member');
164
- $account = Mage::helper('emvdatasync')->getEmvAccountForStore();
165
- $service->setAccount($account);
166
 
167
  // create lock file => do not allow several process at the same time
168
  $helper->createLockFile('Member synchronization cron process running at GMT timezone ' . $startRunTime);
@@ -178,7 +180,8 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
178
  }
179
  }
180
  } catch (Exception $e) {
181
- $this->_errors[] = 'Errors occured while running memberExport (memberApi cron), at GMT timezone ' . $startRunTime;
 
182
  $this->_errors[] = $e->getMessage();
183
  foreach ($processErrors as $error) {
184
  $this->_errors[] = $error;
@@ -194,6 +197,7 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
194
  }
195
  }
196
 
 
197
  // if some errors occur, we should inform the client
198
  if (count($this->_errors)) {
199
  $this->_sendCustomerExportErrors();
@@ -203,7 +207,7 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
203
  }
204
 
205
  /**
206
- * Cron method to clean files moved in uploaded folder after exporting customers
207
  *
208
  * @return Emv_DataSync_Model_Cron
209
  */
@@ -215,37 +219,128 @@ class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
215
 
216
  // everything is in GMT date time
217
  $startRunTime = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
 
 
218
 
219
  $this->_errors = array();
220
-
221
  try {
222
  // Check folders in case this method is called before any export
223
- Mage::helper('emvdatasync')->checkAndCreatFolder();
224
-
225
- // remove uploaded file
226
- $dirHandler = @opendir(Mage::getBaseDir('export'). DS . 'emailvision' . DS . 'uploaded');
227
- while($filename = readdir($dirHandler)) {
228
- // Delete any file in uploaded folder
229
- if ($filename != '.' && $filename != '..') {
230
- unlink(Mage::getBaseDir('export'). DS . 'emailvision' . DS . 'uploaded'. DS . $filename);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  }
232
- }
233
- @closedir($dirHandler);
234
-
235
- // remove emailvision export folder
236
- $dirHandler = @opendir(Mage::getBaseDir('export'). DS . 'emailvision' );
237
- while($filename = readdir($dirHandler)) {
238
- $path = Mage::getBaseDir('export'). DS . 'emailvision' . DS . $filename;
239
- // Delete any file in uploaded folder
240
- if ($filename != '.' && $filename != '..' && is_file($path)) {
241
- unlink($path);
 
 
 
 
 
 
242
  }
 
243
  }
244
- @closedir($dirHandler);
245
  } catch (Exception $e) {
246
  $this->_errors[] = 'Errors occured while removing exported files (cleanEmailVisionFiles cron), at GMT timezone '
247
  . $startRunTime;
248
  $this->_errors[] = $e->getMessage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
249
  $this->_sendCustomerExportErrors();
250
  }
251
 
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_DataSync_Model_Cron extends Mage_Core_Model_Abstract
11
  {
72
  public function batchMemberExport()
73
  {
74
  $helper = Mage::helper('emvdatasync');
 
75
 
76
  if (!Mage::getStoreConfigFlag(self::XML_PATH_EMAILVISION_BATCH_ENABLED)) {
77
  return $this;
80
  $this->_errors = array();
81
 
82
  $startRunTime = $helper->getFormattedGmtDateTime();
83
+ // !!! it's very important to set a custom error handler in order to remove lock file in case of fatal error
84
+ Mage::helper('emvcore')->setSmartFocusErrorHandler();
85
 
86
  $processErrors = array();
87
  $createdLock = false;
89
  // check and create lock
90
  if (!$helper->checkLockFile()) {
91
  $service = Mage::getModel('emvdatasync/service_batchMember');
 
 
92
 
93
  // create lock file => do not allow several process at the same time
94
  $helper->createLockFile('Batch member synchronization cron process running at GMT timezone ' . $startRunTime);
95
  $createdLock = true;
96
 
97
+ $service->init();
98
+ $service->run();
99
 
100
  // If non-blocking errors occurs
101
  $processErrors = $service->getErrors();
122
  }
123
  }
124
 
125
+ // reset to Magento error handler
126
+ Mage::helper('emvcore')->resetErrorHandler();
127
+
128
  // if some errors occur, we should inform the client
129
  if (count($this->_errors)) {
130
  $this->_sendCustomerExportErrors();
131
  }
132
 
133
+ $config = Mage::getModel('core/config');
134
+ $config->saveConfig(
135
+ 'emvdatasync/last_successful_synchronization/customers',
136
+ Mage::helper('emvdatasync')->getFormattedGmtDateTime()
137
+ );
138
+ $config->removeCache();
 
 
139
 
140
  return $this;
141
  }
156
 
157
  // gmt date time
158
  $startRunTime = $helper->getFormattedGmtDateTime();
159
+ // !!! it's very important to set a custom error handler in order to remove lock file in case of fatal error
160
+ Mage::helper('emvcore')->setSmartFocusErrorHandler();
161
 
162
  $processErrors = array();
163
  $createdLock = false;
165
  // check and create lock
166
  if (!$helper->checkLockFile()) {
167
  $service = Mage::getModel('emvdatasync/service_member');
 
 
168
 
169
  // create lock file => do not allow several process at the same time
170
  $helper->createLockFile('Member synchronization cron process running at GMT timezone ' . $startRunTime);
180
  }
181
  }
182
  } catch (Exception $e) {
183
+ $this->_errors[] = 'Errors occured while running memberExport (memberApi cron), at GMT timezone '
184
+ . $startRunTime;
185
  $this->_errors[] = $e->getMessage();
186
  foreach ($processErrors as $error) {
187
  $this->_errors[] = $error;
197
  }
198
  }
199
 
200
+ Mage::helper('emvcore')->resetErrorHandler();
201
  // if some errors occur, we should inform the client
202
  if (count($this->_errors)) {
203
  $this->_sendCustomerExportErrors();
207
  }
208
 
209
  /**
210
+ * Cron method to clean files moved in uploaded folder after exporting customers,
211
  *
212
  * @return Emv_DataSync_Model_Cron
213
  */
219
 
220
  // everything is in GMT date time
221
  $startRunTime = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
222
+ $createdLock = false;
223
+ $helper = Mage::helper('emvdatasync');
224
 
225
  $this->_errors = array();
 
226
  try {
227
  // Check folders in case this method is called before any export
228
+ $helper->checkAndCreatFolder();
229
+
230
+ // check and create lock
231
+ if (!$helper->checkLockFile()) {
232
+ // create lock file => do not allow several process at the same time
233
+ $helper->createLockFile('Cleaning file cron process running at GMT timezone ' . $startRunTime);
234
+ $createdLock = true;
235
+
236
+ // open uploaded folder
237
+ $dirHandler = @opendir(
238
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
239
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
240
+ . DS . Emv_Core_Helper_Data::UPLOADED_FILE_DIR
241
+ );
242
+ while ($filename = readdir($dirHandler)) {
243
+ // Delete any file in uploaded folder
244
+ if ($filename != '.' && $filename != '..') {
245
+ @unlink(
246
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
247
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
248
+ . DS . Emv_Core_Helper_Data::UPLOADED_FILE_DIR
249
+ . DS . $filename
250
+ );
251
+ }
252
  }
253
+ @closedir($dirHandler);
254
+
255
+ // open export folder
256
+ $dirHandler = @opendir(
257
+ Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
258
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
259
+ );
260
+ while ($filename = readdir($dirHandler)) {
261
+ $path = Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
262
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
263
+ . DS . $filename
264
+ ;
265
+ // Delete any file in exporte folder
266
+ if ($filename != '.' && $filename != '..' && is_file($path)) {
267
+ @unlink($path);
268
+ }
269
  }
270
+ @closedir($dirHandler);
271
  }
 
272
  } catch (Exception $e) {
273
  $this->_errors[] = 'Errors occured while removing exported files (cleanEmailVisionFiles cron), at GMT timezone '
274
  . $startRunTime;
275
  $this->_errors[] = $e->getMessage();
276
+ }
277
+
278
+ // if lock is created, need to delete it
279
+ if ($createdLock) {
280
+ try {
281
+ $helper->removeLockFile();
282
+ } catch (Exception $e) {
283
+ $this->_errors[] = $e->getMessage();
284
+ }
285
+ }
286
+
287
+ // if some errors occur, we should inform the client
288
+ if (count($this->_errors)) {
289
+ $this->_sendCustomerExportErrors();
290
+ }
291
+
292
+ return $this;
293
+ }
294
+
295
+ /**
296
+ * Cron method to proceed purchase information
297
+ *
298
+ * @return Emv_DataSync_Model_Cron
299
+ */
300
+ public function startPurchaseProcess()
301
+ {
302
+ // everything is in GMT date time
303
+ $startRunTime = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
304
+ $createdLock = false;
305
+ $helper = Mage::helper('emvdatasync');
306
+
307
+ $processErrors = array();
308
+ $this->_errors = array();
309
+ try {
310
+ // Check folders in case this method is called before any export
311
+ $helper->checkAndCreatFolder();
312
+
313
+ // check and create lock
314
+ if (!$helper->checkLockFile()) {
315
+ // create lock file => do not allow several process at the same time
316
+ $helper->createLockFile('Purchase information cron process running at GMT timezone ' . $startRunTime);
317
+ $createdLock = true;
318
+
319
+ $processErrors = Mage::getModel('emvdatasync/service_dataProcess')->prepareList();
320
+ if (!empty($processErrors)) {
321
+ throw (new Exception('Check below for more details:'));
322
+ }
323
+ }
324
+ } catch (Exception $e) {
325
+ $this->_errors[] = 'Errors occured while preparing purchase information, at GMT timezone '
326
+ . $startRunTime;
327
+ $this->_errors[] = $e->getMessage();
328
+ foreach ($processErrors as $error) {
329
+ $this->_errors[] = $error;
330
+ }
331
+ }
332
+
333
+ // if lock is created, need to delete it
334
+ if ($createdLock) {
335
+ try {
336
+ $helper->removeLockFile();
337
+ } catch (Exception $e) {
338
+ $this->_errors[] = $e->getMessage();
339
+ }
340
+ }
341
+
342
+ // if some errors occur, we should inform the client
343
+ if (count($this->_errors)) {
344
  $this->_sendCustomerExportErrors();
345
  }
346
 
app/code/community/Emv/DataSync/Model/DataProcess/PurchaseInformation.php ADDED
@@ -0,0 +1,32 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Purchase Information Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_DataSync_Model_DataProcess_PurchaseInformation extends Mage_Core_Model_Abstract
11
+ {
12
+ /**
13
+ * (non-PHPdoc)
14
+ * @see Varien_Object::_construct()
15
+ */
16
+ public function _construct()
17
+ {
18
+ $this->_init('emvdatasync/dataProcess_purchaseInformation');
19
+ }
20
+
21
+ /**
22
+ * Load purchase information by subscriber
23
+ *
24
+ * @param Mage_Newsletter_Model_Subscriber $subscriber
25
+ * @return Emv_DataSync_Model_DataProcess_PurchaseInformation
26
+ */
27
+ public function loadBySubscriber(Mage_Newsletter_Model_Subscriber $subscriber)
28
+ {
29
+ $this->addData($this->getResource()->loadBySubscriber($subscriber));
30
+ return $this;
31
+ }
32
+ }
app/code/community/Emv/DataSync/Model/Mysql4/DataProcess/PurchaseInformation.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Purchase Information Resource Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ */
9
+ class Emv_DataSync_Model_Mysql4_DataProcess_PurchaseInformation extends Mage_Core_Model_Mysql4_Abstract
10
+ {
11
+ /**
12
+ * (non-PHPdoc)
13
+ * @see Mage_Core_Model_Resource_Abstract::_construct()
14
+ */
15
+ public function _construct() {
16
+ $this->_init('emvdatasync/purchase_info', 'id');
17
+ }
18
+
19
+ /**
20
+ * Load by subscriber
21
+ *
22
+ * @param Mage_Newsletter_Model_Subscriber $subscriber
23
+ * @return array
24
+ */
25
+ public function loadBySubscriber(Mage_Newsletter_Model_Subscriber $subscriber)
26
+ {
27
+ $result = array();
28
+ if ($subscriber->getCustomerId()) {
29
+ $select = $this->_getReadAdapter()->select()
30
+ ->from(array('main_table' => $this->getMainTable()))
31
+ ->where('customer_id = :customer_id');
32
+
33
+ $result = $this->_getReadAdapter()->fetchRow($select, array('customer_id' => $subscriber->getCustomerId()));
34
+
35
+ if (!$result) {
36
+ $result = array();
37
+ }
38
+ }
39
+
40
+ return $result;
41
+ }
42
+ }
app/code/community/Emv/DataSync/Model/Mysql4/DataProcess/PurchaseInformation/Collection.php ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Purchase Information Collection Resource Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_DataSync_Model_Mysql4_DataProcess_PurchaseInformation_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
11
+ {
12
+ /**
13
+ * (non-PHPdoc)
14
+ * @see Mage_Core_Model_Resource_Db_Collection_Abstract::_construct()
15
+ */
16
+ public function _construct() {
17
+ $this->_init('emvdatasync/dataProcess_purchaseInformation');
18
+ }
19
+ }
app/code/community/Emv/DataSync/Model/Observer.php CHANGED
@@ -4,30 +4,41 @@
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
- * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
 
8
  */
9
- /* @var $customer Mage_Customer_Model_Customer */
10
- /* @var $customerAddress Mage_Customer_Model_Address */
11
- /* @var $subscriber Mage_Newsletter_Model_Subscriber */
12
- /* @var $emailVisionApi Auguria_EmailVision_Model_Emailvision_Api */
13
- /* @var $dateModel Mage_Core_Model_Date */
14
  class Emv_DataSync_Model_Observer
15
  {
16
- const DEFAULT_STORE_CODE = 'admin';
17
- const XML_PATH_EMAILVISION_OBSERVER_ENABLED = 'emvdatasync/apimember/enabled';
18
-
 
19
  protected $_instanciationTime;
20
 
 
 
 
 
21
  protected $_customerHasDataChanged = array();
 
 
 
 
 
22
  protected $_subscriberSaved = array();
23
 
24
  /**
25
- * Customer newsletter subscriber
26
  *
27
  * @var array
28
  */
29
  protected $_customerNewsletter = array();
30
 
 
 
 
 
 
31
  /**
32
  * Constructor, register $this instanciation datetime
33
  */
@@ -44,7 +55,7 @@ class Emv_DataSync_Model_Observer
44
  */
45
  public function onSubscriberDelete(Varien_Event_Observer $observer)
46
  {
47
- if (Mage::getStoreConfigFlag(self::XML_PATH_EMAILVISION_OBSERVER_ENABLED)) {
48
  $subscriber = $observer->getSubscriber();
49
  // Direct unjoin (subscriber will be deleted on customer delete)
50
  if ($subscriber->getId()) {
@@ -68,18 +79,20 @@ class Emv_DataSync_Model_Observer
68
  */
69
  public function onCustomerAddressSave(Varien_Event_Observer $observer)
70
  {
71
- // If address is a billing one and has data changes, else nothing to do (avoid loading customer and subscriber)
72
  $customerAddress = $observer->getCustomerAddress();
73
- if ($customerAddress->getIsDefaultBilling() && $customerAddress->hasDataChanges()) {
 
 
74
  $customer = $customerAddress->getCustomer();
75
  $subscriber = $this->getSubscriberFromCustomer($customer);
76
 
77
  // If a subscriber is linked to this address' customer, update last data changes date
78
- if (
79
- $subscriber && $subscriber->getId()
80
- && $subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED
81
- ) {
82
- $this->setCustomerHasDataChanged($subscriber->getId());
 
83
  }
84
  }
85
  }
@@ -140,11 +153,9 @@ class Emv_DataSync_Model_Observer
140
  if ($subscriber && $subscriber->getId()) {
141
  // Prevent multiple calls on a Mage::app instance
142
  if (!$this->subscriberSaved($subscriber->getId())) {
143
- if (
144
- $subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED
145
- && $customer->hasDataChanges()
146
- ) {
147
  $this->setCustomerHasDataChanged($subscriber->getId());
 
148
  }
149
  }
150
  }
@@ -170,20 +181,45 @@ class Emv_DataSync_Model_Observer
170
  }
171
 
172
  /**
173
- * Method called on subscriber save. Call submethods if required. New subscribers will
174
- * always have the return of getIsStatusChanged method setted to 1.
175
  *
176
  * @param Varien_Event_Observer $observer
177
  */
178
  public function onSubscriberSave(Varien_Event_Observer $observer)
179
  {
180
  $subscriber = $observer->getSubscriber();
 
 
 
 
 
 
 
 
 
 
 
 
181
  if (!$subscriber->getId()) {
182
  return false;
183
  }
184
 
185
  // Prevent multiple calls on a Mage::app instance
186
  if (!$this->subscriberSaved($subscriber->getId())) {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
187
  if (
188
  $subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED
189
  && ($this->customerHasDataChanged($subscriber->getId()) || $this->isSubscriberStatusChanged($subscriber))
@@ -225,7 +261,7 @@ class Emv_DataSync_Model_Observer
225
  * @param Mage_Newsletter_Model_Subscriber $subscriber
226
  * @param boolean $isRejoining
227
  */
228
- protected function updateUnjoinDate(Mage_Newsletter_Model_Subscriber $subscriber, $isRejoining = false)
229
  {
230
  // Prevent infinite loops and multiple calls on a Mage::app instance
231
  $this->setSubscriberSaved($subscriber->getId());
@@ -235,7 +271,8 @@ class Emv_DataSync_Model_Observer
235
  $dateUnjoin = null;
236
  }
237
 
238
- $subscriber->setData('date_unjoin', $dateUnjoin);
 
239
  $subscriber->save();
240
  }
241
 
@@ -249,8 +286,38 @@ class Emv_DataSync_Model_Observer
249
  // Prevent infinite loops and multiple calls on a Mage::app instance
250
  $this->setSubscriberSaved($subscriber->getId());
251
 
252
- $subscriber->setData('data_last_update_date', $this->_instanciationTime);
 
253
  $subscriber->save();
254
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
255
  }
256
 
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
  */
 
 
 
 
 
10
  class Emv_DataSync_Model_Observer
11
  {
12
+ /**
13
+ * Instanciation Date/time
14
+ * @var string
15
+ */
16
  protected $_instanciationTime;
17
 
18
+ /**
19
+ * List of customers that have data changes - use subscriber id as identifiant
20
+ * @var array
21
+ */
22
  protected $_customerHasDataChanged = array();
23
+
24
+ /**
25
+ * List of subscribers that have been saved
26
+ * @var array
27
+ */
28
  protected $_subscriberSaved = array();
29
 
30
  /**
31
+ * List of loaded subscribers (sorted by customers)
32
  *
33
  * @var array
34
  */
35
  protected $_customerNewsletter = array();
36
 
37
+ /**
38
+ * @var array
39
+ */
40
+ protected $_customerHasSavedOrder = array();
41
+
42
  /**
43
  * Constructor, register $this instanciation datetime
44
  */
55
  */
56
  public function onSubscriberDelete(Varien_Event_Observer $observer)
57
  {
58
+ if (Mage::getStoreConfigFlag(Emv_DataSync_Helper_Data::XML_PATH_ENABLED_FOR_MEMBER)) {
59
  $subscriber = $observer->getSubscriber();
60
  // Direct unjoin (subscriber will be deleted on customer delete)
61
  if ($subscriber->getId()) {
79
  */
80
  public function onCustomerAddressSave(Varien_Event_Observer $observer)
81
  {
 
82
  $customerAddress = $observer->getCustomerAddress();
83
+
84
+ // Proceed data if address has data changes
85
+ if ($customerAddress->hasDataChanges()) {
86
  $customer = $customerAddress->getCustomer();
87
  $subscriber = $this->getSubscriberFromCustomer($customer);
88
 
89
  // If a subscriber is linked to this address' customer, update last data changes date
90
+ if ($subscriber && $subscriber->getId()) {
91
+ // Prevent multiple calls on a Mage::app instance
92
+ if (!$this->subscriberSaved($subscriber->getId())) {
93
+ $this->setCustomerHasDataChanged($subscriber->getId());
94
+ $this->handleSubscriberInformation($subscriber);
95
+ }
96
  }
97
  }
98
  }
153
  if ($subscriber && $subscriber->getId()) {
154
  // Prevent multiple calls on a Mage::app instance
155
  if (!$this->subscriberSaved($subscriber->getId())) {
156
+ if ($customer->hasDataChanges()) {
 
 
 
157
  $this->setCustomerHasDataChanged($subscriber->getId());
158
+ $this->handleSubscriberInformation($subscriber);
159
  }
160
  }
161
  }
181
  }
182
 
183
  /**
184
+ * Method called on subscriber save.
 
185
  *
186
  * @param Varien_Event_Observer $observer
187
  */
188
  public function onSubscriberSave(Varien_Event_Observer $observer)
189
  {
190
  $subscriber = $observer->getSubscriber();
191
+
192
+ $this->handleSubscriberInformation($subscriber);
193
+ }
194
+
195
+ /**
196
+ * Update the subscriber information according to the changes
197
+ *
198
+ * @param Mage_Newsletter_Model_Subscriber $subscriber
199
+ * @return boolean
200
+ */
201
+ public function handleSubscriberInformation(Mage_Newsletter_Model_Subscriber $subscriber)
202
+ {
203
  if (!$subscriber->getId()) {
204
  return false;
205
  }
206
 
207
  // Prevent multiple calls on a Mage::app instance
208
  if (!$this->subscriberSaved($subscriber->getId())) {
209
+ // if the subscriber was just created
210
+ if ($subscriber->getCustomerId() && $subscriber->isObjectNew()) {
211
+ try {
212
+ if (Mage::helper('emvdatasync')->doesCustomerHaveOrder($subscriber->getCustomerId())) {
213
+ $subscriber->setData(
214
+ Emv_DataSync_Helper_Service::FIELD_PURCHASE_LAST_UPDATE,
215
+ $this->_instanciationTime
216
+ );
217
+ }
218
+ } catch (Exception $e) {
219
+ Mage::logException($e);
220
+ }
221
+ }
222
+
223
  if (
224
  $subscriber->getStatus() == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED
225
  && ($this->customerHasDataChanged($subscriber->getId()) || $this->isSubscriberStatusChanged($subscriber))
261
  * @param Mage_Newsletter_Model_Subscriber $subscriber
262
  * @param boolean $isRejoining
263
  */
264
+ public function updateUnjoinDate(Mage_Newsletter_Model_Subscriber $subscriber, $isRejoining = false)
265
  {
266
  // Prevent infinite loops and multiple calls on a Mage::app instance
267
  $this->setSubscriberSaved($subscriber->getId());
271
  $dateUnjoin = null;
272
  }
273
 
274
+ $subscriber->setData(Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN, $dateUnjoin);
275
+ $subscriber->setData(Emv_DataSync_Helper_Service::FIELD_QUEUED, Emv_DataSync_Helper_Service::SCHEDULED_VALUE);
276
  $subscriber->save();
277
  }
278
 
286
  // Prevent infinite loops and multiple calls on a Mage::app instance
287
  $this->setSubscriberSaved($subscriber->getId());
288
 
289
+ $subscriber->setData(Emv_DataSync_Helper_Service::FIELD_DATA_LAST_UPDATE, $this->_instanciationTime);
290
+ $subscriber->setData(Emv_DataSync_Helper_Service::FIELD_QUEUED, Emv_DataSync_Helper_Service::SCHEDULED_VALUE);
291
  $subscriber->save();
292
  }
293
+
294
+ /**
295
+ * Observer on order save after event, update subscriber information according to the changes
296
+ *
297
+ * @param Varien_Event_Observer $observer
298
+ */
299
+ public function handleOrderSaveAfter(Varien_Event_Observer $observer)
300
+ {
301
+ /* @var $order Mage_Sales_Model_Order */
302
+ $order = $observer->getEvent()->getOrder();
303
+
304
+ $customer = Mage::getSingleton('customer/session')->getCustomer();
305
+ if ($customer instanceof Mage_Customer_Model_Customer && $customer->getId()) {
306
+ $subscriber = $this->getSubscriberFromCustomer($customer);
307
+ if ($subscriber && $subscriber->getId() && !isset($this->_customerHasSavedOrder[$subscriber->getId()])) {
308
+ $subscriber->setData(
309
+ Emv_DataSync_Helper_Service::FIELD_PURCHASE_LAST_UPDATE,
310
+ $this->_instanciationTime
311
+ );
312
+ $subscriber->setData(
313
+ Emv_DataSync_Helper_Service::FIELD_QUEUED,
314
+ Emv_DataSync_Helper_Service::SCHEDULED_VALUE
315
+ );
316
+ $subscriber->save();
317
+
318
+ $this->_customerHasSavedOrder[$subscriber->getId()] = true;
319
+ }
320
+ }
321
+ }
322
  }
323
 
app/code/community/Emv/DataSync/Model/Service/BatchMember.php CHANGED
@@ -3,16 +3,17 @@
3
  * Batch Member service - Handle Member Data
4
  *
5
  * @category Emv
6
- * @package Emv_Core
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
  class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_BatchMember
 
11
  {
12
  /**
13
  * XML config path for performance config
14
  */
15
- const XML_PATH_PERFORMANCE = 'emvcore/batchmember/performance';
16
 
17
  /**
18
  * The default limit of subscribers to get
@@ -20,9 +21,9 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
20
  const PAGE_SIZE = 10000;
21
 
22
  /**
23
- * Waiting time between each status checking call
24
  */
25
- const WAITING_TIME = 60;
26
 
27
  /**
28
  * @var boolean
@@ -36,14 +37,11 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
36
 
37
  // Subscribers collection management vars
38
  protected $_pageSize;
39
- protected $_pageCount;
40
- protected $_curPage;
41
 
42
  // Files and upload data
43
- protected $_uploadId;
44
  protected $_errors = array();
45
- protected $_fileNamesToUpload = array();
46
- protected $_fileNamesUploaded = array();
47
 
48
  /**
49
  * Mapped headers
@@ -52,16 +50,34 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
52
  protected $_mappedHeaders = array();
53
 
54
  /**
55
- * Subscriber data list
56
  * @var array
57
  */
58
- protected $_subscriberDataList = array();
59
 
60
  /**
61
- * List of subscriber ids per file
62
- * @var array
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
63
  */
64
- protected $_writtenSubscribersIds = array();
65
 
66
  /**
67
  * (non-PHPdoc)
@@ -75,181 +91,592 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
75
  $this->_pageSize = self::PAGE_SIZE;
76
  }
77
 
78
- // everything should be in GMT
79
- $this->_currentTime = Mage::getModel('core/date')->gmtDate('Ymd_H-i-s');
80
-
81
  return parent::_construct();
82
  }
83
 
84
  /**
85
- * Prepare customer csv files for upload
 
 
86
  */
87
- public function prepareCustomerCsvFiles()
88
  {
89
- $mappedHeaders = $this->prepareAndGetMappedHeaders();
90
-
91
- $subscribers = $this->getSubscriberCollection();
92
- $totalSubscribersCount = $subscribers->getSize();
93
- $this->_pageCount = ceil($subscribers->getSize() / $this->_pageSize);
94
-
95
- if ($subscribers->getSize() > 0) {
96
- // Add all customer and address attributes that have been mapped into collection
97
- Mage::helper('emvdatasync/service')->addCustomerAndAddressAttributes($subscribers);
98
-
99
- // Get all stores
100
- $stores = Mage::app()->getStores(true);
101
-
102
- // Get mapped EmailVision entity id
103
- $entityId = strtoupper(Mage::helper('emvdatasync')->getMappedEntityId());
104
-
105
- // Get api service corresponding to current account
106
- $service = $this->getApiService($this->getAccount());
107
-
108
- for ($this->_curPage = 1; $this->_curPage <= $this->_pageCount; $this->_curPage++) {
109
- // Define current page
110
- $subscribers->clear()
111
- ->setPageSize($this->_pageSize)
112
- ->setCurPage($this->_curPage);
113
-
114
- // Add a row foreach customer
115
- $preparedData = array();
116
- foreach ($subscribers as $subscriber) {
117
- // Replace customer email by suscriber one
118
- $subscriber->setData('email', $subscriber->getSubscriberEmail());
119
-
120
- // Prepare and add a customer's data row
121
- $subscriberData = array();
122
-
123
- // retreive all maped attribute values from subscriber, build them into array
124
- $entityFieldsToSelect = Mage::helper('emvdatasync/service')->prepareAndGetMappedCustomerAttributes();
125
- foreach ($entityFieldsToSelect as $attribute) {
126
- $emailVisionKey = strtoupper($attribute->getEmailVisionKey());
127
-
128
- $fieldCode = ($attribute->getFinalAttributeCode())
129
- ? $attribute->getFinalAttributeCode() : $attribute->getAttributeCode();
130
- $fieldValue = '';
131
-
132
- if ($attribute->getFrontendInput() == 'date') {
133
- if ($subscriber->getData($fieldCode)) {
134
- // date time should be in EmailVision format
135
- $fieldValue = Mage::helper('emvdatasync/service')
136
- ->getEmailVisionDate($subscriber->getData($fieldCode));
137
- }
138
- } else {
139
- $fieldValue = $subscriber->getData($fieldCode);
140
- if ($fieldCode == 'store_id' && isset($stores[$fieldValue])) {
141
- $fieldValue = $stores[$fieldValue]->getName();
142
- }
143
- }
144
 
145
- $subscriberData[$emailVisionKey] = $fieldValue;
146
- }
 
147
 
148
- // entity id field
149
- $subscriberData[$entityId] = $subscriber->getId();
 
 
 
 
 
 
 
 
 
 
 
150
 
151
- // If is unjoined
152
- $unjoinedDate = '';
153
- if ($subscriber->getData('subscriber_status') == Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED) {
154
- if ($subscriber->getData('date_unjoin')) {
155
- // date time should be in EmailVision format
156
- $unjoinedDate = Mage::helper('emvdatasync/service')
157
- ->getEmailVisionDate($subscriber->getData('date_unjoin'));
158
- }
159
- }
160
- $subscriberData[strtoupper(Emv_Core_Model_Service_Member::FIELD_UNJOIN)] = $unjoinedDate;
161
- $preparedData[] = array(
162
- 'id' => $subscriber->getId(),
163
- 'fields' => $subscriberData
164
- );
165
 
166
- // add subscriber data into array
167
- $tempSubscriber = array(
168
- 'id' => $subscriber->getId(),
169
- 'rejoined' => false
170
- );
171
- if ($subscriber->getData('subscriber_status') == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED) {
172
- if ($subscriber->getData('date_unjoin') != '' && $subscriber->getData('date_unjoin') != null) {
173
- $tempSubscriber['rejoined'] = true;
174
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
175
  }
176
- $this->_subscriberDataList[$subscriber->getId()] = $tempSubscriber;
177
- }// end foreach subscribers
178
 
179
- try {
180
- $csvFileData = $service->createCsvFiles(
181
- $this,
182
- array_keys($mappedHeaders),
183
- $preparedData
 
 
 
 
 
 
 
 
184
  );
 
185
 
186
- foreach ($csvFileData as $data) {
187
- // member list for each file
188
- $this->_writtenSubscribersIds[$data['file']['filename']] = $data['list_member'];
189
- $this->_fileNamesToUpload[] = $data['file'];
 
190
  }
 
 
 
 
 
 
191
  } catch (Exception $e) {
192
  Mage::logException($e);
 
 
 
 
 
 
 
 
 
 
193
 
194
- $this->_errors[] = 'Exception while building csv file, with message: ' . $e->getMessage();
 
 
 
 
195
  }
196
- } // end foreach page
 
197
  }
 
 
 
198
  }
199
 
200
  /**
201
- * Get merge criteria for batch member api requests
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
202
  *
203
- * @return array
 
 
 
 
 
 
 
204
  */
205
- public function getMergeCriteriaForBatchMember()
206
  {
207
- if (Mage::helper('emvdatasync')->getEmailEnabled()) {
208
- $mergeCriteria = array(strtoupper(Emv_Core_Model_Service_Member::FIELD_EMAIL));
209
- } else {
210
- $mergeCriteria = array(strtoupper(Mage::helper('emvdatasync')->getMappedEntityId()));
 
 
 
 
 
 
 
 
 
 
 
 
211
  }
212
- return $mergeCriteria;
213
  }
214
 
215
  /**
216
- * Mass export customers using Batch member api
217
- * @return boolean
 
 
218
  */
219
- public function massExportCustomers()
220
  {
221
- // create csv files
222
- $this->prepareCustomerCsvFiles();
 
 
 
 
 
 
 
 
 
 
 
 
223
 
224
- $mergeCriteria = $this->getMergeCriteriaForBatchMember();
 
 
 
 
 
 
 
 
 
 
 
 
225
 
226
- // return
227
- $uploadDone = true;
 
 
 
 
228
 
229
- $exportedFileTime = Mage::helper('emvdatasync')->getFormattedGmtDateTime();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
230
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
231
  try {
232
- // Get api service corresponding to current account
233
- $service = $this->getApiService($this->getAccount());
234
- foreach ($this->_fileNamesToUpload as $data) {
235
- $mappedHeaders = $this->prepareAndGetMappedHeaders();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
236
 
237
- $this->_uploadId = $service->sendFileToWebservice(
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
238
  $data,
239
  $mappedHeaders,
240
- $mergeCriteria,
241
  false
242
  );
243
 
 
 
244
  // only checking upload status if we can have upload id
245
- if ($this->_uploadId != false) {
246
  $uploadProcessing = true;
 
247
  // wait until SmartFocus platform completes processing uploaded file
248
  // check status's upload for an interval self::WAITING_TIME
249
  do {
250
  sleep(self::WAITING_TIME);
251
  // get status's upload
252
- $uploadStatus = $service->getUploadStatus($this->_uploadId, false);
253
 
254
  if (
255
  in_array(
@@ -257,45 +684,79 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
257
  EmailVision_Api_BatchMemberService::getAccomplishedStatuses()
258
  )
259
  ) {
 
 
 
260
  $uploadProcessing = false;
261
  if (
262
  $uploadStatus['status'] == EmailVision_Api_BatchMemberService::getStatusOkWithoutError()
263
  ) {
264
- $this->_fileNamesUploaded[] = $data['filename'];
265
  } else {
266
- $uploadDone = false;
267
- $this->_errors[] = 'Error on while calling mass_export, uploading file '
268
- . $data['filename'] . ", details returned from EmailVision: " . $uploadStatus['details'];
 
 
 
 
269
  }
270
  }
271
  } while ($uploadProcessing);
272
-
273
- // move uploaded file
274
- $this->moveUploadedFile($data);
275
  }
276
  }
 
 
 
 
277
  } catch (Exception $e) {
278
- $uploadDone = false;
279
  Mage::logException($e);
280
 
281
- $this->_errors[] = "Exception while calling mass_export in file uploading process, with message: "
282
  . $e->getMessage();
283
  }
284
 
285
- // Update all subscribersUpdateDate for files uploaded with success
286
- $this->massSetMemberLastUpdateDate($exportedFileTime);
287
 
288
- if ($service) {
289
- try {
290
- $service->closeApiConnection();
291
- } catch (Exception $e) {
292
- Mage::logException($e);
293
- $this->_errors[] = "Exception while closing SmartFocus service with message : "
294
- . $e->getMessage();
 
 
 
 
 
 
 
 
 
 
 
 
295
  }
296
  }
 
297
 
298
- return $uploadDone;
 
 
 
 
 
 
 
 
 
 
 
 
299
  }
300
 
301
  /**
@@ -318,119 +779,146 @@ class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_Batc
318
  }
319
 
320
  // Preparing filename
321
- $filename = 'customers' . $this->_currentTime . '_part' . $index . '.csv';
322
 
323
  // Preparing file path
324
- $path = Mage::getBaseDir('export') . DS . 'emailvision' . DS . $filename;
 
325
  return array('filename' => $filename, 'path' => $path, 'time' => $this->_currentTime);
326
  }
327
 
328
  /**
329
- * Set member last update date for all updated subscribers
 
 
 
 
 
 
330
  */
331
- public function massSetMemberLastUpdateDate()
332
  {
333
- $subscribersIds = array();
334
- $rejoinedIds = array();
335
-
 
336
  // Cases: mass export will have a _fileNamesUploaded set, member export will have _subsciberIds
337
- if (!empty($this->_fileNamesUploaded)) {
338
- foreach ($this->_fileNamesUploaded as $fileName) {
339
- if (isset($this->_writtenSubscribersIds[$fileName])) {
340
- foreach ($this->_writtenSubscribersIds[$fileName] as $subscriberId) {
341
- $subscribersIds[] = $subscriberId;
342
- if (
343
- isset($this->_subscriberDataList[$subscriberId])
344
- && $this->_subscriberDataList[$subscriberId]['rejoined'] == true
345
- ) {
346
- $rejoinedIds[] = $subscriberId;
 
 
 
347
  }
348
-
349
  }
350
  }
351
  }
352
-
353
- try {
354
- $errorMessage = Mage::helper('emvdatasync/service')->massSetMemberLastUpdateDate($subscribersIds, $rejoinedIds);
355
- if ($errorMessage !== true) {
356
- $this->_errors[] = $errorMessage;
357
- }
358
- } catch (Exception $e) {
359
- Mage::logException($e);
360
- }
361
  }
 
 
362
  }
363
 
364
  /**
365
- * @param array $file
366
- * @return boolean
 
 
 
 
367
  */
368
- public function moveUploadedFile($file)
369
  {
370
- return @rename(
371
- $file['path'],
372
- Mage::getBaseDir('export'). DS . 'emailvision' . DS . 'uploaded' . DS . $file['filename']
373
- );
 
 
 
 
 
 
 
 
 
 
 
374
  }
375
 
376
  /**
377
- * @return Mage_Newsletter_Model_Resource_Subscriber_Collection
 
 
378
  */
379
- public function getSubscriberCollection()
380
  {
381
- /* @var $subscribers Mage_Newsletter_Model_Resource_Subscriber_Collection */
382
- // Get all subscribers that have data modifed since the last sync as well as the unsubscribed ones
383
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection();
 
 
 
 
 
 
 
 
 
384
 
385
- $fieldMemberLastUpdate = Emv_DataSync_Helper_Service::FIELD_MEMBER_LAST_UPDATE;
386
- $fieldUnjoin = Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN;
387
- $fieldDataLastUpdate = Emv_DataSync_Helper_Service::FIELD_DATA_LAST_UPDATE;
388
-
389
- $select = $subscribers->getSelect();
390
- // in the case of member_last_update is not null
391
- // - data_last_update_date > member_last_update => member data has been changed
392
- // - main_table.date_unjoin > member_last_update => member has just unjoined
393
- $notNullMemberCond = "main_table.{$fieldMemberLastUpdate} IS NOT NULL"
394
- . " AND ( main_table.{$fieldDataLastUpdate} > main_table.{$fieldMemberLastUpdate}"
395
- . " OR main_table.{$fieldUnjoin} > main_table.{$fieldMemberLastUpdate}"
396
- . ' )';
397
- $select->where($notNullMemberCond);
398
- $select->orWhere("main_table.{$fieldMemberLastUpdate} IS NULL");
399
 
400
  return $subscribers;
401
  }
402
 
403
  /**
 
 
 
404
  * @return array
405
  */
406
- public function prepareAndGetMappedHeaders()
407
  {
408
- if ($this->_mappedHeaders == null) {
409
- $this->_mappedHeaders = array();
 
 
 
 
 
 
410
 
411
  // retreive all maped attribute values from subscriber, build them into array
412
- $entityFieldsToSelect = Mage::helper('emvdatasync/service')->prepareAndGetMappedCustomerAttributes();
 
413
  foreach ($entityFieldsToSelect as $attribute) {
414
- $emailVisionKey = $attribute->getEmailVisionKey();
415
  $emailVisionKey = strtoupper($emailVisionKey);
416
 
417
- $this->_mappedHeaders[strtoupper($emailVisionKey)] = array(
418
  'to_replace' => true
419
  );
420
  }
421
 
422
  // the entity id can not be replaced
423
  $entityIdField = Mage::helper('emvdatasync')->getMappedEntityId();
424
- $this->_mappedHeaders[strtoupper($entityIdField)] = array(
425
  'to_replace' => false
426
  );
427
 
428
- $this->_mappedHeaders[strtoupper(Emv_Core_Model_Service_Member::FIELD_UNJOIN)] = array(
429
  'to_replace' => true
430
  );
431
  }
432
 
433
- return $this->_mappedHeaders;
434
  }
435
 
436
  /**
3
  * Batch Member service - Handle Member Data
4
  *
5
  * @category Emv
6
+ * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
  class Emv_DataSync_Model_Service_BatchMember extends Emv_Core_Model_Service_BatchMember
11
+ implements Emv_Core_Model_DataProcessing_Profile_Interface
12
  {
13
  /**
14
  * XML config path for performance config
15
  */
16
+ const XML_PATH_PERFORMANCE = 'emvdatasync/batchmember/performance';
17
 
18
  /**
19
  * The default limit of subscribers to get
21
  const PAGE_SIZE = 10000;
22
 
23
  /**
24
+ * Waiting time (seconds) between each status checking call
25
  */
26
+ const WAITING_TIME = 40;
27
 
28
  /**
29
  * @var boolean
37
 
38
  // Subscribers collection management vars
39
  protected $_pageSize;
 
 
40
 
41
  // Files and upload data
 
42
  protected $_errors = array();
43
+
44
+ protected $_exportFilePrefix = '';
45
 
46
  /**
47
  * Mapped headers
50
  protected $_mappedHeaders = array();
51
 
52
  /**
53
+ * Input data for service
54
  * @var array
55
  */
56
+ protected $_inputData = array();
57
 
58
  /**
59
+ * Profile type
60
+ * @var string
61
+ */
62
+ public static $type = Emv_Core_Model_DataProcessing_Process::TYPE_DATA_SYNC;
63
+
64
+ /**
65
+ * Profile title
66
+ * @var string
67
+ */
68
+ protected $_title = 'Batch Member Data Synchronization';
69
+
70
+ /**
71
+ * Current process
72
+ * @var Emv_Core_Model_DataProcessing_Process
73
+ */
74
+ protected $_process = null;
75
+
76
+ /**
77
+ * Process class name
78
+ * @var string
79
  */
80
+ protected $_processClassName = 'emvcore/dataProcessing_process';
81
 
82
  /**
83
  * (non-PHPdoc)
91
  $this->_pageSize = self::PAGE_SIZE;
92
  }
93
 
 
 
 
94
  return parent::_construct();
95
  }
96
 
97
  /**
98
+ * Get default profile process
99
+ *
100
+ * @return Emv_Core_Model_DataProcessing_Process $process
101
  */
102
+ public function initProcess()
103
  {
104
+ $process = Mage::getModel($this->_processClassName);
105
+ $process->setTitle($this->_title);
106
+ $process->setType(self::$type);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
107
 
108
+ $process->save();
109
+ return $process;
110
+ }
111
 
112
+ /**
113
+ * Init profile
114
+ *
115
+ * @param Emv_Core_Model_DataProcessing_Process $process
116
+ *
117
+ * @return void
118
+ * @throws Exception
119
+ */
120
+ public function init(Emv_Core_Model_DataProcessing_Process $process = null)
121
+ {
122
+ if (is_null($process)) {
123
+ $process = $this->initProcess();
124
+ }
125
 
126
+ $process->initLog();
127
+ $this->_process = $process;
128
+ }
 
 
 
 
 
 
 
 
 
 
 
129
 
130
+ /**
131
+ * (non-PHPdoc)
132
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::getInputData()
133
+ */
134
+ public function getInputData()
135
+ {
136
+ return $this->_inputData;
137
+ }
138
+
139
+ /**
140
+ * (non-PHPdoc)
141
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::setInputData()
142
+ */
143
+ public function setInputData(array $input)
144
+ {
145
+ $this->_inputData = $input;
146
+ return $this;
147
+ }
148
+
149
+ /**
150
+ * Get Associated Process
151
+ * (non-PHPdoc)
152
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::getProcess()
153
+ */
154
+ public function getProcess()
155
+ {
156
+ return $this->_process;
157
+ }
158
+
159
+ /**
160
+ * Run the process of mass subscriber export
161
+ * - if member_ids is defined and an array, only the subscribers in this list are synced
162
+ * - if dry_mode is defined and contains true, we only create the csv files, no sync will be done at SmartFocus
163
+ * - if test_mode is defined, we run the process in test mode
164
+ *
165
+ * (non-PHPdoc)
166
+ * @see Emv_Core_Model_DataProcessing_Profile_Interface::run()
167
+ */
168
+ public function run()
169
+ {
170
+ $inputData = $this->getInputData();
171
+
172
+ $memberIds = array();
173
+ if(isset($inputData['member_ids']) && is_array($inputData['member_ids'])) {
174
+ $memberIds = $inputData['member_ids'];
175
+ }
176
+
177
+ $dryMode = false;
178
+ if (isset($inputData['dry_mode'])) {
179
+ $dryMode = $inputData['dry_mode'];
180
+ }
181
+
182
+ $testMode = false;
183
+ if (isset($inputData['test_mode'])) {
184
+ $testMode = $inputData['test_mode'];
185
+ }
186
+
187
+ $this->massExportCustomers($memberIds, $dryMode, $testMode);
188
+
189
+ }
190
+
191
+ /**
192
+ * Export customers, by default if member id list is empty, we only take the scheduled members
193
+ *
194
+ * @param array $memberIds - which subscribers/members are allowed to sync
195
+ * @param boolean $dryMode - only allows to create csv file(s), no sync will be triggered
196
+ * @param boolean $testMode - run the export in test mode
197
+ * @param array - sorted by account id
198
+ * for each account, we have :
199
+ * - treated_files : all the files (path, name, label) have been created
200
+ * - uploaded_subscribers : the number of subscribers that have been correctly synced
201
+ */
202
+ public function massExportCustomers(array $memberIds = array(), $dryMode = false, $testMode = false)
203
+ {
204
+ // Set new title
205
+ if ($this->getProcess()) {
206
+ if ($dryMode) {
207
+ $this->getProcess()->setTitle($this->_title . ' - Dry Mode');
208
+ }
209
+ if ($testMode) {
210
+ $this->getProcess()->setTitle($this->_title . ' - Manual Sync');
211
+ }
212
+ // run process
213
+ $this->getProcess()->run();
214
+ }
215
+
216
+ // get all active account for batch member service
217
+ $accounts = Mage::helper('emvdatasync')->getActiveEmvAccountsForStore(Emv_DataSync_Helper_Data::TYPE_BATCH);
218
+
219
+ // prepare final export info array
220
+ $exportInfo = array();
221
+ $this->_errors = array();
222
+
223
+ $percentForEachAccount = 100;
224
+ if (count($accounts)) {
225
+ $percentForEachAccount = 100 / count($accounts);
226
+ }
227
+
228
+ // the current percentage of the process
229
+ $currentPercent = 0;
230
+
231
+ $this->_updateProcess('Start Process');
232
+ foreach ($accounts as $accountId => $accountData)
233
+ {
234
+ $storeIds = $accountData['stores'];
235
+ $account = $accountData['model'];
236
+ $service = false;
237
+ $currentStore = $storeIds[0];
238
+ $totalTreatedSubscribers = array(
239
+ 'treated_subscribers' => array(),
240
+ 'rejoined_subscribers' => array(),
241
+ );
242
+
243
+ $exportInfo[$accountId] = array(
244
+ 'treated_files' => array(),
245
+ 'uploaded_subscribers' => 0,
246
+ );
247
+
248
+ $this->_updateProcess('Start proceeding account "' . $account->getName() . '"');
249
+
250
+ try {
251
+ // Get api service corresponding to current account
252
+ $service = $this->getApiService($account, $storeIds[0]);
253
+ } catch (Exception $e) {
254
+ $this->_errors[] = "The account {$account->getName()} is invalid : " . $e->getMessage();
255
+ }
256
+
257
+ if (!$service) {
258
+ $currentPercent = $currentPercent + $percentForEachAccount;
259
+ } else {
260
+ // only get subscribers from the associated stores
261
+ $subscribers = $subscribers = $this->getSubscriberCollection($memberIds, $storeIds);
262
+ $currentPercent = $currentPercent + (0.03 * $percentForEachAccount);
263
+ $this->_updateProcess('Prepare Subscriber Collection', Zend_Log::INFO, $currentPercent);
264
+
265
+ // Add all customer and address attributes that have been mapped into collection
266
+ Mage::getSingleton('emvdatasync/attributeProcessing_config')
267
+ ->prepareSubscriberCollection($subscribers, $currentStore);
268
+ $currentPercent = $currentPercent + (0.07 * $percentForEachAccount);
269
+ $this->_updateProcess('Add mapping attributes into collection', Zend_Log::INFO, $currentPercent);
270
+
271
+ // calculate the number of pages to export
272
+ $pageCount = ceil($subscribers->getSize() / $this->_pageSize);
273
+ $this->_updateProcess(
274
+ 'Collection contains ' . (int)$subscribers->getSize() . ' subscribers'
275
+ . ' divided in ' . $pageCount . ' pages (' . $this->_pageSize . ' members/page)'
276
+ );
277
+
278
+ if ($subscribers->getSize() == 0) {
279
+ $currentPercent = $currentPercent + (0.97 * $percentForEachAccount);
280
+ } else {
281
+
282
+ // everything should be in GMT
283
+ $this->_currentTime = Mage::getModel('core/date')->gmtDate('Ymd_H-i-s');
284
+ // make a new file prefix
285
+ $this->_exportFilePrefix = 'magento_account_' . $account->getId() . '_';
286
+
287
+ $percentForEachPage = 0.9 * $percentForEachAccount / $pageCount;
288
+ for ($curPage = 1; $curPage <= $pageCount; $curPage++) {
289
+ $this->_updateProcess('Start Proceeding Page ' . $curPage);
290
+
291
+ // Define current page
292
+ $subscribers->clear()
293
+ ->setPageSize($this->_pageSize)
294
+ ->setCurPage($curPage);
295
+ $this->_updateProcess('Get subscriber list');
296
+
297
+ $this->_updateProcess('Creating csv files');
298
+ // prepare csv files
299
+ $arrayReturn = $this->prepareCustomerCsvFiles($subscribers, $currentStore, $service);
300
+ $this->_errors = array_merge($arrayReturn['errors'], $this->_errors);
301
+
302
+ // update process for creating file step
303
+ $currentPercent = $currentPercent + (0.2 * $percentForEachPage);
304
+ $this->_updateProcessWhileCreatingFiles($arrayReturn, $currentPercent);
305
+
306
+ if ($dryMode) {
307
+ $currentPercent = $currentPercent + (0.8 * $percentForEachPage);
308
+
309
+ $this->_prepareOutputInfo(
310
+ $exportInfo[$accountId],
311
+ array(),
312
+ $arrayReturn
313
+ );
314
+ $this->_updateProcess('Prepare final export information');
315
+
316
+ } else {
317
+ $this->_updateProcess('Uploading csv files');
318
+ // send file and get status upload
319
+ $uploadInfo = $this->sendFileAndGetStatusUpload(
320
+ $arrayReturn['created_files'],
321
+ $currentStore,
322
+ $service
323
+ );
324
+ $this->_errors = array_merge($uploadInfo['errors'], $this->_errors);
325
+
326
+ // update process for uploading file step
327
+ $currentPercent = $currentPercent + (0.7 * $percentForEachPage);
328
+ $this->_updateProcess('Uploading files is done.', Zend_Log::INFO, $currentPercent);
329
+ $this->_updateProcessWhileUploadingFiles(
330
+ $uploadInfo,
331
+ $arrayReturn['writtent_subscriber_ids']
332
+ );
333
+
334
+ // move proceeded files to new placements
335
+ $this->treatProceededFiles($uploadInfo);
336
+ // update process for uploading file step
337
+ $currentPercent = $currentPercent + (0.1 * $percentForEachPage);
338
+ $this->_updateProcess('Treat uploaded files ', Zend_Log::INFO, $currentPercent);
339
+
340
+ // prepare treated subscriber list
341
+ $treatedList = $this->getTreatedSubscribers (
342
+ $uploadInfo['uploaded_files'],
343
+ $arrayReturn['writtent_subscriber_ids'],
344
+ $arrayReturn['subscriber_data_list']
345
+ );
346
+ $totalTreatedSubscribers['treated_subscribers'] = array_merge(
347
+ $treatedList['treated_subscribers'],
348
+ $totalTreatedSubscribers['treated_subscribers']
349
+ );
350
+ $totalTreatedSubscribers['rejoined_subscribers'] = array_merge(
351
+ $treatedList['rejoined_subscribers'],
352
+ $totalTreatedSubscribers['rejoined_subscribers']
353
+ );
354
+
355
+ // prepare out put information
356
+ $this->_prepareOutputInfo(
357
+ $exportInfo[$accountId],
358
+ $uploadInfo,
359
+ $arrayReturn
360
+ );
361
+ $this->_updateProcess('Prepare final export information');
362
+
363
+ unset($uploadInfo);
364
+ }
365
+
366
+ unset($arrayReturn);
367
+ $this->_updateProcess('End Proceeding Page ' . $curPage, Zend_Log::INFO, $currentPercent);
368
  }
 
 
369
 
370
+ // clear all fetched data
371
+ $subscribers->getSelect()->reset();
372
+ $subscribers->resetData()->clear();
373
+ unset($subscribers);
374
+ Mage::getSingleton('emvdatasync/attributeProcessing_config')
375
+ ->cleanMappedCustomerAttributes($currentStore);
376
+ $this->_updateProcess('Clean proceeded data');
377
+ } // subscriber collection is not empty
378
+
379
+ if (count($totalTreatedSubscribers['treated_subscribers'])) {
380
+ $errors = $this->massSetMemberLastUpdateDate(
381
+ $totalTreatedSubscribers['treated_subscribers'],
382
+ $totalTreatedSubscribers['rejoined_subscribers']
383
  );
384
+ $this->_errors = array_merge($errors, $this->_errors);
385
 
386
+ $this->_updateProcess('Flag uploaded subscribers');
387
+ if (count($errors)) {
388
+ $error = "Process has encoutered the following errors when flagging uploaded subsscribers : \n"
389
+ . implode("\n", $errors);
390
+ $this->_updateProcess($error);
391
  }
392
+ }
393
+
394
+ unset($totalTreatedSubscribers);
395
+
396
+ try {
397
+ $service->closeApiConnection();
398
  } catch (Exception $e) {
399
  Mage::logException($e);
400
+ $this->_errors[] = "Exception while closing SmartFocus service for account {{$account->getName()}} with message : "
401
+ . $e->getMessage();
402
+ }
403
+ } // end if service
404
+
405
+ $this->_updateProcess('Total of uploaded files : ' . count($exportInfo[$accountId]['treated_files']));
406
+ $this->_updateProcess('Total of uploaded subscribers : ' . $exportInfo[$accountId]['uploaded_subscribers']);
407
+ $this->_updateProcess('End proceeding account "' . $account->getName() . '"', Zend_Log::INFO, $currentPercent);
408
+ $this->_updateProcess('*************************');
409
+ }
410
 
411
+ // add output information into process and finalize it
412
+ if ($this->getProcess()) {
413
+ foreach ($exportInfo as $infoByAccount) {
414
+ foreach ($infoByAccount['treated_files'] as $fileOutput) {
415
+ $this->getProcess()->addOutputInformation($fileOutput);
416
  }
417
+ }
418
+ $this->getProcess()->finalize();
419
  }
420
+ $this->_updateProcess('End Process', Zend_Log::INFO, 100);
421
+
422
+ return $exportInfo;
423
  }
424
 
425
  /**
426
+ * Update process with a new message at give level, or/and update status percentage
427
+ * @param string $logMessage
428
+ * @param int $level (@see Zend_Log for more detail)
429
+ * @param int $statusPercent
430
+ */
431
+ protected function _updateProcess($logMessage, $level = Zend_Log::INFO, $statusPercent = 0)
432
+ {
433
+ if ($this->getProcess()) {
434
+ $this->getProcess()->getLog()->log($logMessage, $level);
435
+ if ($statusPercent > 0) {
436
+ $this->getProcess()->updateStatus($statusPercent);
437
+ }
438
+ }
439
+ }
440
+
441
+ /**
442
+ * Update process for creating file step
443
  *
444
+ * @param array $createdData
445
+ * - created_files : all file data will be stored in this array, each file will have the following information :
446
+ * - filename
447
+ * - path
448
+ * - time
449
+ * - writtent_subscriber_ids
450
+ *
451
+ * @param int $currentPercent - the current percentage
452
  */
453
+ protected function _updateProcessWhileCreatingFiles($createdData, $currentPercent)
454
  {
455
+ $list = '';
456
+ if (count($createdData['created_files'])) {
457
+ $list = ' List of created files : ';
458
+ foreach ($createdData['created_files'] as $fileData) {
459
+ $list .= $fileData['filename'];
460
+ }
461
+ }
462
+ $this->_updateProcess(
463
+ count($createdData['created_files']) . ' csv files have been created.' . $list,
464
+ Zend_Log::INFO,
465
+ $currentPercent
466
+ );
467
+ if (count($createdData['errors'])) {
468
+ $error = "Process has encoutered the following errors when creating files : \n"
469
+ . implode("\n", $createdData['errors']);
470
+ $this->_updateProcess($error, Zend_Log::ERR);
471
  }
 
472
  }
473
 
474
  /**
475
+ * Update process for uploading file step
476
+ *
477
+ * @param array $uploadInfo
478
+ * @param array $writtenSubscribers
479
  */
480
+ protected function _updateProcessWhileUploadingFiles($uploadInfo, $writtenSubscribers)
481
  {
482
+ if (count($uploadInfo['uploaded_files'])) {
483
+ $uploadedFilesStatus = 'List of correctly uploaded files :';
484
+ foreach ($uploadInfo['uploaded_files'] as $fileData) {
485
+ $uploadedFilesStatus .= $fileData['file_data']['filename'];
486
+ if (
487
+ isset($writtenSubscribers[$fileData['file_data']['filename']])
488
+ ) {
489
+ $uploadedFilesStatus .= '('
490
+ .count($writtenSubscribers[$fileData['file_data']['filename']]).' members)';
491
+ }
492
+ $uploadedFilesStatus .= ' ';
493
+ }
494
+ $this->_updateProcess($uploadedFilesStatus);
495
+ }
496
 
497
+ if (count($uploadInfo['invalid_files'])) {
498
+ $uploadedFilesStatus = 'List of invalid files :';
499
+ foreach ($uploadInfo['invalid_files'] as $fileData) {
500
+ $uploadedFilesStatus .= $fileData['file_data']['filename'];
501
+ if (
502
+ isset($writtenSubscribers[$fileData['file_data']['filename']])
503
+ ) {
504
+ $uploadedFilesStatus .= '('
505
+ .count($writtenSubscribers[$fileData['file_data']['filename']]).')';
506
+ }
507
+ }
508
+ $this->_updateProcess($uploadedFilesStatus);
509
+ }
510
 
511
+ if (count($uploadInfo['errors'])) {
512
+ $error = "Process has encoutered the following errors when uploading files : \n"
513
+ . implode("\n", $uploadInfo['errors']);
514
+ $this->_updateProcess($error, Zend_Log::ERR);
515
+ }
516
+ }
517
 
518
+ /**
519
+ * Prepare output information (file name, lable, path) for the process
520
+ *
521
+ * @param reference to array $exportInfo
522
+ * @param array $uploadInfo
523
+ * @param array $createdFileInfo
524
+ */
525
+ protected function _prepareOutputInfo(&$exportInfo, array $uploadInfo, array $createdFileInfo)
526
+ {
527
+ if (isset($createdFileInfo['created_files'])) {
528
+ foreach($createdFileInfo['created_files'] as $fileData) {
529
+ $exportInfo['treated_files'][$fileData['filename']] = array(
530
+ 'path' => $fileData['path'],
531
+ 'label' => $fileData['filename'],
532
+ 'filename' => $fileData['filename']
533
+ );
534
+ }
535
+ }
536
+
537
+ if (isset($uploadInfo['uploaded_files'])) {
538
+ foreach ($uploadInfo['uploaded_files'] as $fileData) {
539
+ $fileName = $fileData['file_data']['filename'];
540
+ if (isset($exportInfo['treated_files'][$fileName])) {
541
+ $exportInfo['treated_files'][$fileName] = array(
542
+ 'path' => $fileData['file_data']['path'],
543
+ 'label' => $fileName . ' (correctly synced)',
544
+ 'filename' => $fileName
545
+ );
546
 
547
+ if (
548
+ isset($createdFileInfo['writtent_subscriber_ids'])
549
+ && isset($createdFileInfo['writtent_subscriber_ids'][$fileName])
550
+ ) {
551
+ $exportInfo['uploaded_subscribers'] += count(
552
+ $createdFileInfo['writtent_subscriber_ids'][$fileName]
553
+ );
554
+ }
555
+ }
556
+ }
557
+ }
558
+ }
559
+
560
+ /**
561
+ * @param Varien_Data_Collection_Db $subscribers
562
+ * @param string $storeId
563
+ * @param EmailVision_Api_BatchMemberService $service
564
+ * @return array
565
+ * subscriber_data_list => list of subscriber data
566
+ * created_files => list of created files
567
+ * writtent_subscriber_ids => list of subscriber ids by created files
568
+ * errors => list of errors encountered during sync
569
+ */
570
+ public function prepareCustomerCsvFiles($subscribers, $storeId, EmailVision_Api_BatchMemberService $service)
571
+ {
572
+ // list of return data
573
+ $arrayReturn = array(
574
+ 'subscriber_data_list' => array(),
575
+ 'created_files' => array(),
576
+ 'writtent_subscriber_ids' => array(),
577
+ 'errors' => array()
578
+ );
579
+
580
+ // Add a row foreach customer
581
+ $preparedData = array();
582
+ foreach ($subscribers as $subscriber) {
583
+ // Replace customer email by suscriber one
584
+ $subscriber->setData('email', $subscriber->getSubscriberEmail());
585
+ $subscriberData = Mage::getSingleton('emvdatasync/attributeProcessing_config')
586
+ ->getSubscriberData($subscriber, $storeId);
587
+
588
+ $preparedData[] = array(
589
+ 'id' => $subscriber->getId(),
590
+ 'fields' => $subscriberData
591
+ );
592
+
593
+ // add subscriber data into array - this data will allow us to distinguish who rejoined recently
594
+ $tempSubscriber = array(
595
+ 'id' => $subscriber->getId(),
596
+ 'rejoined' => false
597
+ );
598
+ if ($subscriber->getData('subscriber_status') == Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED) {
599
+ if (
600
+ $subscriber->getData(Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN) != ''
601
+ && $subscriber->getData(Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN) != null
602
+ ) {
603
+ $tempSubscriber['rejoined'] = true;
604
+ }
605
+ }
606
+
607
+ $arrayReturn['subscriber_data_list'][$subscriber->getId()] = $tempSubscriber;
608
+ }// end foreach subscribers
609
+
610
+ // Mapped header array
611
+ $mappedHeaders = $this->prepareAndGetMappedHeaders($storeId);
612
  try {
613
+ $csvFileData = $service->createCsvFiles(
614
+ $this,
615
+ array_keys($mappedHeaders),
616
+ $preparedData
617
+ );
618
+
619
+ // prepare array return from created file data
620
+ foreach ($csvFileData as $key => $data) {
621
+ // member list for each file
622
+ $arrayReturn['writtent_subscriber_ids'][$data['file']['filename']] = $data['list_member'];
623
+ $arrayReturn['created_files'][] = $data['file'];
624
+ }
625
+ } catch (Exception $e) {
626
+ Mage::logException($e);
627
+
628
+ $arrayReturn['errors'][] = 'Exception while building csv file, with message: ' . $e->getMessage();
629
+ }
630
+
631
+ return $arrayReturn;
632
+ }
633
 
634
+ /**
635
+ * @param array $filesToUpload
636
+ * @param unknown $storeId
637
+ * @param EmailVision_Api_BatchMemberService $service
638
+ * @param string $closeApi
639
+ * @return array
640
+ */
641
+ public function sendFileAndGetStatusUpload(
642
+ array $filesToUpload = array(),
643
+ $storeId,
644
+ EmailVision_Api_BatchMemberService $service,
645
+ $closeApi = true
646
+ )
647
+ {
648
+ $arrayReturn = array(
649
+ 'merge_criteria' => $this->getMergeCriteriaForBatchMember($storeId),
650
+ 'uploaded_files' => array(),
651
+ 'invalid_files' => array(),
652
+ 'errors' => array()
653
+ );
654
+
655
+ // return
656
+ $uploadDone = true;
657
+ $mappedHeaders = $this->prepareAndGetMappedHeaders($storeId);
658
+
659
+ try {
660
+ foreach ($filesToUpload as $data) {
661
+ $uploadId = $service->sendFileToWebservice(
662
  $data,
663
  $mappedHeaders,
664
+ $arrayReturn['merge_criteria'],
665
  false
666
  );
667
 
668
+ $treatingFileArray = array('file_data' => $data, 'upload_id' => $uploadId, 'status' => false);
669
+
670
  // only checking upload status if we can have upload id
671
+ if ($uploadId != false) {
672
  $uploadProcessing = true;
673
+
674
  // wait until SmartFocus platform completes processing uploaded file
675
  // check status's upload for an interval self::WAITING_TIME
676
  do {
677
  sleep(self::WAITING_TIME);
678
  // get status's upload
679
+ $uploadStatus = $service->getUploadStatus($uploadId, false);
680
 
681
  if (
682
  in_array(
684
  EmailVision_Api_BatchMemberService::getAccomplishedStatuses()
685
  )
686
  ) {
687
+ // update uploading status
688
+ $treatingFileArray['status'] = $uploadStatus['status'];
689
+
690
  $uploadProcessing = false;
691
  if (
692
  $uploadStatus['status'] == EmailVision_Api_BatchMemberService::getStatusOkWithoutError()
693
  ) {
694
+ $arrayReturn['uploaded_files'][] = $treatingFileArray;
695
  } else {
696
+ $arrayReturn['invalid_files'][] = $treatingFileArray;
697
+
698
+ $messageError = 'Error on while uploading file ' . $data['filename'];
699
+ if ($uploadStatus['details']) {
700
+ $messageError .= ", details returned from SmartFocus: " . $uploadStatus['details'];
701
+ }
702
+ $arrayReturn['errors'][] = $messageError;
703
  }
704
  }
705
  } while ($uploadProcessing);
706
+ } else {
707
+ $arrayReturn['invalid_files'][] = $treatingFileArray;
 
708
  }
709
  }
710
+
711
+ if ($closeApi == true) {
712
+ $service->closeApiConnection();
713
+ }
714
  } catch (Exception $e) {
 
715
  Mage::logException($e);
716
 
717
+ $arrayReturn['errors'][] = "Exception during file uploading process, with message: "
718
  . $e->getMessage();
719
  }
720
 
721
+ return $arrayReturn;
722
+ }
723
 
724
+ /**
725
+ * Move the synced files to new placement, update their paths in the array respectively
726
+ *
727
+ * @param array $proceededFiles
728
+ */
729
+ public function treatProceededFiles(array &$proceededFiles)
730
+ {
731
+ if (isset($proceededFiles['uploaded_files'])) {
732
+ foreach ($proceededFiles['uploaded_files'] as $key => $fileData) {
733
+ if (isset($fileData['file_data']['filename']) && $fileData['file_data']['path']) {
734
+ $newPath = Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
735
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR
736
+ . DS . Emv_Core_Helper_Data::UPLOADED_FILE_DIR
737
+ . DS . $fileData['file_data']['filename'];
738
+
739
+ if (@rename($fileData['file_data']['path'],$newPath)) {
740
+ $proceededFiles['uploaded_files'][$key]['file_data']['path'] = $newPath;
741
+ }
742
+ }
743
  }
744
  }
745
+ }
746
 
747
+ /**
748
+ * Get merge criteria for batch member api requests
749
+ * @param int $storeId
750
+ * @return array
751
+ */
752
+ public function getMergeCriteriaForBatchMember($storeId = null)
753
+ {
754
+ if (Mage::helper('emvdatasync')->getEmailEnabled($storeId)) {
755
+ $mergeCriteria = array(strtoupper(Emv_Core_Model_Service_Member::FIELD_EMAIL));
756
+ } else {
757
+ $mergeCriteria = array(strtoupper(Mage::helper('emvdatasync')->getMappedEntityId($storeId)));
758
+ }
759
+ return $mergeCriteria;
760
  }
761
 
762
  /**
779
  }
780
 
781
  // Preparing filename
782
+ $filename = $this->_exportFilePrefix . 'customers' . $this->_currentTime . '_part' . $index . '.csv';
783
 
784
  // Preparing file path
785
+ $path = Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
786
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR . DS . $filename;;
787
  return array('filename' => $filename, 'path' => $path, 'time' => $this->_currentTime);
788
  }
789
 
790
  /**
791
+ * Get treated subscribers (synced and rejoined)
792
+ * @param array $uploadedFileNames
793
+ * @param array $listSubscriberByFiles
794
+ * @param array $subscriberData
795
+ * @return array
796
+ * - treated_subscribers : the total number of synced subscribers
797
+ * - rejoined_subscribers : the list of rejoined subscribers among the synced ones
798
  */
799
+ public function getTreatedSubscribers(array $uploadedFileNames, array $listSubscriberByFiles, array $subscriberData)
800
  {
801
+ $arrayReturn = array(
802
+ 'treated_subscribers' => array(),
803
+ 'rejoined_subscribers' => array()
804
+ );
805
  // Cases: mass export will have a _fileNamesUploaded set, member export will have _subsciberIds
806
+ if (!empty($uploadedFileNames) && count($uploadedFileNames)) {
807
+ foreach ($uploadedFileNames as $fileData) {
808
+ if (isset($fileData['file_data']) && isset($fileData['file_data']['filename'])) {
809
+ $fileName = $fileData['file_data']['filename'];
810
+ if (isset($listSubscriberByFiles[$fileName])) {
811
+ foreach ($listSubscriberByFiles[$fileName] as $subscriberId) {
812
+ $arrayReturn['treated_subscribers'][] = $subscriberId;
813
+ if (
814
+ isset($subscriberData[$subscriberId])
815
+ && $subscriberData[$subscriberId]['rejoined'] == true
816
+ ) {
817
+ $arrayReturn['rejoined_subscribers'][] = $subscriberId;
818
+ }
819
  }
 
820
  }
821
  }
822
  }
 
 
 
 
 
 
 
 
 
823
  }
824
+
825
+ return $arrayReturn;
826
  }
827
 
828
  /**
829
+ * Set member last update date for all exported subscribers
830
+ *
831
+ * @param array $uploadedFileNames
832
+ * @param array $listSubscriberByFiles
833
+ * @param array $subscriberData
834
+ * @return array error
835
  */
836
+ public function massSetMemberLastUpdateDate(array $subscribersIds, array $rejoinedIds)
837
  {
838
+ $errors = array();
839
+ try {
840
+ $errorMessage = Mage::helper('emvdatasync/service')->massSetMemberLastUpdateDate(
841
+ $subscribersIds,
842
+ $rejoinedIds
843
+ );
844
+
845
+ if ($errorMessage !== true) {
846
+ $errors[] = $errorMessage;
847
+ }
848
+ } catch (Exception $e) {
849
+ Mage::logException($e);
850
+ }
851
+
852
+ return $errors;
853
  }
854
 
855
  /**
856
+ * @param array $memberIds
857
+ * @param array $storeIds
858
+ * @return Mage_Newsletter_Model_Mysql4_Subscriber_Collection
859
  */
860
+ public function getSubscriberCollection(array $memberIds = array(), array $storeIds = array())
861
  {
862
+ /* @var $subscribers Mage_Newsletter_Model_Mysql4_Subscriber_Collection */
 
863
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection();
864
+ if (count($memberIds)) {
865
+ $subscribers->addFieldToFilter('subscriber_id', array('in' => $memberIds));
866
+ } else {
867
+ // only get subscirbers that have been scheduled
868
+ $subscribers->addFieldToFilter(
869
+ 'main_table.' . Emv_DataSync_Helper_Service::FIELD_QUEUED,
870
+ Emv_DataSync_Helper_Service::SCHEDULED_VALUE
871
+ );
872
+ }
873
 
874
+ if (count($storeIds)) {
875
+ $subscribers->addFieldToFilter('main_table.store_id', array('in' => $storeIds));
876
+ }
 
 
 
 
 
 
 
 
 
 
 
877
 
878
  return $subscribers;
879
  }
880
 
881
  /**
882
+ * Prepare and get mapped header array
883
+ *
884
+ * @param int $storeId
885
  * @return array
886
  */
887
+ public function prepareAndGetMappedHeaders($storeId = null)
888
  {
889
+ // by default the key will be store id, else will be set to undefined
890
+ $key = $storeId;
891
+ if ($key === null) {
892
+ $key = 'undefined';
893
+ }
894
+
895
+ if (!isset($this->_mappedHeaders[$key])) {
896
+ $this->_mappedHeaders[$key] = array();
897
 
898
  // retreive all maped attribute values from subscriber, build them into array
899
+ $entityFieldsToSelect = Mage::getSingleton('emvdatasync/attributeProcessing_config')
900
+ ->prepareAndGetMappedCustomerAttributes($storeId);
901
  foreach ($entityFieldsToSelect as $attribute) {
902
+ $emailVisionKey = $attribute->getMappedEmailVisionKey();
903
  $emailVisionKey = strtoupper($emailVisionKey);
904
 
905
+ $this->_mappedHeaders[$key][strtoupper($emailVisionKey)] = array(
906
  'to_replace' => true
907
  );
908
  }
909
 
910
  // the entity id can not be replaced
911
  $entityIdField = Mage::helper('emvdatasync')->getMappedEntityId();
912
+ $this->_mappedHeaders[$key][strtoupper($entityIdField)] = array(
913
  'to_replace' => false
914
  );
915
 
916
+ $this->_mappedHeaders[$key][strtoupper(Emv_Core_Model_Service_Member::FIELD_UNJOIN)] = array(
917
  'to_replace' => true
918
  );
919
  }
920
 
921
+ return $this->_mappedHeaders[$key];
922
  }
923
 
924
  /**
app/code/community/Emv/DataSync/Model/Service/DataProcess.php ADDED
@@ -0,0 +1,360 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Data process service
4
+ *
5
+ * @category Emv
6
+ * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
+ */
10
+ class Emv_DataSync_Model_Service_DataProcess
11
+ {
12
+ const XML_PATH_ENABLED_PURCHASE_INFO = 'emvdatasync/purchase_info/enabled';
13
+ const XML_PATH_LIMIT_TABLE_SIZE = 'emvdatasync/purchase_info/limit_size';
14
+ const LIMIT_PAGE_SIZE = 50000;
15
+
16
+ /**
17
+ * Chunk size (the limit number of customers to handle
18
+ * @var int
19
+ */
20
+ public static $chunkSize = 2000;
21
+
22
+ /**
23
+ * List of fields to insert
24
+ * @var array
25
+ */
26
+ protected $_fieldsForInsert = array(
27
+ 'email' ,
28
+ 'customer_id' ,
29
+ 'order_list' ,
30
+
31
+ 'created_at' ,
32
+ 'updated_at' ,
33
+
34
+ 'base_currency_code' ,
35
+
36
+ 'total_order' ,
37
+
38
+ 'total_ordered_item_qty' ,
39
+ 'avg_item_qty' ,
40
+ 'order_amount_total' ,
41
+ 'avg_order_amount_total' ,
42
+ 'discount_amount_total' ,
43
+ 'avg_discount_amount_total' ,
44
+ 'shipping_amount_total' ,
45
+ 'avg_shipping_amount_total' ,
46
+
47
+ 'min_order_amount_total' ,
48
+ 'max_order_amount_total' ,
49
+ 'first_order_date' ,
50
+ 'last_order_date' ,
51
+ 'min_total_ordered_item_qty' ,
52
+ 'max_total_ordered_item_qty' ,
53
+
54
+ 'shipping_list' ,
55
+ 'payment_methods' ,
56
+ 'coupon_list' ,
57
+ 'nb_order_having_discount'
58
+ );
59
+
60
+ /**
61
+ * Is the purchase information process enabled ?
62
+ *
63
+ * @return boolean
64
+ */
65
+ public function enabledPurchaseInformation($storeId = null)
66
+ {
67
+ return Mage::getStoreConfig(self::XML_PATH_ENABLED_PURCHASE_INFO, $storeId);
68
+ }
69
+
70
+ /**
71
+ * Get limit of purchase information records to be stored inside the table
72
+ *
73
+ * @return int
74
+ */
75
+ public function getLimitPurchaseInformationTableSize()
76
+ {
77
+ return Mage::getStoreConfig(self::XML_PATH_LIMIT_TABLE_SIZE);
78
+ }
79
+
80
+ /**
81
+ * Get the customer id list that have correct purchase information
82
+ *
83
+ * @param string $list - indicates if we should return the list
84
+ * @param string $count - indicates if we should return the total number
85
+ * @return array
86
+ */
87
+ public function getOkPurchaseInfoCustomerIdList($list = true, $count = false)
88
+ {
89
+ $resource = Mage::getModel('core/resource');
90
+ $readConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_READ_RESOURCE);
91
+
92
+ $queuedField = Emv_DataSync_Helper_Service::FIELD_QUEUED;
93
+ $select = $readConnection->select();
94
+ $select
95
+ ->from(array('main_table' => $resource->getTableName('emvdatasync/purchase_info')), array())
96
+ ->join(
97
+ array('newsletter' => $resource->getTableName('newsletter/subscriber')),
98
+ 'main_table.customer_id = newsletter.customer_id
99
+ AND newsletter.date_last_purchase < main_table.updated_at',
100
+ array()
101
+ )
102
+ -> where("$queuedField = ?", Emv_DataSync_Helper_Service::SCHEDULED_VALUE);
103
+
104
+ if ($list) {
105
+ $select->columns(array('main_table.customer_id'));
106
+ }
107
+ if ($count) {
108
+ $select->columns('COUNT(*)');
109
+ }
110
+
111
+ return $readConnection->fetchCol($select);
112
+ }
113
+
114
+ /**
115
+ * @return array
116
+ */
117
+ public function numberOfRecordsInPurchaseInfoTable()
118
+ {
119
+ $resource = Mage::getModel('core/resource');
120
+ $readConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_READ_RESOURCE);
121
+
122
+ $select = $readConnection->select();
123
+ $select->from(array('main_table' => $resource->getTableName('emvdatasync/purchase_info')), array('COUNT(*)'));
124
+
125
+ return $readConnection->fetchCol($select);
126
+ }
127
+
128
+ /**
129
+ * Remove useless purchase information
130
+ * - The subscribers that haven't been scheduled
131
+ * - The purchase date is outdated
132
+ *
133
+ * @return int - the number of rows which have been removed
134
+ */
135
+ public function removeUselessPurchaseInfo()
136
+ {
137
+ $resource = Mage::getModel('core/resource');
138
+ $writeConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE);
139
+
140
+ $select = $writeConnection->select();
141
+ $select
142
+ ->from(array('purchase' => $resource->getTableName('emvdatasync/purchase_info')), array())
143
+ ->joinLeft(
144
+ array('subscriber' => $resource->getTableName('newsletter/subscriber')),
145
+ 'purchase.customer_id = subscriber.customer_id',
146
+ array()
147
+ )
148
+ ->where(
149
+ 'subscriber.subscriber_id IS NULL OR subscriber.queued = ?
150
+ OR subscriber.date_last_purchase > purchase.updated_at',
151
+ Emv_DataSync_Helper_Service::NOT_SCHEDULED_VALUE
152
+ )
153
+ ;
154
+ $select->reset(Zend_Db_Select::DISTINCT);
155
+ $select->reset(Zend_Db_Select::COLUMNS);
156
+ $deleteQuery = sprintf('DELETE purchase %s', $select->assemble());
157
+
158
+ $stmt = $writeConnection->query($deleteQuery);
159
+ $result = $stmt->rowCount();
160
+ return $result;
161
+ }
162
+
163
+ /**
164
+ * Get list of customers to proceed.
165
+ * If $count is given and equal to true => only return the total number of concerning customers
166
+ * else we return the list of customers
167
+ *
168
+ * @param string $count
169
+ * @param int $page (the page to retrieve)
170
+ * @param int $pageSize (the page size)
171
+ * @return array
172
+ */
173
+ public function getListCustomerToProceed($count = false, $page = 1, $pageSize = self::LIMIT_PAGE_SIZE)
174
+ {
175
+ $queuedField = Emv_DataSync_Helper_Service::FIELD_QUEUED;
176
+
177
+ $resource = Mage::getModel('core/resource');
178
+ $readConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_READ_RESOURCE);
179
+
180
+ $select = $readConnection->select();
181
+ $select->from(
182
+ array('main_table' => $resource->getTableName('newsletter/subscriber')),
183
+ array()
184
+ )
185
+ ->joinLeft(
186
+ array('purchase' => $resource->getTableName('emvdatasync/purchase_info')),
187
+ 'purchase.customer_id = main_table.customer_id',
188
+ array()
189
+ )
190
+ ->where('main_table.customer_id > 0')
191
+ ->where("$queuedField = ?", Emv_DataSync_Helper_Service::SCHEDULED_VALUE)
192
+ ->where('main_table.date_last_purchase IS NOT NULL')
193
+ // when member does not have calculated purchase information or, this information is outdated
194
+ ->where('purchase.id IS NULL OR purchase.updated_at < main_table.date_last_purchase')
195
+ ;
196
+
197
+ if ($count) {
198
+ $select->columns('COUNT(*)');
199
+ } else {
200
+ $select->columns('customer_id');
201
+ $select->limitPage($page, $pageSize);
202
+ }
203
+
204
+ return $readConnection->fetchCol($select);
205
+ }
206
+
207
+ /**
208
+ * Prepare and return the select to calculate purchase information
209
+ * (for now, we only accept the calculation for 1 global currency code)
210
+ *
211
+ * @param array $customerList
212
+ * @return Zend_Db_Select|boolean
213
+ */
214
+ public function getSelectToCalculatePurchaseInformation($customerList = array())
215
+ {
216
+ if (is_array($customerList) && count($customerList)) {
217
+ $resource = Mage::getModel('core/resource');
218
+ $readConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_READ_RESOURCE);
219
+ $select = $readConnection->select();
220
+
221
+ $gmtDate = Mage::getModel('core/date')->gmtDate();
222
+ $select->from(
223
+ array('flat_order' => $resource->getTableName('sales/order')),
224
+ array(
225
+ 'email' => "GROUP_CONCAT( DISTINCT flat_order.customer_email SEPARATOR '|' )",
226
+ 'customer_id' => 'flat_order.customer_id',
227
+ 'order_list' => "GROUP_CONCAT( DISTINCT flat_order.increment_id SEPARATOR '|' )",
228
+
229
+ new Zend_Db_Expr('"' . $gmtDate . '" as created_at'),
230
+ new Zend_Db_Expr('"' . $gmtDate . '" as updated_at'),
231
+
232
+ 'base_currency_code' => "GROUP_CONCAT( DISTINCT flat_order.base_currency_code SEPARATOR '|' )",
233
+
234
+ 'total_order' => 'COUNT(flat_order.entity_id)',
235
+
236
+ 'total_ordered_item_qty' => 'SUM(flat_order.total_item_count)',
237
+ 'avg_item_qty' => 'AVG(flat_order.total_item_count)',
238
+ 'order_amount_total' => 'SUM(flat_order.base_grand_total)',
239
+ 'avg_order_amount_total' => 'AVG(flat_order.base_grand_total)',
240
+ 'discount_amount_total' => 'ABS(SUM(flat_order.base_discount_amount))',
241
+ 'avg_discount_amount_total' => 'ABS(AVG(flat_order.base_discount_amount))',
242
+ 'shipping_amount_total' => 'SUM(flat_order.base_shipping_amount)',
243
+ 'avg_shipping_amount_total' => 'AVG(flat_order.base_shipping_amount)',
244
+
245
+ 'min_order_amount_total' => 'MIN(flat_order.base_grand_total)',
246
+ 'max_order_amount_total' => 'MAX(flat_order.base_grand_total)',
247
+ 'first_order_date' => 'MIN(flat_order.created_at)',
248
+ 'last_order_date' => 'MAX(flat_order.created_at)',
249
+ 'min_total_ordered_item_qty' => 'MIN(flat_order.total_item_count)',
250
+ 'max_total_ordered_item_qty' => 'MAX(flat_order.total_item_count)',
251
+
252
+ 'shipping_list' => "GROUP_CONCAT( DISTINCT flat_order.shipping_description SEPARATOR '|' )",
253
+ 'payment_methods' => "GROUP_CONCAT( DISTINCT payment.method SEPARATOR '|' )",
254
+ 'coupon_list' => "GROUP_CONCAT( DISTINCT flat_order.coupon_code SEPARATOR '|' )",
255
+ 'nb_order_having_discount' => 'COUNT(coupon_code)'
256
+ )
257
+ )
258
+ ->join(
259
+ array('subscriber' => $resource->getTableName('newsletter/subscriber')),
260
+ 'subscriber.customer_id = flat_order.customer_id',
261
+ array()
262
+ ) // only prepare data for subscriber
263
+ ->join(
264
+ array('payment' => $resource->getTableName('sales/order_payment')),
265
+ 'payment.parent_id = flat_order.entity_id',
266
+ array()
267
+ ) // get used payment methods
268
+ ->group(array('flat_order.customer_id'))
269
+ ->where('flat_order.customer_id IN (?)', $customerList);
270
+ ;
271
+
272
+ return $select;
273
+ }
274
+
275
+ return false;
276
+ }
277
+
278
+ /**
279
+ * Proceed purchase information for a given customer list
280
+ *
281
+ * @param array $customerList
282
+ */
283
+ public function proceedPurchaseInfoForList($customerList = array())
284
+ {
285
+ $resource = Mage::getModel('core/resource');
286
+ $writeConnection = $resource->getConnection(Mage_Core_Model_Resource::DEFAULT_WRITE_RESOURCE);
287
+
288
+ // split email list into small chunk to easily handle
289
+ $chunkList = array_chunk($customerList, self::$chunkSize);
290
+
291
+ foreach ($chunkList as $list) {
292
+ $select = $this->getSelectToCalculatePurchaseInformation($list);
293
+ if ($select) {
294
+ $insert = sprintf(
295
+ "INSERT INTO `%s` (%s) %s",
296
+ $resource->getTableName('emvdatasync/purchase_info'),
297
+ implode(', ', $this->_fieldsForInsert),
298
+ $select->assemble()
299
+ );
300
+ $writeConnection->query($insert);
301
+ }
302
+ }
303
+ }
304
+
305
+ /**
306
+ * Start the whole process to proceed purchase information
307
+ */
308
+ public function prepareList()
309
+ {
310
+ $errorList = array();
311
+ if ($this->enabledPurchaseInformation()) {
312
+ try {
313
+ // the number of clients will be proceeded
314
+ $nbToTreat = $this->getListCustomerToProceed(true);
315
+ if (is_array($nbToTreat) && count($nbToTreat) && $nbToTreat[0] > 0) {
316
+ $limit = $this->getLimitPurchaseInformationTableSize();
317
+
318
+ // the number of left records to treat
319
+ $nbRest = 0;
320
+
321
+ // clean useless information
322
+ $this->removeUselessPurchaseInfo();
323
+ // the number of existing records
324
+ $nbExisting = $this->numberOfRecordsInPurchaseInfoTable();
325
+
326
+ if (is_array($nbExisting) && count($nbExisting)) {
327
+ if ($nbExisting[0] + $nbToTreat[0] <= $limit) {
328
+ $nbRest = $nbToTreat[0];
329
+ } else {
330
+ if ($limit > $nbExisting[0]) {
331
+ $nbRest = $limit - $nbExisting[0];
332
+ }
333
+ }
334
+ }
335
+
336
+ $nbPages = ceil($nbRest/self::LIMIT_PAGE_SIZE);
337
+ $nbTaken = 0;
338
+ for ($curPage = 1; $curPage <= $nbPages; $curPage++) {
339
+ // always take the first page
340
+ $customerList = $this->getListCustomerToProceed(false, 0, self::LIMIT_PAGE_SIZE);
341
+
342
+ $nbToTake = $nbRest - $nbTaken;
343
+ if ($nbToTake < self::LIMIT_PAGE_SIZE) {
344
+ $this->proceedPurchaseInfoForList(array_slice($customerList, 0, $nbToTake));
345
+ $nbTaken += $nbToTake;
346
+ } else {
347
+ $this->proceedPurchaseInfoForList($customerList);
348
+ $nbTaken += self::LIMIT_PAGE_SIZE;
349
+ }
350
+ }
351
+ }
352
+ } catch (Exception $e) {
353
+ Mage::logException($e);
354
+ $errorList[] = $e->getMessage();
355
+ }
356
+ }
357
+
358
+ return $errorList;
359
+ }
360
+ }
app/code/community/Emv/DataSync/Model/Service/Member.php CHANGED
@@ -3,46 +3,53 @@
3
  * Member service - Handle Member Data
4
  *
5
  * @category Emv
6
- * @package Emv_Core
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
  class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
11
  {
12
- protected $_subscribersIdsUpdated = array();
13
- protected $_subscribersIdsUnjoined = array();
14
- protected $_subscribersIdsRejoined = array();
15
-
16
  protected $_errors = array();
17
 
18
  /**
19
  * This method will get subscribers that require data update to EmailVision platform
20
  * and manage the api calls in order to insert or update the data
21
  *
22
- * @return Array $_subscribersIdsUpdated An array contains the subscribers ids updated with success
 
 
 
 
23
  */
24
- public function exportSubscribers()
25
  {
26
  $size = false;
 
27
  try {
28
  // Subscribers that never have been sync || that have been update more recently than their last sync
29
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
30
- ->addFieldToFilter('main_table.' . Emv_DataSync_Helper_Service::FIELD_MEMBER_LAST_UPDATE,
31
- array(
32
- array('null'=> true),
33
- array('lt'=> new Zend_Db_Expr('main_table.' . Emv_DataSync_Helper_Service::FIELD_DATA_LAST_UPDATE))
34
- )
35
- )
36
  ->addFieldToFilter(
37
  'main_table.subscriber_status',
38
  array(
39
  array('eq' => Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED)
40
  )
41
  );
 
 
 
 
 
 
 
 
 
 
 
42
  $size = $subscribers->getSize();
43
  if ($size) {
44
  // Add all customer and address attributes that have been mapped into collection
45
- Mage::helper('emvdatasync/service')->addCustomerAndAddressAttributes($subscribers);
 
46
  }
47
  } catch (Exception $e) {
48
  Mage::logException($e);
@@ -52,7 +59,10 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
52
  if ($size) {
53
  foreach ($subscribers as $subscriber) {
54
  try {
55
- $this->_insertOrUpdateMember($subscriber);
 
 
 
56
  } catch (Exception $e) {
57
  Mage::logException($e);
58
 
@@ -62,7 +72,7 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
62
  }
63
  }
64
 
65
- return $this->_subscribersIdsUpdated;
66
  }
67
 
68
  /**
@@ -72,19 +82,18 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
72
  * @param Mage_Newsletter_Model_Subscriber $subscriber
73
  * @return array
74
  */
75
- public function getMergeCriteriaForMember(Mage_Newsletter_Model_Subscriber $subscriber)
76
  {
77
- if (Mage::helper('emvdatasync')->getEmailEnabled()) {
78
  $mergeCriteria = array(strtoupper(Emv_Core_Model_Service_Member::FIELD_EMAIL) => $subscriber->getEmail());
79
  } else {
80
  $mergeCriteria = array(
81
- strtoupper(Mage::helper('emvdatasync')->getMappedEntityId()) => $subscriber->getId()
82
  );
83
  }
84
  return $mergeCriteria;
85
  }
86
 
87
-
88
  /**
89
  * Method to call insert or update on subscriber passed as param
90
  *
@@ -93,60 +102,27 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
93
  *
94
  * @return string | boolean $result The soap call result
95
  */
96
- protected function _insertOrUpdateMember(Mage_Newsletter_Model_Subscriber $subscriber, $closeApi = false)
 
 
 
 
 
97
  {
98
- $params = array();
99
-
100
  // Replace customer email by suscriber one
101
  $subscriber->setData('email', $subscriber->getSubscriberEmail());
102
 
103
- // retreive all maped attribute values from subscriber, build them into array
104
- $entityFieldsToSelect = Mage::helper('emvdatasync/service')->prepareAndGetMappedCustomerAttributes();
105
- if ($entityFieldsToSelect && $entityFieldsToSelect->count() > 0) {
106
- // get list of all available stores
107
- $stores = Mage::app()->getStores(true);
108
-
109
- foreach($entityFieldsToSelect as $attribute) {
110
- $emailVisionKey = $attribute->getEmailVisionKey();
111
- $emailVisionKey = strtoupper($emailVisionKey);
112
-
113
- $fieldCode = ($attribute->getFinalAttributeCode())
114
- ? $attribute->getFinalAttributeCode() : $attribute->getAttributeCode();
115
-
116
- $fieldValue = '';
117
-
118
- if ($attribute->getFrontendInput() == 'date') {
119
- if ($subscriber->getData($fieldCode)) {
120
- // date time should be in EmailVision format
121
- $fieldValue = Mage::helper('emvdatasync/service')
122
- ->getEmailVisionDate($subscriber->getData($fieldCode));
123
- }
124
- } else {
125
- $fieldValue = $subscriber->getData($fieldCode);
126
- if ($fieldCode == 'store_id' && isset($stores[$fieldValue])) {
127
- // get store code
128
- $fieldValue = $stores[$fieldValue]->getCode();
129
- }
130
- }
131
-
132
- $params[$emailVisionKey] = $fieldValue;
133
- }
134
-
135
- // entity id
136
- $params[strtoupper(Mage::helper('emvdatasync')->getMappedEntityId())] = $subscriber->getId();
137
- }
138
 
139
  // make api call with all prepared array (mapped attributes and criteria)
140
  try {
141
  $uploadId = null;
142
- $service = $this->getApiService($this->getAccount());
143
  $uploadId = $service->insertOrUpdateMemberByObj(
144
- $this->getMergeCriteriaForMember($subscriber),
145
  $params,
146
  $closeApi
147
  );
148
-
149
- $this->_subscribersIdsUpdated[] = $subscriber->getId();
150
  } catch (Exception $e) {
151
  Mage::logException($e);
152
 
@@ -158,29 +134,39 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
158
  }
159
 
160
  /**
161
- * Unjoin all unsubscribed members from EmailVision platform
162
  *
 
 
 
163
  * @param boolean $closeApi
164
- * @return Array $_subscribersIdsUnjoined An array containing the subscribers ids unjoined with success
165
  */
166
- public function unjoinSubscribers()
 
 
 
167
  {
 
168
  try {
169
  // Subscribers that have unjoined more recently than their last sync
170
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
171
- ->addFieldToFilter(
172
- 'main_table.' . Emv_DataSync_Helper_Service::FIELD_DATE_UNJOIN,
173
- array(
174
- array('gt' => new Zend_Db_Expr('main_table.' . Emv_DataSync_Helper_Service::FIELD_MEMBER_LAST_UPDATE))
175
- )
176
- )
177
- ->addFieldToFilter(
178
- 'main_table.subscriber_status',
179
- array(
180
- array('eq' => Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED),
181
- )
182
  );
183
- $subscribers->load();
 
 
 
 
184
  } catch (Exception $e) {
185
  Mage::logException($e);
186
  $this->_errors[] = 'Exception while retreiving data for subscribers to unjoin with message: ' . $e->getMessage();
@@ -188,9 +174,9 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
188
 
189
  foreach ($subscribers as $subscriber) {
190
  try {
191
- $this->unjoinOneSubscriber($subscriber, false);
192
 
193
- $this->_subscribersIdsUnjoined[] = $subscriber->getId();
194
  } catch (Exception $e) {
195
  Mage::logException($e);
196
  $this->_errors[] = 'Exception while preparing data to call unjoin, for subscriber '
@@ -198,21 +184,26 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
198
  }
199
  }
200
 
201
- return $this->_subscribersIdsUnjoined;
202
  }
203
 
204
  /**
205
  * Unjoin member from EmailVision platform
206
  *
207
  * @param Mage_Newsletter_Model_Subscriber $subscriber
 
 
208
  * @param boolean $closeApi
209
  * @return Emv_DataSync_Model_Service_Member
210
  */
211
- public function unjoinOneSubscriber(Mage_Newsletter_Model_Subscriber $subscriber, $closeApi = true)
 
 
 
 
212
  {
213
  if ($subscriber->getId()) {
214
- $service = $this->getApiService($this->getAccount());
215
- $service->unjoinMember('object', $this->getMergeCriteriaForMember($subscriber), $closeApi);
216
  }
217
 
218
  return $this;
@@ -221,12 +212,17 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
221
  /**
222
  * Rejoin subscribers to EmailVision platform
223
  * (subscribers that change their status from unsubscribed to subscribe)
224
- *
 
225
  * @param boolean $closeApi
226
- * @return Array $_subscribersIdsRejoined An array containing the subscribers ids rejoined with success
227
  */
228
- public function rejoinSubscribers($closeApi = false)
 
 
 
229
  {
 
230
  try {
231
  // Subscribers which have last sync more recently than unjoin && that are subscribed
232
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
@@ -239,14 +235,21 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
239
  array('eq'=> Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED),
240
  ));
241
 
242
- $subscribers->load();
 
 
 
 
 
 
 
 
 
243
  } catch (Exception $e) {
244
  Mage::logException($e);
245
  $this->_errors[] = 'Exception while retreiving data for subscribers to rejoin with message: ' . $e->getMessage();
246
  }
247
 
248
- $service = $this->getApiService($this->getAccount());
249
-
250
  foreach ($subscribers as $subscriber) {
251
  try {
252
  $memberId = false;
@@ -264,7 +267,7 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
264
  }
265
  if ($memberId) {
266
  $service->rejoinMember('id', $memberId, $closeApi);
267
- $this->_subscribersIdsRejoined[] = $subscriber->getId();
268
  }
269
  } catch (Exception $e) {
270
  Mage::logException($e);
@@ -273,7 +276,7 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
273
  }
274
  }
275
 
276
- return $this->_subscribersIdsRejoined;
277
  }
278
 
279
  /**
@@ -287,16 +290,20 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
287
  /**
288
  * Method to set massively the custom member_last_update_date after a member or a batchmember export
289
  */
290
- public function massSetMemberLastUpdateDate()
 
 
 
 
291
  {
292
  $subscribersIds = array();
293
- foreach ($this->_subscribersIdsUpdated as $subscriberId) {
294
  $subscribersIds[] = $subscriberId;
295
  }
296
- foreach ($this->_subscribersIdsUnjoined as $subscriberId) {
297
  $subscribersIds[] = $subscriberId;
298
  }
299
- foreach ($this->_subscribersIdsRejoined as $subscriberId) {
300
  $subscribersIds[] = $subscriberId;
301
  }
302
  $subscribersIds = array_unique($subscribersIds);
@@ -304,7 +311,7 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
304
  try {
305
  $errorMessage = Mage::helper('emvdatasync/service')->massSetMemberLastUpdateDate(
306
  $subscribersIds,
307
- $this->_subscribersIdsRejoined
308
  );
309
  if ($errorMessage !== true) {
310
  $this->_errors[] = $errorMessage;
@@ -319,19 +326,38 @@ class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
319
  */
320
  public function triggerExport()
321
  {
322
- $this->exportSubscribers();
323
- $this->unjoinSubscribers();
324
- $this->rejoinSubscribers();
325
 
326
- // Update memberLastUpdateDate
327
- $this->massSetMemberLastUpdateDate();
 
 
 
 
328
 
329
- try {
330
- $this->getApiService($this->getAccount())->closeApiConnection();
331
- } catch (Exception $e) {
332
- Mage::logException($e);
333
- $this->_errors[] = "Exception while closing SmartFocus service with message : "
334
- . $e->getMessage();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
335
  }
336
  }
337
  }
3
  * Member service - Handle Member Data
4
  *
5
  * @category Emv
6
+ * @package Emv_DataSync
7
  * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
  * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
  */
10
  class Emv_DataSync_Model_Service_Member extends Emv_Core_Model_Service_Member
11
  {
 
 
 
 
12
  protected $_errors = array();
13
 
14
  /**
15
  * This method will get subscribers that require data update to EmailVision platform
16
  * and manage the api calls in order to insert or update the data
17
  *
18
+ * @param EmailVision_Api_MemberService $service
19
+ * @param array $storeIds
20
+ * @param string $currentStore
21
+ * @param boolean $closeApi
22
+ * @return Array - An array contains the subscribers ids updated with success
23
  */
24
+ public function exportSubscribers(EmailVision_Api_MemberService $service, array $storeIds = array(), $currentStore = null)
25
  {
26
  $size = false;
27
+ $updatedSubscribers = array();
28
  try {
29
  // Subscribers that never have been sync || that have been update more recently than their last sync
30
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
 
 
 
 
 
 
31
  ->addFieldToFilter(
32
  'main_table.subscriber_status',
33
  array(
34
  array('eq' => Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED)
35
  )
36
  );
37
+
38
+ // only get subscirbers that have been scheduled
39
+ $subscribers->addFieldToFilter(
40
+ 'main_table.' . Emv_DataSync_Helper_Service::FIELD_QUEUED,
41
+ Emv_DataSync_Helper_Service::SCHEDULED_VALUE
42
+ );
43
+
44
+ if (count($storeIds)) {
45
+ $subscribers->addFieldToFilter('main_table.store_id', array('in' => $storeIds));
46
+ }
47
+
48
  $size = $subscribers->getSize();
49
  if ($size) {
50
  // Add all customer and address attributes that have been mapped into collection
51
+ Mage::getSingleton('emvdatasync/attributeProcessing_config')
52
+ ->prepareSubscriberCollection($subscribers, $currentStore);
53
  }
54
  } catch (Exception $e) {
55
  Mage::logException($e);
59
  if ($size) {
60
  foreach ($subscribers as $subscriber) {
61
  try {
62
+ $ok = $this->_insertOrUpdateMember($subscriber, $service, $currentStore);
63
+ if ($ok) {
64
+ $updatedSubscribers[] = $subscriber->getId();
65
+ }
66
  } catch (Exception $e) {
67
  Mage::logException($e);
68
 
72
  }
73
  }
74
 
75
+ return $updatedSubscribers;
76
  }
77
 
78
  /**
82
  * @param Mage_Newsletter_Model_Subscriber $subscriber
83
  * @return array
84
  */
85
+ public function getMergeCriteriaForMember(Mage_Newsletter_Model_Subscriber $subscriber, $storeId = null)
86
  {
87
+ if (Mage::helper('emvdatasync')->getEmailEnabled($storeId)) {
88
  $mergeCriteria = array(strtoupper(Emv_Core_Model_Service_Member::FIELD_EMAIL) => $subscriber->getEmail());
89
  } else {
90
  $mergeCriteria = array(
91
+ strtoupper(Mage::helper('emvdatasync')->getMappedEntityId($storeId)) => $subscriber->getId()
92
  );
93
  }
94
  return $mergeCriteria;
95
  }
96
 
 
97
  /**
98
  * Method to call insert or update on subscriber passed as param
99
  *
102
  *
103
  * @return string | boolean $result The soap call result
104
  */
105
+ protected function _insertOrUpdateMember(
106
+ Mage_Newsletter_Model_Subscriber $subscriber,
107
+ EmailVision_Api_MemberService $service,
108
+ $storeId = null,
109
+ $closeApi = false
110
+ )
111
  {
 
 
112
  // Replace customer email by suscriber one
113
  $subscriber->setData('email', $subscriber->getSubscriberEmail());
114
 
115
+ $params = Mage::getSingleton('emvdatasync/attributeProcessing_config')
116
+ ->getSubscriberData($subscriber, $storeId);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
117
 
118
  // make api call with all prepared array (mapped attributes and criteria)
119
  try {
120
  $uploadId = null;
 
121
  $uploadId = $service->insertOrUpdateMemberByObj(
122
+ $this->getMergeCriteriaForMember($subscriber, $storeId),
123
  $params,
124
  $closeApi
125
  );
 
 
126
  } catch (Exception $e) {
127
  Mage::logException($e);
128
 
134
  }
135
 
136
  /**
137
+ * Unjoin all unsubscribed members from SmartFocus platform
138
  *
139
+ * @param EmailVision_Api_MemberService $service
140
+ * @param array $storeIds
141
+ * @param string $currentStore
142
  * @param boolean $closeApi
143
+ * @return Array - An array containing the subscribers ids unjoined with success
144
  */
145
+ public function unjoinSubscribers(EmailVision_Api_MemberService $service,
146
+ array $storeIds = array(),
147
+ $currentStore = null
148
+ )
149
  {
150
+ $unjoinedSubscribers = array();
151
  try {
152
  // Subscribers that have unjoined more recently than their last sync
153
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
154
+ ->addFieldToFilter(
155
+ 'main_table.subscriber_status',
156
+ array(
157
+ array('eq' => Mage_Newsletter_Model_Subscriber::STATUS_UNSUBSCRIBED),
158
+ )
159
+ );
160
+ // only get subscirbers that have been scheduled
161
+ $subscribers->addFieldToFilter(
162
+ 'main_table.' . Emv_DataSync_Helper_Service::FIELD_QUEUED,
163
+ Emv_DataSync_Helper_Service::SCHEDULED_VALUE
 
164
  );
165
+
166
+ if (count($storeIds)) {
167
+ $subscribers->addFieldToFilter('main_table.store_id', array('in' => $storeIds));
168
+ }
169
+
170
  } catch (Exception $e) {
171
  Mage::logException($e);
172
  $this->_errors[] = 'Exception while retreiving data for subscribers to unjoin with message: ' . $e->getMessage();
174
 
175
  foreach ($subscribers as $subscriber) {
176
  try {
177
+ $this->unjoinOneSubscriber($subscriber,$service, $currentStore, false);
178
 
179
+ $unjoinedSubscribers[] = $subscriber->getId();
180
  } catch (Exception $e) {
181
  Mage::logException($e);
182
  $this->_errors[] = 'Exception while preparing data to call unjoin, for subscriber '
184
  }
185
  }
186
 
187
+ return $unjoinedSubscribers;
188
  }
189
 
190
  /**
191
  * Unjoin member from EmailVision platform
192
  *
193
  * @param Mage_Newsletter_Model_Subscriber $subscriber
194
+ * @param EmailVision_Api_MemberService $service
195
+ * @param string $currentStore
196
  * @param boolean $closeApi
197
  * @return Emv_DataSync_Model_Service_Member
198
  */
199
+ public function unjoinOneSubscriber(Mage_Newsletter_Model_Subscriber $subscriber,
200
+ EmailVision_Api_MemberService $service,
201
+ $currentStore = null,
202
+ $closeApi = true
203
+ )
204
  {
205
  if ($subscriber->getId()) {
206
+ $service->unjoinMember('object', $this->getMergeCriteriaForMember($subscriber, $currentStore), $closeApi);
 
207
  }
208
 
209
  return $this;
212
  /**
213
  * Rejoin subscribers to EmailVision platform
214
  * (subscribers that change their status from unsubscribed to subscribe)
215
+ * @param EmailVision_Api_MemberService $service
216
+ * @param array $storeIds
217
  * @param boolean $closeApi
218
+ * @return Array - An array containing the subscribers ids rejoined with success
219
  */
220
+ public function rejoinSubscribers(EmailVision_Api_MemberService $service,
221
+ array $storeIds = array(),
222
+ $closeApi = false
223
+ )
224
  {
225
+ $rejoinedSubscribers = array();
226
  try {
227
  // Subscribers which have last sync more recently than unjoin && that are subscribed
228
  $subscribers = Mage::getModel('newsletter/subscriber')->getCollection()
235
  array('eq'=> Mage_Newsletter_Model_Subscriber::STATUS_SUBSCRIBED),
236
  ));
237
 
238
+ // only get subscirbers that have been scheduled
239
+ $subscribers->addFieldToFilter(
240
+ 'main_table.' . Emv_DataSync_Helper_Service::FIELD_QUEUED,
241
+ Emv_DataSync_Helper_Service::SCHEDULED_VALUE
242
+ );
243
+
244
+ if (count($storeIds)) {
245
+ $subscribers->addFieldToFilter('main_table.store_id', array('in' => $storeIds));
246
+ }
247
+
248
  } catch (Exception $e) {
249
  Mage::logException($e);
250
  $this->_errors[] = 'Exception while retreiving data for subscribers to rejoin with message: ' . $e->getMessage();
251
  }
252
 
 
 
253
  foreach ($subscribers as $subscriber) {
254
  try {
255
  $memberId = false;
267
  }
268
  if ($memberId) {
269
  $service->rejoinMember('id', $memberId, $closeApi);
270
+ $rejoinedSubscribers[] = $subscriber->getId();
271
  }
272
  } catch (Exception $e) {
273
  Mage::logException($e);
276
  }
277
  }
278
 
279
+ return $rejoinedSubscribers;
280
  }
281
 
282
  /**
290
  /**
291
  * Method to set massively the custom member_last_update_date after a member or a batchmember export
292
  */
293
+ public function massSetMemberLastUpdateDate(
294
+ array $updatedSubscribers,
295
+ array $unjoinedSubscribers,
296
+ array $rejoinedSubscribers
297
+ )
298
  {
299
  $subscribersIds = array();
300
+ foreach ($updatedSubscribers as $subscriberId) {
301
  $subscribersIds[] = $subscriberId;
302
  }
303
+ foreach ($unjoinedSubscribers as $subscriberId) {
304
  $subscribersIds[] = $subscriberId;
305
  }
306
+ foreach ($rejoinedSubscribers as $subscriberId) {
307
  $subscribersIds[] = $subscriberId;
308
  }
309
  $subscribersIds = array_unique($subscribersIds);
311
  try {
312
  $errorMessage = Mage::helper('emvdatasync/service')->massSetMemberLastUpdateDate(
313
  $subscribersIds,
314
+ $rejoinedSubscribers
315
  );
316
  if ($errorMessage !== true) {
317
  $this->_errors[] = $errorMessage;
326
  */
327
  public function triggerExport()
328
  {
329
+ $accounts = Mage::helper('emvdatasync')->getActiveEmvAccountsForStore(Emv_DataSync_Helper_Data::TYPE_MEMBER);
 
 
330
 
331
+ foreach ($accounts as $accountId => $accountData)
332
+ {
333
+ $storeIds = $accountData['stores'];
334
+ $account = $accountData['model'];
335
+ $service = false;
336
+ $currentStore = $storeIds[0];
337
 
338
+ try {
339
+ // Get api service corresponding to current account
340
+ $service = $this->getApiService($account, $storeIds[0]);
341
+ } catch (Exception $e) {
342
+ $this->_errors[] = "The account {$account->getName()} is invalid : " . $e->getMessage();
343
+ }
344
+
345
+ if ($service) {
346
+ $updatedSubscribers = $this->exportSubscribers($service, $storeIds, $currentStore);
347
+ $unjoinedSubscribers = $this->unjoinSubscribers($service, $storeIds, $currentStore);
348
+ $rejoinedSubscribers = $this->rejoinSubscribers($service, $storeIds);
349
+
350
+ // Update memberLastUpdateDate
351
+ $this->massSetMemberLastUpdateDate($updatedSubscribers, $unjoinedSubscribers, $rejoinedSubscribers);
352
+
353
+ try {
354
+ $service->closeApiConnection();
355
+ } catch (Exception $e) {
356
+ Mage::logException($e);
357
+ $this->_errors[] = "Exception while closing SmartFocus service for account {{$account->getName()}} with message : "
358
+ . $e->getMessage();
359
+ }
360
+ }
361
  }
362
  }
363
  }
app/code/community/Emv/DataSync/controllers/Adminhtml/DataSyncController.php CHANGED
@@ -4,7 +4,8 @@
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
- * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
 
8
  */
9
  class Emv_DataSync_Adminhtml_DataSyncController extends Mage_Adminhtml_Controller_Action
10
  {
@@ -18,21 +19,268 @@ class Emv_DataSync_Adminhtml_DataSyncController extends Mage_Adminhtml_Controlle
18
  $this->setUsedModuleName('Emv_DataSync');
19
  }
20
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
21
  /**
22
  * Get EmailVision fields from api object
23
  */
24
  public function getMemberFieldsAction()
25
  {
26
  $accountId = $this->getRequest()->getParam('account_id', null);
27
- $preparedFields = array();
28
-
29
- $account = Mage::getModel('emvcore/account');
30
  if (!$accountId) {
31
- $account = Mage::helper('emvdatasync')->getEmvAccountForStore();
32
- } else {
33
- $account->load($accountId);
34
  }
35
 
 
 
 
 
36
  // get account id for
37
  if ($account->getId()) {
38
  try {
@@ -62,10 +310,6 @@ class Emv_DataSync_Adminhtml_DataSyncController extends Mage_Adminhtml_Controlle
62
 
63
  if (count($preparedFields)) {
64
  Mage::helper('emvdatasync')->saveEmailVisionFieldsInConfig($preparedFields);
65
- // SmartFocus fields need to be in lower case
66
- Mage::helper('emvdatasync')->saveMappedEntityId(
67
- strtolower(Emv_Core_Model_Service_Member::FIELD_SUBSCRIBER_ID)
68
- );
69
 
70
  $config = Mage::getModel('core/config');
71
  $config->removeCache();
@@ -75,7 +319,21 @@ class Emv_DataSync_Adminhtml_DataSyncController extends Mage_Adminhtml_Controlle
75
  );
76
  }
77
 
78
- $this->_redirect('adminhtml/system_config/edit/section/emvdatasync/');
 
 
 
79
  }
 
 
 
 
 
 
 
 
 
 
 
80
  }
81
 
4
  *
5
  * @category Emv
6
  * @package Emv_DataSync
7
+ * @author Minh Quang VO (minhquang.vo@smartfocus.com)
8
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
9
  */
10
  class Emv_DataSync_Adminhtml_DataSyncController extends Mage_Adminhtml_Controller_Action
11
  {
19
  $this->setUsedModuleName('Emv_DataSync');
20
  }
21
 
22
+ /**
23
+ * Subscriber Queue Grid
24
+ */
25
+ public function indexAction()
26
+ {
27
+ $this->_title($this->__('SmartFocus'))->_title($this->__('Subscriber Export'));
28
+
29
+ if ($this->getRequest()->getParam('ajax')) {
30
+ $this->_forward('grid');
31
+ return;
32
+ }
33
+ $this->loadLayout();
34
+
35
+ $this->_setActiveMenu('emailvision/datasync');
36
+
37
+ $this->_addContent(
38
+ $this->getLayout()->createBlock('emvdatasync/adminhtml_newsletter_subscriber','subscriber')
39
+ );
40
+
41
+ $this->renderLayout();
42
+ }
43
+
44
+ /**
45
+ * Subscriber Queue Grid action for ajax request
46
+ */
47
+ public function gridAction()
48
+ {
49
+ $this->loadLayout();
50
+ $this->getResponse()->setBody(
51
+ $this->getLayout()->createBlock('emvdatasync/adminhtml_newsletter_subscriber_grid')->toHtml()
52
+ );
53
+ }
54
+
55
+ /**
56
+ * Export subscribers grid to CSV format
57
+ */
58
+ public function exportCsvAction()
59
+ {
60
+ $fileName = 'subscribers.csv';
61
+ $content = $this->getLayout()->createBlock('emvdatasync/adminhtml_newsletter_subscriber_grid')
62
+ ->getCsvFile();
63
+
64
+ $this->_prepareDownloadResponse($fileName, $content);
65
+ }
66
+
67
+ /**
68
+ * Export subscribers grid to XML format
69
+ */
70
+ public function exportXmlAction()
71
+ {
72
+ $fileName = 'subscribers.xml';
73
+ $content = $this->getLayout()->createBlock('emvdatasync/adminhtml_newsletter_subscriber_grid')
74
+ ->getExcelFile();
75
+
76
+ $this->_prepareDownloadResponse($fileName, $content);
77
+ }
78
+
79
+ /**
80
+ * Schedule or Remove subscriber list from export queue action
81
+ */
82
+ public function massQueueAction()
83
+ {
84
+ $subscribersIds = $this->getRequest()->getParam('subscriber');
85
+ if (!is_array($subscribersIds) || count($subscribersIds) == 0) {
86
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('newsletter')->__('Please select subscriber(s)'));
87
+ } else {
88
+ try {
89
+ $scheduled = $this->getRequest()->getParam('scheduled');
90
+ if (
91
+ $scheduled != Emv_DataSync_Helper_Service::SCHEDULED_VALUE
92
+ && $scheduled != Emv_DataSync_Helper_Service::NOT_SCHEDULED_VALUE
93
+ ) {
94
+ $scheduled = Emv_DataSync_Helper_Service::SCHEDULED_VALUE;
95
+ }
96
+
97
+ Mage::helper('emvdatasync')->massScheduleSubscriber($subscribersIds, $scheduled);
98
+ Mage::getSingleton('adminhtml/session')->addSuccess(
99
+ Mage::helper('adminhtml')->__('Total of %d record(s) were updated', count($subscribersIds))
100
+ );
101
+ } catch (Exception $e) {
102
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
103
+ }
104
+ }
105
+
106
+ $this->_redirect('*/*/index');
107
+ }
108
+
109
+ /**
110
+ * Mass dry test - creating csv files for the given subscribers list
111
+ * Allows to download the file(s) if they are readable else display the error message and forward to queue grid
112
+ */
113
+ public function massDryTestAction()
114
+ {
115
+ $subscribersIds = $this->getRequest()->getParam('subscriber');
116
+ if (!is_array($subscribersIds) || count($subscribersIds) == 0) {
117
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('newsletter')->__('Please select subscriber(s)'));
118
+ } else {
119
+ try {
120
+ $service = Mage::getModel('emvdatasync/service_batchMember');
121
+ $output = $service->massExportCustomers($subscribersIds, true);
122
+
123
+ // If non-blocking errors occurs
124
+ $processErrors = $service->getErrors();
125
+ if (!empty($processErrors)) {
126
+ foreach ($processErrors as $error) {
127
+ Mage::getSingleton('adminhtml/session')->addError($error);
128
+ }
129
+ } else {
130
+ $listFileToZip = array();
131
+ foreach ($output as $accountId => $fileData) {
132
+ foreach ($fileData['treated_files'] as $file) {
133
+ if (is_readable($file['path'])) {
134
+ $listFileToZip[] = array($file['path'], $file['filename']);
135
+ }
136
+ }
137
+ }
138
+
139
+ if (count($listFileToZip)) {
140
+ $downloadFileName = 'export_files_'.rand().'.zip';
141
+ $zipFilePath = Mage::getBaseDir(Emv_Core_Helper_Data::BASE_CONTAINER)
142
+ . DS . Emv_Core_Helper_Data::BASE_WORKING_DIR . DS . Emv_Core_Helper_Data::TEMPORARY_DIR;
143
+ Mage_System_Dirs::mkdirStrict($zipFilePath);
144
+
145
+ $zipFileName = $zipFilePath . DS . $downloadFileName;
146
+ $zip = new ZipArchive();
147
+ if ($zip->open($zipFileName, ZIPARCHIVE::CREATE) === true) {
148
+ /**
149
+ * Manage list of files to zip
150
+ */
151
+ foreach ($listFileToZip as $file) {
152
+ if (is_readable($file[0])) {
153
+ $zip->addFile($file[0], $file[1]);
154
+ }
155
+ }
156
+
157
+ $zip->close();
158
+
159
+ $content = array(
160
+ 'type' => 'filename',
161
+ 'value' => $zipFileName,
162
+ 'rm' => true,
163
+ );
164
+ return $this->_prepareDownloadResponse($downloadFileName, $content, 'application/zip');
165
+ } else {
166
+ Mage::throwException(Mage::helper('emvdatasync')->__('Error while creating archive'));
167
+ }
168
+ } else {
169
+ Mage::getSingleton('adminhtml/session')->addNotice(
170
+ Mage::helper('emvdatasync')->__('No file is generated')
171
+ );
172
+ }
173
+ }
174
+ } catch (Exception $e) {
175
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
176
+ }
177
+ }
178
+
179
+ $this->_redirect('*/*/index');
180
+ }
181
+
182
+ /**
183
+ * Make a test of synchronization
184
+ */
185
+ public function sendTestAction()
186
+ {
187
+ $subscribersIds = $this->getRequest()->getParam('subscriber');
188
+ if (!is_array($subscribersIds) || count($subscribersIds) == 0) {
189
+ Mage::getSingleton('adminhtml/session')->addError(Mage::helper('newsletter')->__('Please select subscriber(s)'));
190
+ } else {
191
+ $allowed = (int)Mage::getStoreConfig(Emv_DataSync_Helper_Data::XML_PATH_ALLOWED_NUMBER_TEST);
192
+ if ($allowed < count($subscribersIds)) {
193
+ Mage::getSingleton('adminhtml/session')->addError(
194
+ Mage::helper('emvdatasync')->__(
195
+ 'Your list (%s members) exceeds the allowed limit (%s)!',
196
+ count($subscribersIds),
197
+ $allowed
198
+ )
199
+ );
200
+ } else {
201
+ $helper = Mage::helper('emvdatasync');
202
+ $createdLock = false;
203
+ $startRunTime = $helper->getFormattedGmtDateTime();
204
+
205
+ try {
206
+ // check and create lock
207
+ if (!$helper->checkLockFile()) {
208
+ // create lock file => do not allow several process at the same time
209
+ $helper->createLockFile('Batch member synchronization cron process running at GMT timezone '
210
+ . $startRunTime
211
+ );
212
+ $service = Mage::getModel('emvdatasync/service_batchMember');
213
+ $createdLock = true;
214
+
215
+ $service->init();
216
+ $service->setInputData(array('test_mode' => true, 'member_ids' => $subscribersIds));
217
+ $service->run();
218
+
219
+ $gridLink = sprintf(
220
+ '<a href="%s">%s</a>',
221
+ $this->getUrl('emv_core/dataProcessing'),
222
+ Mage::helper('emvcore')->__('Process grid')
223
+ );
224
+ Mage::getSingleton('adminhtml/session')->addNotice(
225
+ Mage::helper('emvdatasync')->__(
226
+ 'Your synchronization (%s subscriber(s)) has been triggered. Please look at process %s (%s)',
227
+ count($subscribersIds),
228
+ $service->getProcess()->getId(),
229
+ $gridLink
230
+ )
231
+ );
232
+
233
+ // If non-blocking errors occurs
234
+ $processErrors = $service->getErrors();
235
+ if (!empty($processErrors)) {
236
+ $url = Mage::helper('emvcore')->getLogUrlForProcess($service->getProcess());
237
+ $logLink = sprintf('<a href="%s">%s</a>', $url, Mage::helper('emvcore')->__('Click here'));
238
+ Mage::getSingleton('adminhtml/session')->addError(
239
+ Mage::helper('emvdatasync')->__(
240
+ 'Some non-blocking errors occured, check log (%s) for more details!',
241
+ $logLink
242
+ )
243
+ );
244
+ }
245
+ } else {
246
+ Mage::getSingleton('adminhtml/session')->addError(
247
+ Mage::helper('newsletter')->__('Another Data Sync has been running! Please wait until it finishes!')
248
+ );
249
+ }
250
+ } catch (Exception $e) {
251
+ Mage::getSingleton('adminhtml/session')->addError($e->getMessage());
252
+ }
253
+
254
+ // if lock is created, need to delete it
255
+ if ($createdLock) {
256
+ try {
257
+ $helper->removeLockFile();
258
+ } catch (Exception $e) {
259
+ // don't do anything
260
+ }
261
+ }
262
+ }
263
+ }
264
+
265
+ $this->_redirect('*/*/index');
266
+ }
267
+
268
  /**
269
  * Get EmailVision fields from api object
270
  */
271
  public function getMemberFieldsAction()
272
  {
273
  $accountId = $this->getRequest()->getParam('account_id', null);
 
 
 
274
  if (!$accountId) {
275
+ $accountId = Mage::helper('emvcore')->getAdminScopedConfig(
276
+ Emv_DataSync_Helper_Data::XML_PATH_ACCOUNT_FOR_MEMBER
277
+ );
278
  }
279
 
280
+ $preparedFields = array();
281
+
282
+ $account = Mage::getModel('emvcore/account');
283
+ $account->load($accountId);
284
  // get account id for
285
  if ($account->getId()) {
286
  try {
310
 
311
  if (count($preparedFields)) {
312
  Mage::helper('emvdatasync')->saveEmailVisionFieldsInConfig($preparedFields);
 
 
 
 
313
 
314
  $config = Mage::getModel('core/config');
315
  $config->removeCache();
319
  );
320
  }
321
 
322
+ $this->_redirect(
323
+ 'adminhtml/system_config/edit/section/emvdatasync/',
324
+ array('_current' => array('section', 'website', 'store'))
325
+ );
326
  }
327
+
328
+ /**
329
+ * Check if having a correct permission
330
+ *
331
+ * @return boolean
332
+ */
333
+ protected function _isallowed()
334
+ {
335
+ return Mage::getSingleton('admin/session')->isAllowed('emailvision/datasync/queue');
336
+ }
337
+
338
  }
339
 
app/code/community/Emv/DataSync/etc/adminhtml.xml CHANGED
@@ -1,9 +1,42 @@
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
3
  <acl>
4
  <resources>
5
  <admin>
6
  <children>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
7
  <system>
8
  <children>
9
  <config>
1
  <?xml version="1.0" encoding="UTF-8"?>
2
  <config>
3
+ <menu>
4
+ <emailvision>
5
+ <children>
6
+ <!-- SmartFocus Data Sync menu in the back office -->
7
+ <datasync translate="title" module="emvdatasync">
8
+ <title>Subscriber Export</title>
9
+ <sort_order>999</sort_order>
10
+ <children>
11
+ <queue translate="title">
12
+ <title>Newsletter Subscriber Queue</title>
13
+ <sort_order>10</sort_order>
14
+ <action>emv_datasync/dataSync</action>
15
+ </queue>
16
+ </children>
17
+ </datasync>
18
+ </children>
19
+ </emailvision>
20
+ </menu>
21
+
22
  <acl>
23
  <resources>
24
  <admin>
25
  <children>
26
+ <emailvision>
27
+ <children>
28
+ <datasync>
29
+ <title>Subscriber Export</title>
30
+ <sort_order>999</sort_order>
31
+ <children>
32
+ <queue>
33
+ <title>Subscriber Queue</title>
34
+ <sort_order>10</sort_order>
35
+ </queue>
36
+ </children>
37
+ </datasync>
38
+ </children>
39
+ </emailvision>
40
  <system>
41
  <children>
42
  <config>
app/code/community/Emv/DataSync/etc/config.xml CHANGED
@@ -2,7 +2,7 @@
2
  <config>
3
  <modules>
4
  <Emv_DataSync>
5
- <version>0.1.0</version>
6
  </Emv_DataSync>
7
  </modules>
8
 
@@ -31,21 +31,37 @@
31
  </adminhtml>
32
 
33
  <global>
 
 
 
 
34
  <blocks>
35
  <emvdatasync>
36
  <class>Emv_DataSync_Block</class>
37
  </emvdatasync>
38
  </blocks>
 
39
  <models>
40
  <emvdatasync>
41
  <class>Emv_DataSync_Model</class>
 
42
  </emvdatasync>
 
 
 
 
 
 
 
 
43
  </models>
 
44
  <helpers>
45
  <emvdatasync>
46
  <class>Emv_DataSync_Helper</class>
47
  </emvdatasync>
48
  </helpers>
 
49
  <resources>
50
  <emvdatasync_setup>
51
  <setup>
@@ -66,6 +82,8 @@
66
  </connection>
67
  </emvdatasync_read>
68
  </resources>
 
 
69
  <events>
70
  <!-- customer/customer -->
71
  <customer_save_after>
@@ -106,18 +124,28 @@
106
  </emailvision_on_subscriber_save>
107
  </observers>
108
  </newsletter_subscriber_save_after>
 
 
 
 
 
 
 
 
109
  </events>
 
110
  <template>
111
  <email>
112
  <emvdatasync_general_error_email_template translate="label" module="directory">
113
- <label>EmailVision cron errors</label>
114
- <file>emailvision/datasync/cron_errors.html</file>
115
  <type>html</type>
116
  </emvdatasync_general_error_email_template>
117
  </email>
118
  </template>
119
  </global>
120
 
 
121
  <crontab>
122
  <jobs>
123
  <emailvision_member_export>
@@ -130,22 +158,34 @@
130
  <model>emvdatasync/cron::batchMemberExport</model>
131
  </run>
132
  </emailvision_batchmember_export>
133
- <emailvision_clean>
134
  <run>
135
  <model>emvdatasync/cron::cleanEmailVisionFiles</model>
136
  </run>
137
- </emailvision_clean>
 
 
 
 
 
138
  </jobs>
139
  </crontab>
140
 
 
141
  <default>
142
  <emvdatasync>
143
  <general>
 
144
  <error_email_recipient>contact@domain.com</error_email_recipient>
145
  <error_email_sender>general</error_email_sender>
146
  <error_email_template>emvdatasync_batchmember_error_email_template</error_email_template>
147
  </general>
148
 
 
 
 
 
 
149
  <batchmember>
150
  <performance>10000</performance>
151
  <enabled>0</enabled>
2
  <config>
3
  <modules>
4
  <Emv_DataSync>
5
+ <version>0.2.1</version>
6
  </Emv_DataSync>
7
  </modules>
8
 
31
  </adminhtml>
32
 
33
  <global>
34
+ <smartfocus_attribute_processing>
35
+ <newsletter>emvdatasync/attributeProcessing_handler_newsletter</newsletter>
36
+ <purchase_information>emvdatasync/attributeProcessing_handler_purchaseInformation</purchase_information>
37
+ </smartfocus_attribute_processing>
38
  <blocks>
39
  <emvdatasync>
40
  <class>Emv_DataSync_Block</class>
41
  </emvdatasync>
42
  </blocks>
43
+ <!-- Model Defintion -->
44
  <models>
45
  <emvdatasync>
46
  <class>Emv_DataSync_Model</class>
47
+ <resourceModel>emvdatasync_mysql4</resourceModel>
48
  </emvdatasync>
49
+ <emvdatasync_mysql4>
50
+ <class>Emv_DataSync_Model_Mysql4</class>
51
+ <entities>
52
+ <purchase_info>
53
+ <table>emv_dataprocess_purchaseinformation</table>
54
+ </purchase_info>
55
+ </entities>
56
+ </emvdatasync_mysql4>
57
  </models>
58
+ <!-- Helper Defintion -->
59
  <helpers>
60
  <emvdatasync>
61
  <class>Emv_DataSync_Helper</class>
62
  </emvdatasync>
63
  </helpers>
64
+ <!-- Resource Defintion -->
65
  <resources>
66
  <emvdatasync_setup>
67
  <setup>
82
  </connection>
83
  </emvdatasync_read>
84
  </resources>
85
+
86
+ <!-- Event observers -->
87
  <events>
88
  <!-- customer/customer -->
89
  <customer_save_after>
124
  </emailvision_on_subscriber_save>
125
  </observers>
126
  </newsletter_subscriber_save_after>
127
+ <sales_order_save_after>
128
+ <observers>
129
+ <emailvision_on_order_save_after>
130
+ <class>emvdatasync/observer</class>
131
+ <method>handleOrderSaveAfter</method>
132
+ </emailvision_on_order_save_after>
133
+ </observers>
134
+ </sales_order_save_after>
135
  </events>
136
+ <!-- Email Template -->
137
  <template>
138
  <email>
139
  <emvdatasync_general_error_email_template translate="label" module="directory">
140
+ <label>SmartFocus Cron Errors</label>
141
+ <file>smartfocus/datasync/cron_errors.html</file>
142
  <type>html</type>
143
  </emvdatasync_general_error_email_template>
144
  </email>
145
  </template>
146
  </global>
147
 
148
+ <!-- Cron tab -->
149
  <crontab>
150
  <jobs>
151
  <emailvision_member_export>
158
  <model>emvdatasync/cron::batchMemberExport</model>
159
  </run>
160
  </emailvision_batchmember_export>
161
+ <emailvision_batchmember_cleanning>
162
  <run>
163
  <model>emvdatasync/cron::cleanEmailVisionFiles</model>
164
  </run>
165
+ </emailvision_batchmember_cleanning>
166
+ <emailvision_purchase_process>
167
+ <run>
168
+ <model>emvdatasync/cron::startPurchaseProcess</model>
169
+ </run>
170
+ </emailvision_purchase_process>
171
  </jobs>
172
  </crontab>
173
 
174
+ <!-- Default parameters -->
175
  <default>
176
  <emvdatasync>
177
  <general>
178
+ <test_members>50</test_members>
179
  <error_email_recipient>contact@domain.com</error_email_recipient>
180
  <error_email_sender>general</error_email_sender>
181
  <error_email_template>emvdatasync_batchmember_error_email_template</error_email_template>
182
  </general>
183
 
184
+ <purchase_info>
185
+ <enabled>0</enabled>
186
+ <limit_size>75000</limit_size>
187
+ </purchase_info>
188
+
189
  <batchmember>
190
  <performance>10000</performance>
191
  <enabled>0</enabled>
app/code/community/Emv/DataSync/etc/system.xml CHANGED
@@ -9,11 +9,26 @@
9
  <show_in_website>1</show_in_website>
10
  <show_in_store>1</show_in_store>
11
  <groups>
 
 
 
 
 
 
 
 
 
12
  <general translate="label comment" module="emvdatasync">
13
  <label>General</label>
14
  <sort_order>10</sort_order>
15
  <show_in_default>1</show_in_default>
16
  <fields>
 
 
 
 
 
 
17
  <error_email_recipient translate="label">
18
  <label>Error Email Recipient</label>
19
  <frontend_type>text</frontend_type>
@@ -36,12 +51,44 @@
36
  </error_email_template>
37
  </fields>
38
  </general>
39
-
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
40
  <apimember translate="label comment" module="emvdatasync">
41
  <label>Triggered Export Settings</label>
42
  <comment>Enable the automatic update of your members data with apimember (Member Service)</comment>
43
  <sort_order>20</sort_order>
44
  <show_in_default>1</show_in_default>
 
 
45
  <fields>
46
  <enabled translate="label">
47
  <label>Enabled</label>
@@ -50,14 +97,18 @@
50
  <backend_model>emvdatasync/adminhtml_system_config_backend_apiMember_enabled</backend_model>
51
  <sort_order>1</sort_order>
52
  <show_in_default>1</show_in_default>
 
 
53
  </enabled>
54
  <account translate="label">
55
  <label>SmartFocus Account</label>
56
  <frontend_type>select</frontend_type>
57
- <source_model>emvcore/system_config_source_account</source_model>
58
  <backend_model>emvdatasync/adminhtml_system_config_backend_apiMember_account</backend_model>
59
  <sort_order>10</sort_order>
60
  <show_in_default>1</show_in_default>
 
 
61
  </account>
62
  <frequency translate="label">
63
  <label>Frequency</label>
@@ -76,6 +127,8 @@
76
  <frontend_type>text</frontend_type>
77
  <sort_order>30</sort_order>
78
  <show_in_default>1</show_in_default>
 
 
79
  <fields>
80
  <enabled translate="label">
81
  <label>Enabled</label>
@@ -84,14 +137,18 @@
84
  <backend_model>emvdatasync/adminhtml_system_config_backend_batchMember_enabled</backend_model>
85
  <sort_order>1</sort_order>
86
  <show_in_default>1</show_in_default>
 
 
87
  </enabled>
88
  <account translate="label">
89
  <label>SmartFocus Account</label>
90
  <frontend_type>select</frontend_type>
91
- <source_model>emvcore/system_config_source_account</source_model>
92
  <backend_model>emvdatasync/adminhtml_system_config_backend_batchMember_account</backend_model>
93
  <sort_order>10</sort_order>
94
  <show_in_default>1</show_in_default>
 
 
95
  </account>
96
  <frequency translate="label">
97
  <label>Frequency</label>
@@ -100,6 +157,22 @@
100
  <sort_order>20</sort_order>
101
  <show_in_default>1</show_in_default>
102
  </frequency>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
103
  <time translate="label">
104
  <label>Start Time (in Admin timezone)</label>
105
  <frontend_type>time</frontend_type>
@@ -131,20 +204,36 @@
131
  <sort_order>1</sort_order>
132
  <show_in_default>1</show_in_default>
133
  </enabled>
134
- <time translate="label">
135
- <label>Start Time (in Admin timezone)</label>
136
- <frontend_type>time</frontend_type>
137
- <backend_model>emvdatasync/adminhtml_system_config_backend_clean_cron</backend_model>
138
- <sort_order>3</sort_order>
139
- <show_in_default>1</show_in_default>
140
- </time>
141
  <frequency translate="label">
142
  <label>Frequency</label>
143
  <frontend_type>select</frontend_type>
144
  <source_model>adminhtml/system_config_source_cron_frequency</source_model>
145
- <sort_order>4</sort_order>
146
  <show_in_default>1</show_in_default>
147
  </frequency>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
148
  </fields>
149
  </export_file_cleaning>
150
 
@@ -169,6 +258,8 @@
169
  <frontend_type>text</frontend_type>
170
  <sort_order>70</sort_order>
171
  <show_in_default>1</show_in_default>
 
 
172
  <fields>
173
  <get_emailvision_fields translate="label comment">
174
  <label>Field Synchronization</label>
@@ -177,6 +268,8 @@
177
  <comment>Connect to SmartFocus apimember webservice and get the list of available fields</comment>
178
  <sort_order>1</sort_order>
179
  <show_in_default>1</show_in_default>
 
 
180
  </get_emailvision_fields>
181
  <email_enabled translate="label">
182
  <label>Synchronize with email</label>
@@ -185,6 +278,8 @@
185
  <comment>If enabled, Magento newsletter subscribers will be synced by their email address. By default, the SmartFocus Entity Id will be used.</comment>
186
  <sort_order>3</sort_order>
187
  <show_in_default>1</show_in_default>
 
 
188
  </email_enabled>
189
  <emailvision_entity_id translate="label comment">
190
  <label>SmartFocus Entity Id</label>
@@ -193,6 +288,8 @@
193
  <comment>Default field used to link a Magento newsletter subscriber to a SmartFocus member. CLIENTURN is selected by default.</comment>
194
  <sort_order>5</sort_order>
195
  <show_in_default>1</show_in_default>
 
 
196
  </emailvision_entity_id>
197
  <attributes translate="comment">
198
  <label></label>
@@ -201,6 +298,8 @@
201
  <backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
202
  <sort_order>10</sort_order>
203
  <show_in_default>1</show_in_default>
 
 
204
  </attributes>
205
  </fields>
206
  </customer_mapping>
9
  <show_in_website>1</show_in_website>
10
  <show_in_store>1</show_in_store>
11
  <groups>
12
+ <extension_status translate="label">
13
+ <label>Plugin Status</label>
14
+ <frontend_model>emvcore/adminhtml_config_extensionStatus</frontend_model>
15
+ <sort_order>0</sort_order>
16
+ <frontend_type>text</frontend_type>
17
+ <show_in_default>1</show_in_default>
18
+ <show_in_website>1</show_in_website>
19
+ <show_in_store>1</show_in_store>
20
+ </extension_status>
21
  <general translate="label comment" module="emvdatasync">
22
  <label>General</label>
23
  <sort_order>10</sort_order>
24
  <show_in_default>1</show_in_default>
25
  <fields>
26
+ <test_members>
27
+ <label>Allowed Numbers of Subscribers (for testing)</label>
28
+ <frontend_type>text</frontend_type>
29
+ <sort_order>40</sort_order>
30
+ <show_in_default>1</show_in_default>
31
+ </test_members>
32
  <error_email_recipient translate="label">
33
  <label>Error Email Recipient</label>
34
  <frontend_type>text</frontend_type>
51
  </error_email_template>
52
  </fields>
53
  </general>
54
+ <purchase_info>
55
+ <label>Purchase Data Process Settings</label>
56
+ <comment>Enable the automatic calculation for Customer Purchase Data</comment>
57
+ <sort_order>15</sort_order>
58
+ <show_in_default>1</show_in_default>
59
+ <show_in_website>0</show_in_website>
60
+ <show_in_store>0</show_in_store>
61
+ <fields>
62
+ <enabled translate="label">
63
+ <label>Enabled</label>
64
+ <frontend_type>select</frontend_type>
65
+ <source_model>adminhtml/system_config_source_yesno</source_model>
66
+ <sort_order>1</sort_order>
67
+ <show_in_default>1</show_in_default>
68
+ </enabled>
69
+ <limit_size>
70
+ <label>The limit of purchase information to store</label>
71
+ <frontend_type>text</frontend_type>
72
+ <sort_order>10</sort_order>
73
+ <show_in_default>1</show_in_default>
74
+ </limit_size>
75
+ <frequency translate="label">
76
+ <label>Frequency</label>
77
+ <frontend_type>select</frontend_type>
78
+ <source_model>emvdatasync/adminhtml_system_config_source_memberCronTime</source_model>
79
+ <backend_model>emvdatasync/adminhtml_system_config_backend_purchaseProcess_cron</backend_model>
80
+ <sort_order>20</sort_order>
81
+ <show_in_default>1</show_in_default>
82
+ </frequency>
83
+ </fields>
84
+ </purchase_info>
85
  <apimember translate="label comment" module="emvdatasync">
86
  <label>Triggered Export Settings</label>
87
  <comment>Enable the automatic update of your members data with apimember (Member Service)</comment>
88
  <sort_order>20</sort_order>
89
  <show_in_default>1</show_in_default>
90
+ <show_in_website>1</show_in_website>
91
+ <show_in_store>1</show_in_store>
92
  <fields>
93
  <enabled translate="label">
94
  <label>Enabled</label>
97
  <backend_model>emvdatasync/adminhtml_system_config_backend_apiMember_enabled</backend_model>
98
  <sort_order>1</sort_order>
99
  <show_in_default>1</show_in_default>
100
+ <show_in_website>1</show_in_website>
101
+ <show_in_store>1</show_in_store>
102
  </enabled>
103
  <account translate="label">
104
  <label>SmartFocus Account</label>
105
  <frontend_type>select</frontend_type>
106
+ <source_model>emvcore/adminhtml_system_config_source_account</source_model>
107
  <backend_model>emvdatasync/adminhtml_system_config_backend_apiMember_account</backend_model>
108
  <sort_order>10</sort_order>
109
  <show_in_default>1</show_in_default>
110
+ <show_in_website>1</show_in_website>
111
+ <show_in_store>1</show_in_store>
112
  </account>
113
  <frequency translate="label">
114
  <label>Frequency</label>
127
  <frontend_type>text</frontend_type>
128
  <sort_order>30</sort_order>
129
  <show_in_default>1</show_in_default>
130
+ <show_in_website>1</show_in_website>
131
+ <show_in_store>1</show_in_store>
132
  <fields>
133
  <enabled translate="label">
134
  <label>Enabled</label>
137
  <backend_model>emvdatasync/adminhtml_system_config_backend_batchMember_enabled</backend_model>
138
  <sort_order>1</sort_order>
139
  <show_in_default>1</show_in_default>
140
+ <show_in_website>1</show_in_website>
141
+ <show_in_store>1</show_in_store>
142
  </enabled>
143
  <account translate="label">
144
  <label>SmartFocus Account</label>
145
  <frontend_type>select</frontend_type>
146
+ <source_model>emvcore/adminhtml_system_config_source_account</source_model>
147
  <backend_model>emvdatasync/adminhtml_system_config_backend_batchMember_account</backend_model>
148
  <sort_order>10</sort_order>
149
  <show_in_default>1</show_in_default>
150
+ <show_in_website>1</show_in_website>
151
+ <show_in_store>1</show_in_store>
152
  </account>
153
  <frequency translate="label">
154
  <label>Frequency</label>
157
  <sort_order>20</sort_order>
158
  <show_in_default>1</show_in_default>
159
  </frequency>
160
+ <day>
161
+ <label>Day of the week</label>
162
+ <frontend_type>select</frontend_type>
163
+ <source_model>emvcore/adminhtml_system_config_source_cronDay</source_model>
164
+ <sort_order>22</sort_order>
165
+ <depends><frequency>W</frequency></depends>
166
+ <show_in_default>1</show_in_default>
167
+ </day>
168
+ <date>
169
+ <label>Date of the month</label>
170
+ <frontend_type>select</frontend_type>
171
+ <source_model>emvcore/adminhtml_system_config_source_cronDate</source_model>
172
+ <sort_order>23</sort_order>
173
+ <depends><frequency>M</frequency></depends>
174
+ <show_in_default>1</show_in_default>
175
+ </date>
176
  <time translate="label">
177
  <label>Start Time (in Admin timezone)</label>
178
  <frontend_type>time</frontend_type>
204
  <sort_order>1</sort_order>
205
  <show_in_default>1</show_in_default>
206
  </enabled>
 
 
 
 
 
 
 
207
  <frequency translate="label">
208
  <label>Frequency</label>
209
  <frontend_type>select</frontend_type>
210
  <source_model>adminhtml/system_config_source_cron_frequency</source_model>
211
+ <sort_order>20</sort_order>
212
  <show_in_default>1</show_in_default>
213
  </frequency>
214
+ <day>
215
+ <label>Day of the week</label>
216
+ <frontend_type>select</frontend_type>
217
+ <source_model>emvcore/adminhtml_system_config_source_cronDay</source_model>
218
+ <sort_order>22</sort_order>
219
+ <depends><frequency>W</frequency></depends>
220
+ <show_in_default>1</show_in_default>
221
+ </day>
222
+ <date>
223
+ <label>Date of the month</label>
224
+ <frontend_type>select</frontend_type>
225
+ <source_model>emvcore/adminhtml_system_config_source_cronDate</source_model>
226
+ <sort_order>23</sort_order>
227
+ <depends><frequency>M</frequency></depends>
228
+ <show_in_default>1</show_in_default>
229
+ </date>
230
+ <time translate="label">
231
+ <label>Start Time (in Admin timezone)</label>
232
+ <frontend_type>time</frontend_type>
233
+ <backend_model>emvdatasync/adminhtml_system_config_backend_clean_cron</backend_model>
234
+ <sort_order>40</sort_order>
235
+ <show_in_default>1</show_in_default>
236
+ </time>
237
  </fields>
238
  </export_file_cleaning>
239
 
258
  <frontend_type>text</frontend_type>
259
  <sort_order>70</sort_order>
260
  <show_in_default>1</show_in_default>
261
+ <show_in_website>1</show_in_website>
262
+ <show_in_store>1</show_in_store>
263
  <fields>
264
  <get_emailvision_fields translate="label comment">
265
  <label>Field Synchronization</label>
268
  <comment>Connect to SmartFocus apimember webservice and get the list of available fields</comment>
269
  <sort_order>1</sort_order>
270
  <show_in_default>1</show_in_default>
271
+ <show_in_website>1</show_in_website>
272
+ <show_in_store>1</show_in_store>
273
  </get_emailvision_fields>
274
  <email_enabled translate="label">
275
  <label>Synchronize with email</label>
278
  <comment>If enabled, Magento newsletter subscribers will be synced by their email address. By default, the SmartFocus Entity Id will be used.</comment>
279
  <sort_order>3</sort_order>
280
  <show_in_default>1</show_in_default>
281
+ <show_in_website>1</show_in_website>
282
+ <show_in_store>1</show_in_store>
283
  </email_enabled>
284
  <emailvision_entity_id translate="label comment">
285
  <label>SmartFocus Entity Id</label>
288
  <comment>Default field used to link a Magento newsletter subscriber to a SmartFocus member. CLIENTURN is selected by default.</comment>
289
  <sort_order>5</sort_order>
290
  <show_in_default>1</show_in_default>
291
+ <show_in_website>1</show_in_website>
292
+ <show_in_store>1</show_in_store>
293
  </emailvision_entity_id>
294
  <attributes translate="comment">
295
  <label></label>
298
  <backend_model>adminhtml/system_config_backend_serialized_array</backend_model>
299
  <sort_order>10</sort_order>
300
  <show_in_default>1</show_in_default>
301
+ <show_in_website>1</show_in_website>
302
+ <show_in_store>1</show_in_store>
303
  </attributes>
304
  </fields>
305
  </customer_mapping>
app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-install-0.0.1.php CHANGED
@@ -4,9 +4,9 @@ $this->startSetup();
4
  /* @var Varien_Db_Adapter_Pdo_Mysql $connection*/
5
  $connection = $this->getConnection();
6
 
7
- $connection->addColumn($this->getTable('newsletter_subscriber'), 'date_unjoin', 'DATETIME default NULL');
8
- $connection->addColumn($this->getTable('newsletter_subscriber'), 'data_last_update_date', 'DATETIME default NULL');
9
- $connection->addColumn($this->getTable('newsletter_subscriber'), 'member_last_update_date', 'DATETIME default NULL');
10
 
11
  $this->endSetup();
12
  ?>
4
  /* @var Varien_Db_Adapter_Pdo_Mysql $connection*/
5
  $connection = $this->getConnection();
6
 
7
+ $connection->addColumn($this->getTable('newsletter/subscriber'), 'date_unjoin', 'DATETIME default NULL');
8
+ $connection->addColumn($this->getTable('newsletter/subscriber'), 'data_last_update_date', 'DATETIME default NULL');
9
+ $connection->addColumn($this->getTable('newsletter/subscriber'), 'member_last_update_date', 'DATETIME default NULL');
10
 
11
  $this->endSetup();
12
  ?>
app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-upgrade-0.1.0-0.2.0.php ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $installer Emv_Emt_Model_Resource_Setup */
3
+ $this->startSetup();
4
+
5
+ /* @var Varien_Db_Adapter_Pdo_Mysql $connection*/
6
+ $connection = $this->getConnection();
7
+ $connection->addColumn($this->getTable('newsletter/subscriber'), 'queued', 'TINYINT(1) default 0');
8
+
9
+ $this->run("
10
+ UPDATE {$this->getTable('newsletter/subscriber')}
11
+ SET queued = 1
12
+ WHERE member_last_update_date IS NULL
13
+ OR (member_last_update_date IS NOT NULL
14
+ AND (
15
+ date_unjoin > member_last_update_date OR data_last_update_date > member_last_update_date
16
+ )
17
+ )
18
+ ");
19
+
20
+ $this->endSetup();
app/code/community/Emv/DataSync/sql/emvdatasync_setup/mysql4-upgrade-0.2.0-0.2.1.php ADDED
@@ -0,0 +1,60 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /* @var $installer Emv_Emt_Model_Resource_Setup */
3
+ $this->startSetup();
4
+
5
+ /* @var Varien_Db_Adapter_Pdo_Mysql $connection*/
6
+
7
+ $this->run("
8
+ DROP TABLE IF EXISTS {$this->getTable('emvdatasync/purchase_info')};
9
+ CREATE TABLE {$this->getTable('emvdatasync/purchase_info')} (
10
+ `id` int(11) unsigned NOT NULL auto_increment,
11
+ `created_at` DATETIME NOT NULL,
12
+ `updated_at` DATETIME NOT NULL,
13
+ `base_currency_code` varchar(255) NULL,
14
+
15
+ `total_order` INT(4) DEFAULT 0,
16
+
17
+ `total_ordered_item_qty` INT(5) DEFAULT 0,
18
+ `avg_item_qty` INT(5) DEFAULT 0,
19
+ `order_amount_total` DECIMAL(12,4) DEFAULT 0,
20
+ `avg_order_amount_total` DECIMAL(12,4) DEFAULT 0,
21
+ `discount_amount_total` DECIMAL(12,4) DEFAULT 0,
22
+ `avg_discount_amount_total` DECIMAL(12,4) DEFAULT 0,
23
+
24
+ `min_order_amount_total` DECIMAL(12,4) DEFAULT 0,
25
+ `max_order_amount_total` DECIMAL(12,4) DEFAULT 0,
26
+ `first_order_date` DATETIME NULL,
27
+ `last_order_date` DATETIME NULL,
28
+ `min_total_ordered_item_qty` INT(5) DEFAULT 0,
29
+ `max_total_ordered_item_qty` INT(5) DEFAULT 0,
30
+
31
+ `shipping_amount_total` DECIMAL(12,4) DEFAULT 0,
32
+ `avg_shipping_amount_total` DECIMAL(12,4) DEFAULT 0,
33
+ `shipping_list` TEXT NULL,
34
+ `payment_methods` TEXT NULL,
35
+ `coupon_list` TEXT NULL,
36
+ `nb_order_having_discount` INT(4) DEFAULT 0,
37
+
38
+ `customer_id` int(9) unsigned NULL,
39
+ `email` varchar(255) NOT NULL,
40
+ `order_list` TEXT NULL,
41
+
42
+ PRIMARY KEY (`id`),
43
+
44
+ INDEX `IDX_PURCHASE_INFO_CUSTOMER_ID` (`customer_id`),
45
+ INDEX `IDX_PURCHASE_INFO_EMAIL` (`email`)
46
+
47
+ ) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='Purchase Information';
48
+ ");
49
+
50
+ /* @var Varien_Db_Adapter_Pdo_Mysql $connection*/
51
+ $connection = $this->getConnection();
52
+ $connection->addColumn($this->getTable('newsletter/subscriber'), 'date_last_purchase', 'DATETIME default NULL');
53
+
54
+ $gmtDate = Mage::getModel('core/date')->gmtDate();
55
+ $this->run("
56
+ UPDATE {$this->getTable('newsletter/subscriber')} subscriber
57
+ JOIN {$this->getTable('sales/order')} flat_order ON subscriber.customer_id = flat_order.customer_id
58
+ SET date_last_purchase = '$gmtDate';
59
+ ");
60
+ $this->endSetup();
app/code/community/Emv/Emt/Block/Adminhtml/Config/ExtensionStatus.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Extension status block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Emt
7
+ * @copyright Copyright (c) 2014 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Emt_Block_Adminhtml_Config_ExtensionStatus
11
+ extends Emv_Core_Block_Adminhtml_Config_ExtensionStatus
12
+ {
13
+ /**
14
+ * List of call back functions to test
15
+ * @var array
16
+ */
17
+ protected $_callbackList = array('getEmailTemplateRewriteStatus');
18
+
19
+ /**
20
+ * Check if email template has been correctly rewritten by our module or it's in conflict with another extension
21
+ *
22
+ * @return string
23
+ */
24
+ public function getEmailTemplateRewriteStatus()
25
+ {
26
+ $classModelName = 'core/email_template';
27
+ $class = Mage::getModel($classModelName);
28
+
29
+ $ok = true;
30
+ $className = '';
31
+ if (!$class instanceof Emv_Emt_Model_Mage_Core_Email_Template) {
32
+ $ok = false;
33
+ $className = get_class($class);
34
+ }
35
+
36
+ $message = '';
37
+ if ($ok) {
38
+ $image = $this->_getTickImageLink();
39
+ $message = Mage::helper('emvcore')->__(
40
+ '<span class="icon-status">%s</span> Email Template class (<strong>"%s"</strong>) has been correctly overwritten.',
41
+ $image,
42
+ $classModelName
43
+ );
44
+ } else {
45
+ $image = $this->_getUnTickImageLink();
46
+ $message = Mage::helper('emvcore')->__(
47
+ '<span class="icon-status">%s</span> Email Template class (<strong>"%s"</strong>) has not been correctly overwritten - in conflict with the following class <strong>%s</strong>.',
48
+ $image,
49
+ $classModelName,
50
+ $className
51
+ );
52
+ }
53
+ return $message;
54
+ }
55
+
56
+ }
app/code/community/Emv/Emt/Block/Adminhtml/Log/Grid.php CHANGED
@@ -9,6 +9,17 @@
9
  */
10
  class Emv_Emt_Block_Adminhtml_Log_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
  {
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Prepare collection for grid
14
  *
@@ -100,7 +111,7 @@ class Emv_Emt_Block_Adminhtml_Log_Grid extends Mage_Adminhtml_Block_Widget_Grid
100
  )
101
  );
102
 
103
- // EmailVision Template name
104
  $this->addColumn('emv_name',
105
  array(
106
  'header'=> Mage::helper('emvemt')->__('SmartFocus Template'),
9
  */
10
  class Emv_Emt_Block_Adminhtml_Log_Grid extends Mage_Adminhtml_Block_Widget_Grid
11
  {
12
+ /**
13
+ * Constructor
14
+ *
15
+ * Set main configuration of grid
16
+ */
17
+ public function __construct()
18
+ {
19
+ parent::__construct();
20
+ $this->setDefaultSort('id', 'desc');
21
+ }
22
+
23
  /**
24
  * Prepare collection for grid
25
  *
111
  )
112
  );
113
 
114
+ // SmartFocus Template name
115
  $this->addColumn('emv_name',
116
  array(
117
  'header'=> Mage::helper('emvemt')->__('SmartFocus Template'),
app/code/community/Emv/Emt/Block/Adminhtml/Resending/Grid.php CHANGED
@@ -18,6 +18,7 @@ class Emv_Emt_Block_Adminhtml_Resending_Grid extends Mage_Adminhtml_Block_Widget
18
  {
19
  $collection = Mage::getResourceModel('emvemt/resending_queue_message_collection');
20
  $this->setCollection($collection);
 
21
 
22
  parent::_prepareCollection();
23
  }
@@ -107,7 +108,7 @@ class Emv_Emt_Block_Adminhtml_Resending_Grid extends Mage_Adminhtml_Block_Widget
107
  )
108
  );
109
 
110
- // EmailVision Template name
111
  $this->addColumn('emv_name',
112
  array(
113
  'header'=> Mage::helper('emvemt')->__('SmartFocus Template'),
18
  {
19
  $collection = Mage::getResourceModel('emvemt/resending_queue_message_collection');
20
  $this->setCollection($collection);
21
+ $this->setDefaultSort('id', 'desc');
22
 
23
  parent::_prepareCollection();
24
  }
108
  )
109
  );
110
 
111
+ // SmartFocus Template name
112
  $this->addColumn('emv_name',
113
  array(
114
  'header'=> Mage::helper('emvemt')->__('SmartFocus Template'),
app/code/community/Emv/Emt/Block/Adminhtml/System/Config/ValidateAccount.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Account validation block
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Emt
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+
11
+ class Emv_Emt_Block_Adminhtml_System_Config_ValidateAccount
12
+ extends Mage_Adminhtml_Block_System_Config_Form_Field
13
+ {
14
+ /**
15
+ * Set template to itself
16
+ *
17
+ * @return Emv_Emt_Block_Adminhtml_System_Config_ValidateAccount
18
+ */
19
+ protected function _prepareLayout()
20
+ {
21
+ parent::_prepareLayout();
22
+ if (!$this->getTemplate()) {
23
+ $this->setTemplate('smartfocus/emt/system/config/account_validation.phtml');
24
+ }
25
+ return $this;
26
+ }
27
+
28
+ /**
29
+ * Get the button and scripts contents
30
+ *
31
+ * @param Varien_Data_Form_Element_Abstract $element
32
+ *
33
+ * @return string
34
+ */
35
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
36
+ {
37
+ return $this->_toHtml();
38
+ }
39
+ }
app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit.php CHANGED
@@ -11,7 +11,7 @@ class Emv_Emt_Block_Adminhtml_Template_Edit extends Mage_Adminhtml_Block_Widget
11
  {
12
  public function __construct()
13
  {
14
- $this->setTemplate('emailvision/emt/template/edit.phtml');
15
  $this->setId('emv_email_template');
16
  }
17
 
@@ -27,8 +27,9 @@ class Emv_Emt_Block_Adminhtml_Template_Edit extends Mage_Adminhtml_Block_Widget
27
  $head->addItem('js', 'prototype/window.js')
28
  ->addItem('js_css', 'prototype/windows/themes/default.css')
29
  ->addCss('lib/prototype/windows/themes/magento.css')
30
- ->addCss('campaign-commander.css')
31
- ->addItem('js', 'mage/adminhtml/variables.js');
 
32
  }
33
 
34
  // back button - get back to grid menu
11
  {
12
  public function __construct()
13
  {
14
+ $this->setTemplate('smartfocus/emt/template/edit.phtml');
15
  $this->setId('emv_email_template');
16
  }
17
 
27
  $head->addItem('js', 'prototype/window.js')
28
  ->addItem('js_css', 'prototype/windows/themes/default.css')
29
  ->addCss('lib/prototype/windows/themes/magento.css')
30
+ ->addCss('smartfocus.css')
31
+ ->addItem('js', 'mage/adminhtml/variables.js')
32
+ ->addItem('js_css', 'prototype/windows/themes/magento.css');
33
  }
34
 
35
  // back button - get back to grid menu
app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit/Tab/EmvDyn.php CHANGED
@@ -52,7 +52,7 @@ class Emv_Emt_Block_Adminhtml_Template_Edit_Tab_EmvDyn extends Mage_Adminhtml_Bl
52
  public function __construct()
53
  {
54
  parent::__construct();
55
- $this->setTemplate('emailvision/emt/template/mapped_attributes.phtml');
56
  }
57
 
58
  /**
52
  public function __construct()
53
  {
54
  parent::__construct();
55
+ $this->setTemplate('smartfocus/emt/template/mapped_attributes.phtml');
56
  }
57
 
58
  /**
app/code/community/Emv/Emt/Block/Adminhtml/Template/Edit/Tab/General.php CHANGED
@@ -141,7 +141,7 @@ class Emv_Emt_Block_Adminhtml_Template_Edit_Tab_General extends Mage_Adminhtml_B
141
  {
142
  // js block contains all common javascript functions
143
  $jsBlock = $this->getLayout()->createBlock('adminhtml/template');
144
- $jsBlock->setData('edit_block', $this)->setTemplate('emailvision/emt/template/common_js.phtml');
145
  $fieldset->addField(
146
  'js_block',
147
  'note',
141
  {
142
  // js block contains all common javascript functions
143
  $jsBlock = $this->getLayout()->createBlock('adminhtml/template');
144
+ $jsBlock->setData('edit_block', $this)->setTemplate('smartfocus/emt/template/common_js.phtml');
145
  $fieldset->addField(
146
  'js_block',
147
  'note',
app/code/community/Emv/Emt/Helper/Emvtemplate.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * EmailVision Email template Helper
4
  *
5
  * @category Emv
6
  * @package Emv_Emt
@@ -12,8 +12,8 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
12
  /**
13
  * Xml path for different configurations
14
  */
15
- const XML_PATH_LOG_ENABLED = 'emvemt/transactional_service/log_enabled';
16
- const XML_PATH_SENDING_PARAMETER_LOG_ENABLED = 'emvemt/transactional_service/parameter_log_enabled';
17
 
18
  /**
19
  * SmartFocus attributes for a current SmartFocus template from registry
@@ -111,7 +111,7 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
111
  }
112
 
113
  /**
114
- * Get data necessary for email sending
115
  *
116
  * @param string $mageTemplateId
117
  * @param string $accountId
@@ -161,7 +161,7 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
161
  }
162
 
163
  /**
164
- * Get collection to retreive objects for email sending
165
  *
166
  * @param string $mageTemplateId
167
  * @param string $accountId
@@ -179,13 +179,13 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
179
  $magentoEmailTable = $resource->getTableName('core/email_template');
180
 
181
  // get SmartFocus sending template
182
- $codition = 'tmp_sending.emv_account_id = main_table.emv_account_id AND tmp_sending.mage_template_id = "'
183
  . Emv_Emt_Model_Emt::MAGENTO_TEMPLATE_ID_FOR_EMV_SEND . '"'
184
  . ' AND tmp_sending.emv_send_mail_mode_id = ' . Emv_Emt_Model_Mailmode::EMV_CREATE
185
  ;
186
  $select->joinLeft(
187
  array('tmp_sending' => $emtTable),
188
- $codition,
189
  array(
190
  'sending_template.emv_template_id' => 'tmp_sending.emv_template_id',
191
  'sending_template.emv_parameters' => 'tmp_sending.emv_parameters',
@@ -360,7 +360,10 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
360
  }
361
 
362
  /**
 
 
363
  * @param Emv_Core_Model_Account $account
 
364
  */
365
  public function checkAndCreateDefaultSendingTemplate(Emv_Core_Model_Account $account)
366
  {
@@ -370,11 +373,39 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
370
  $existingDefault = $this->getEmvEmt(Emv_Emt_Model_Emt::MAGENTO_TEMPLATE_ID_FOR_EMV_SEND, $account->getId());
371
  $needToCreate = false;
372
  if ($existingDefault && $existingDefault->getId()) {
373
- if (!$existingDefault->getEmvTemplate()) {
 
 
 
 
 
 
 
374
  $needToCreate = true;
375
  $defaultEmt->setId($existingDefault->getId());
376
  } else {
377
  $defaultEmt = $existingDefault;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
378
  }
379
  } else {
380
  $needToCreate = true;
@@ -499,4 +530,43 @@ class Emv_Emt_Helper_Emvtemplate extends Mage_Core_Helper_Abstract
499
 
500
  return $this->_sortedMappedAttributes;
501
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
502
  }
1
  <?php
2
  /**
3
+ * SmartFocus Email template Helper
4
  *
5
  * @category Emv
6
  * @package Emv_Emt
12
  /**
13
  * Xml path for different configurations
14
  */
15
+ const XML_PATH_LOG_ENABLED = 'emvemt/transactional_service/log_enabled';
16
+ const XML_PATH_SENDING_PARAMETER_LOG_ENABLED = 'emvemt/transactional_service/parameter_log_enabled';
17
 
18
  /**
19
  * SmartFocus attributes for a current SmartFocus template from registry
111
  }
112
 
113
  /**
114
+ * Prepare and get data necessary for email sending
115
  *
116
  * @param string $mageTemplateId
117
  * @param string $accountId
161
  }
162
 
163
  /**
164
+ * Get all objects useful for email sending
165
  *
166
  * @param string $mageTemplateId
167
  * @param string $accountId
179
  $magentoEmailTable = $resource->getTableName('core/email_template');
180
 
181
  // get SmartFocus sending template
182
+ $condition = 'tmp_sending.emv_account_id = main_table.emv_account_id AND tmp_sending.mage_template_id = "'
183
  . Emv_Emt_Model_Emt::MAGENTO_TEMPLATE_ID_FOR_EMV_SEND . '"'
184
  . ' AND tmp_sending.emv_send_mail_mode_id = ' . Emv_Emt_Model_Mailmode::EMV_CREATE
185
  ;
186
  $select->joinLeft(
187
  array('tmp_sending' => $emtTable),
188
+ $condition,
189
  array(
190
  'sending_template.emv_template_id' => 'tmp_sending.emv_template_id',
191
  'sending_template.emv_parameters' => 'tmp_sending.emv_parameters',
360
  }
361
 
362
  /**
363
+ * Check and create default sending template if necessary
364
+ *
365
  * @param Emv_Core_Model_Account $account
366
+ * @return Emv_Emt_Model_Emt
367
  */
368
  public function checkAndCreateDefaultSendingTemplate(Emv_Core_Model_Account $account)
369
  {
373
  $existingDefault = $this->getEmvEmt(Emv_Emt_Model_Emt::MAGENTO_TEMPLATE_ID_FOR_EMV_SEND, $account->getId());
374
  $needToCreate = false;
375
  if ($existingDefault && $existingDefault->getId()) {
376
+ $emvTemplate = false;
377
+ try {
378
+ $emvTemplate = $existingDefault->getEmvTemplate();
379
+ } catch(Mage_Core_Exception $e) {
380
+ // ignore Exception, if template does not exist anymore, create a new one
381
+ }
382
+
383
+ if (!$emvTemplate) {
384
  $needToCreate = true;
385
  $defaultEmt->setId($existingDefault->getId());
386
  } else {
387
  $defaultEmt = $existingDefault;
388
+
389
+ // try to get all template parameters
390
+ $savedEmvParams = $existingDefault->getEmailVisionParams();
391
+ $newParms = $existingDefault->getEmailVisionParams($emvTemplate);
392
+
393
+ // if the template parameters are different, need to recreate the template
394
+ if (
395
+ !is_array($savedEmvParams)
396
+ || !is_array($newParms)
397
+ || count($savedEmvParams) != count($newParms)
398
+ ) {
399
+ $needToCreate = true;
400
+ } else {
401
+ $checkingParam = array('emv_id','emv_random', 'emv_encrypt', 'emv_name');
402
+ foreach ($checkingParam as $paramName) {
403
+ if (!isset($newParms[$paramName]) || $newParms[$paramName] !== $savedEmvParams[$paramName]) {
404
+ $needToCreate = true;
405
+ break;
406
+ }
407
+ }
408
+ }
409
  }
410
  } else {
411
  $needToCreate = true;
530
 
531
  return $this->_sortedMappedAttributes;
532
  }
533
+
534
+ /**
535
+ * Validate SmartFocus account with given account id
536
+ *
537
+ * @param string $accountId
538
+ * @throws Mage_Core_Exception if something is missing or not correctly defined
539
+ * @return boolean
540
+ */
541
+ public function validateEmvAccount($accountId)
542
+ {
543
+ $account = Mage::getModel('emvcore/account')->load($accountId);
544
+ if (!$account->getId()) {
545
+ Mage::throwException(Mage::helper('emvcore')->__('Your selected account does not exist anymore!'));
546
+ }
547
+
548
+ // check url
549
+ $url = Mage::helper('emvcore')
550
+ ->checkAndGetUrlForType($account, Emv_Core_Model_Account::URL_TRANSACTIONAL_SERVICE_TYPE);
551
+
552
+ try {
553
+ // check credentials
554
+ $this->checkAndCreateDefaultSendingTemplate($account);
555
+ } catch (EmailVision_Api_Exception $e) {
556
+ if ($e->isRecoverable()) {
557
+ Mage::throwException(
558
+ Mage::helper('emvcore')
559
+ ->__('Could not verify the selected account. Network problems occured!')
560
+ );
561
+ } else {
562
+ Mage::throwException($e->getMessage());
563
+ }
564
+ }
565
+
566
+ Mage::helper('emvcore')
567
+ ->checkAndGetUrlForType($account, Emv_Core_Model_Account::URL_REST_NOTIFICATION_SERVICE_TYPE);
568
+
569
+ // every thing is ok, so return true
570
+ return true;
571
+ }
572
  }
app/code/community/Emv/Emt/Model/Adminhtml/System/Config/Backend/Account.php CHANGED
@@ -29,29 +29,7 @@ class Emv_Emt_Model_Adminhtml_System_Config_Backend_Account extends Emv_Core_Mod
29
  protected function _beforeSave()
30
  {
31
  if ($this->isValueChanged() && $this->getValue()) {
32
- $account = $this->_getAccount();
33
- if (!$account->getId()) {
34
- Mage::throwException(Mage::helper('emvcore')->__('Your selected account does not exist anymore!'));
35
- }
36
-
37
- // check url
38
- $url = $this->_checkAndGetUrlForType($account, $this->_urlType);
39
-
40
- try {
41
- // check credentials
42
- Mage::helper('emvemt/emvtemplate')->checkAndCreateDefaultSendingTemplate($account);
43
- } catch (EmailVision_Api_Exception $e) {
44
- if ($e->isRecoverable()) {
45
- Mage::throwException(
46
- Mage::helper('emvcore')
47
- ->__('Could not verify the account. Network problems occured! Please Save again!')
48
- );
49
- } else {
50
- Mage::throwException($e->getMessage());
51
- }
52
- }
53
-
54
- $this->_checkAndGetUrlForType($account, Emv_Core_Model_Account::URL_REST_NOTIFICATION_SERVICE_TYPE);
55
  }
56
 
57
  return Mage_Core_Model_Abstract::_beforeSave();
29
  protected function _beforeSave()
30
  {
31
  if ($this->isValueChanged() && $this->getValue()) {
32
+ Mage::helper('emvemt/emvtemplate')->validateEmvAccount($this->getValue());
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
33
  }
34
 
35
  return Mage_Core_Model_Abstract::_beforeSave();
app/code/community/Emv/Emt/Model/Adminhtml/System/Config/Backend/Log/Cron.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Log Cron Backend Model
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Emt
7
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
8
+ */
9
+ class Emv_Emt_Model_Adminhtml_System_Config_Backend_Log_Cron extends Emv_Core_Model_Adminhtml_System_Config_Backend_Cron
10
+ {
11
+ protected $_crontabPath = 'crontab/jobs/emailvision_process_sending_log_cleanning/schedule/cron_expr';
12
+ }
app/code/community/Emv/Emt/Model/Cron.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /**
3
- * EmailVision emt cron model
4
  *
5
  * @category Emv
6
  * @package Emv_Emt
@@ -9,6 +9,32 @@
9
  */
10
  class Emv_Emt_Model_Cron
11
  {
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
12
  /**
13
  * Process all error sending emails
14
  * - convert all error sending emails into rescheduled queue messages
@@ -23,6 +49,9 @@ class Emv_Emt_Model_Cron
23
  return;
24
  }
25
 
 
 
 
26
  // create lock file, in order to prevent from launching several process at the same time
27
  $rule->createLock();
28
 
@@ -33,7 +62,22 @@ class Emv_Emt_Model_Cron
33
  Mage::logException($e);
34
  }
35
 
 
 
36
  // remove lock file
37
  $rule->removeLock();
38
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
39
  }
1
  <?php
2
  /**
3
+ * SmartFocus emt cron model
4
  *
5
  * @category Emv
6
  * @package Emv_Emt
9
  */
10
  class Emv_Emt_Model_Cron
11
  {
12
+ /**
13
+ * Xml path for log cleanning mechanism
14
+ */
15
+ const XML_PATH_LOG_CLEAN_ENABLED = 'emvemt/log_cleanning/enabled';
16
+ const XML_PATH_LOG_CLEAN_NUMBER_LAST_DAY = 'emvemt/log_cleanning/keeping_days';
17
+
18
+ /**
19
+ * Is log cleanning mechanism activated ?
20
+ *
21
+ * @return boolean
22
+ */
23
+ public function isLogCleanningEnabled()
24
+ {
25
+ return (bool)Mage::getStoreConfig(self::XML_PATH_LOG_CLEAN_ENABLED);
26
+ }
27
+
28
+ /**
29
+ * Get number of days to keep
30
+ *
31
+ * @return int
32
+ */
33
+ public function getNumberDaysToKeep()
34
+ {
35
+ return (int)Mage::getStoreConfig(self::XML_PATH_LOG_CLEAN_NUMBER_LAST_DAY);
36
+ }
37
+
38
  /**
39
  * Process all error sending emails
40
  * - convert all error sending emails into rescheduled queue messages
49
  return;
50
  }
51
 
52
+ // !!! it's very important to set SmartFocus custom error handler in order to remove lock file in case of fatal error
53
+ Mage::helper('emvcore')->setSmartFocusErrorHandler();
54
+
55
  // create lock file, in order to prevent from launching several process at the same time
56
  $rule->createLock();
57
 
62
  Mage::logException($e);
63
  }
64
 
65
+ // reset error handler to Magento one
66
+ Mage::helper('emvcore')->resetErrorHandler();
67
  // remove lock file
68
  $rule->removeLock();
69
  }
70
+
71
+ /**
72
+ * Clean sending logs
73
+ */
74
+ public function cleanLogs()
75
+ {
76
+ if (!$this->isLogCleanningEnabled()) {
77
+ return false;
78
+ }
79
+
80
+ $timeLimit = $this->getNumberDaysToKeep() * 60 * 60 * 24;
81
+ Mage::getModel('emvemt/log')->cleanLogs($timeLimit);
82
+ }
83
  }
app/code/community/Emv/Emt/Model/Emt.php CHANGED
@@ -55,7 +55,7 @@ class Emv_Emt_Model_Emt extends Mage_Core_Model_Abstract
55
  {
56
  $this->_emailVisionParams = array();
57
 
58
- //reset emt template if user switch mail mode from 'emv create / SmartFocus Template' to 'emv send' or 'classic'
59
  if (
60
  $this->getEmvSendMailModeId() == Emv_Emt_Model_Mailmode::CLASSIC_MODE
61
  || $this->getEmvSendMailModeId() == Emv_Emt_Model_Mailmode::EMV_SEND
55
  {
56
  $this->_emailVisionParams = array();
57
 
58
+ //reset emt template if user switch mail mode from 'SmartFocus Template' to 'SmartFocus Routage' or 'Classic'
59
  if (
60
  $this->getEmvSendMailModeId() == Emv_Emt_Model_Mailmode::CLASSIC_MODE
61
  || $this->getEmvSendMailModeId() == Emv_Emt_Model_Mailmode::EMV_SEND
app/code/community/Emv/Emt/Model/Log.php CHANGED
@@ -19,7 +19,6 @@ class Emv_Emt_Model_Log extends Mage_Core_Model_Abstract
19
  * Constant for resending workflow
20
  */
21
  const RESENDING_WORKFLOW = 'resending';
22
-
23
  const RESCHEDULED = 1;
24
 
25
  /**
@@ -148,4 +147,15 @@ class Emv_Emt_Model_Log extends Mage_Core_Model_Abstract
148
  => Mage::helper('emvemt')->__('Invalid SmartFocus Parameters')
149
  );
150
  }
 
 
 
 
 
 
 
 
 
 
 
151
  }
19
  * Constant for resending workflow
20
  */
21
  const RESENDING_WORKFLOW = 'resending';
 
22
  const RESCHEDULED = 1;
23
 
24
  /**
147
  => Mage::helper('emvemt')->__('Invalid SmartFocus Parameters')
148
  );
149
  }
150
+
151
+ /**
152
+ * Clean logs created before a time limit
153
+ * @param int $timeLimit
154
+ * @return Emv_Emt_Model_Log
155
+ */
156
+ public function cleanLogs($timeLimit)
157
+ {
158
+ $this->getResource()->cleanLogs($timeLimit);
159
+ return $this;
160
+ }
161
  }
app/code/community/Emv/Emt/Model/Mailmode.php CHANGED
@@ -39,9 +39,9 @@ class Emv_Emt_Model_Mailmode extends Mage_Core_Model_Abstract
39
  public static function getMailModesAndLabels()
40
  {
41
  return array(
42
- self::CLASSIC_MODE => Mage::helper('emvemt')->__('classic'),
43
- self::EMV_CREATE => Mage::helper('emvemt')->__('emv create'),
44
- self::EMV_SEND => Mage::helper('emvemt')->__('emv send'),
45
  );
46
  }
47
 
39
  public static function getMailModesAndLabels()
40
  {
41
  return array(
42
+ self::CLASSIC_MODE => Mage::helper('emvemt')->__('Classic'),
43
+ self::EMV_CREATE => Mage::helper('emvemt')->__('SmartFocus Template'),
44
+ self::EMV_SEND => Mage::helper('emvemt')->__('SmartFocus Routage'),
45
  );
46
  }
47
 
app/code/community/Emv/Emt/Model/Mysql4/Log.php CHANGED
@@ -9,8 +9,61 @@
9
  */
10
  class Emv_Emt_Model_Mysql4_Log extends Mage_Core_Model_Mysql4_Abstract
11
  {
 
 
 
12
  protected function _construct()
13
  {
14
  $this->_init('emvemt/log', 'id');
15
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
16
  }
9
  */
10
  class Emv_Emt_Model_Mysql4_Log extends Mage_Core_Model_Mysql4_Abstract
11
  {
12
+ /* (non-PHPdoc)
13
+ * @see Mage_Core_Model_Resource_Abstract::_construct()
14
+ */
15
  protected function _construct()
16
  {
17
  $this->_init('emvemt/log', 'id');
18
  }
19
+
20
+ /**
21
+ * Clean logs before the time limit
22
+ *
23
+ * @param int $timeLimit
24
+ * @return Emv_Emt_Model_Mysql4_Log
25
+ */
26
+ public function cleanLogs($timeLimit)
27
+ {
28
+ $writeAdapter = $this->_getWriteAdapter();
29
+
30
+ $cleaningTimstamp = Mage::getModel('core/date')->gmtTimestamp() - $timeLimit;
31
+ $cleaningTimstamp = Varien_Date::formatDate($cleaningTimstamp, true);
32
+
33
+ $condition = array('created_at < ?' => $cleaningTimstamp);
34
+ // clean sending logs
35
+ $writeAdapter->delete($this->getMainTable(), $condition);
36
+ // clean resending queue
37
+ $writeAdapter->delete($this->getTable('emvemt/resending_queue_message'), $condition);
38
+ return $this;
39
+ }
40
+
41
+ /**
42
+ * Get total number of logs
43
+ *
44
+ * @return int
45
+ */
46
+ public function getNbTotal()
47
+ {
48
+ $select = $this->_getReadAdapter()->select();
49
+ $select->from($this->getMainTable())->columns('COUNT(*)');
50
+ return $this->_getReadAdapter()->fetchCol($select);
51
+ }
52
+
53
+ /**
54
+ * Delete logs
55
+ *
56
+ * @param array $logIds
57
+ * @return Emv_Emt_Model_Mysql4_Log
58
+ */
59
+ public function deleteLogs(array $logIds)
60
+ {
61
+ if (count($logIds)) {
62
+ $condition = array('id IN (?)' => $logIds);
63
+
64
+ $writeAdapter = $this->_getWriteAdapter();
65
+ $writeAdapter->delete($this->getMainTable(), $condition);
66
+ }
67
+ return $this;
68
+ }
69
  }
app/code/community/Emv/Emt/Model/Observer.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Observer class
4
+ *
5
+ * @category Emv
6
+ * @package Emv_Emt
7
+ * @copyright Copyright (c) 2013 SmartFocus (http://www.smartfocus.com)
8
+ * @author Minh Quang VO <minhquang.vo@smartfocus.com>
9
+ */
10
+ class Emv_Emt_Model_Observer
11
+ {
12
+ /**
13
+ * Observer on SmartFocus account delete event. Delete temporary email template when deleting SmartFocus account
14
+ * @param Varien_Event_Observer $observer
15
+ */
16
+ public function onAccountDelete(Varien_Event_Observer $observer)
17
+ {
18
+ // if we find an emv account
19
+ if ($observer->getEmvAccount()) {
20
+ // check if this account has an temporary email template
21
+ $existingDefault = Mage::helper('emvemt/emvtemplate')->
22
+ getEmvEmt(Emv_Emt_Model_Emt::MAGENTO_TEMPLATE_ID_FOR_EMV_SEND, $observer->getEmvAccount()->getId());
23
+ if ($existingDefault && $existingDefault->getId()) {
24
+ $existingDefault->delete();
25
+ }
26
+ }
27
+ }
28
+ }
app/code/community/Emv/Emt/Model/Resending/Rule.php CHANGED
@@ -24,7 +24,7 @@ class Emv_Emt_Model_Resending_Rule extends Mage_Core_Model_Abstract
24
  /**
25
  * Lock file name pattern
26
  */
27
- const LOCK_FILE_NAME_PATTERN = 'email_resending_process.lock';
28
 
29
  /**
30
  * Is resending mechanism activated ?
24
  /**
25
  * Lock file name pattern
26
  */
27
+ const LOCK_FILE_NAME_PATTERN = 'resending_error_email_process';
28
 
29
  /**
30
  * Is resending mechanism activated ?
app/code/community/Emv/Emt/controllers/Adminhtml/TemplateController.php CHANGED
@@ -713,4 +713,27 @@ class Emv_Emt_Adminhtml_TemplateController extends Mage_Adminhtml_Controller_Act
713
  echo $preview;
714
  }
715
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
716
  }
713
  echo $preview;
714
  }
715
 
716
+ /**
717
+ * Action to validate SmartFocus account
718
+ */
719
+ public function validateTemplateAction()
720
+ {
721
+ $accountId = $this->getRequest()->getParam('account_id');
722
+ $messageReturn = array('error' => array(), 'information' => array());
723
+
724
+ if ($accountId) {
725
+ try {
726
+ Mage::helper('emvemt/emvtemplate')->validateEmvAccount($accountId);
727
+ $messageReturn['information'][] = Mage::helper('emvemt')
728
+ ->__('Your account is correctly set up and ready to send emails');
729
+ } catch (Exception $e) {
730
+ $messageReturn['error'][] = $e->getMessage();
731
+ }
732
+ } else {
733
+ $messageReturn['error'][] = Mage::helper('emvemt')
734
+ ->__('Please select a SmartFocus account !');
735
+ }
736
+
737
+ $this->getResponse()->setBody(Mage::helper('core')->jsonEncode($messageReturn));
738
+ }
739
  }
app/code/community/Emv/Emt/etc/config.xml CHANGED
@@ -5,6 +5,7 @@
5
  <version>0.4.1</version>
6
  </Emv_Emt>
7
  </modules>
 
8
  <global>
9
  <blocks>
10
  <emvemt>
@@ -47,6 +48,8 @@
47
  </entities>
48
  </emvemt_mysql4>
49
  </models>
 
 
50
  <resources>
51
  <emvemt_setup>
52
  <setup>
@@ -55,7 +58,21 @@
55
  </setup>
56
  </emvemt_setup>
57
  </resources>
 
 
 
 
 
 
 
 
 
 
 
 
 
58
  </global>
 
59
  <adminhtml>
60
  <translate>
61
  <modules>
@@ -67,6 +84,7 @@
67
  </modules>
68
  </translate>
69
  </adminhtml>
 
70
  <admin>
71
  <routers>
72
  <emvemt>
@@ -78,6 +96,7 @@
78
  </emvemt>
79
  </routers>
80
  </admin>
 
81
  <crontab>
82
  <jobs>
83
  <emailvision_process_error_sending_emails>
@@ -88,6 +107,11 @@
88
  <model>emvemt/cron::processErrorSendingEmails</model>
89
  </run>
90
  </emailvision_process_error_sending_emails>
 
 
 
 
 
91
  </jobs>
92
  </crontab>
93
  <default>
@@ -99,6 +123,12 @@
99
  <third_delay>120</third_delay>
100
  <fourth_delay>240</fourth_delay>
101
  </resending_mechanism>
 
 
 
 
 
 
102
  </emvemt>
103
  </default>
104
  </config>
5
  <version>0.4.1</version>
6
  </Emv_Emt>
7
  </modules>
8
+
9
  <global>
10
  <blocks>
11
  <emvemt>
48
  </entities>
49
  </emvemt_mysql4>
50
  </models>
51
+
52
+ <!-- Resource Defintion -->
53
  <resources>
54
  <emvemt_setup>
55
  <setup>
58
  </setup>
59
  </emvemt_setup>
60
  </resources>
61
+
62
+ <!-- Event observers -->
63
+ <events>
64
+ <emv_account_delete_after>
65
+ <observers>
66
+ <emailvision_on_account_delete>
67
+ <type>singleton</type>
68
+ <class>emvemt/observer</class>
69
+ <method>onAccountDelete</method>
70
+ </emailvision_on_account_delete>
71
+ </observers>
72
+ </emv_account_delete_after>
73
+ </events>
74
  </global>
75
+
76
  <adminhtml>
77
  <translate>
78
  <modules>
84
  </modules>
85
  </translate>
86
  </adminhtml>
87
+
88
  <admin>
89
  <routers>
90
  <emvemt>
96
  </emvemt>
97
  </routers>
98
  </admin>
99
+
100
  <crontab>
101
  <jobs>
102
  <emailvision_process_error_sending_emails>
107
  <model>emvemt/cron::processErrorSendingEmails</model>
108
  </run>
109
  </emailvision_process_error_sending_emails>
110
+ <emailvision_process_sending_log_cleanning>
111
+ <run>
112
+ <model>emvemt/cron::cleanLogs</model>
113
+ </run>
114
+ </emailvision_process_sending_log_cleanning>
115
  </jobs>
116
  </crontab>
117
  <default>
123
  <third_delay>120</third_delay>
124
  <fourth_delay>240</fourth_delay>
125
  </resending_mechanism>
126
+ <log_cleanning>
127
+ <enabled>0</enabled>
128
+ <time/>
129
+ <frequency>D</frequency>
130
+ <keeping_days>30</keeping_days>
131
+ </log_cleanning>
132
  </emvemt>
133
  </default>
134
  </config>
app/code/community/Emv/Emt/etc/system.xml CHANGED
@@ -9,11 +9,20 @@
9
  <show_in_website>1</show_in_website>
10
  <show_in_store>1</show_in_store>
11
  <groups>
 
 
 
 
 
 
 
 
 
12
  <transactional_service translate="label" module="emvemt">
13
  <label>General</label>
14
  <expanded>1</expanded>
15
  <frontend_type>text</frontend_type>
16
- <sort_order>0</sort_order>
17
  <show_in_default>1</show_in_default>
18
  <show_in_website>1</show_in_website>
19
  <show_in_store>1</show_in_store>
@@ -21,13 +30,20 @@
21
  <account translate="label">
22
  <label>SmartFocus Account</label>
23
  <frontend_type>select</frontend_type>
24
- <source_model>emvcore/system_config_source_account</source_model>
25
  <backend_model>emvemt/adminhtml_system_config_backend_account</backend_model>
26
  <sort_order>0</sort_order>
27
  <show_in_default>1</show_in_default>
28
  <show_in_website>1</show_in_website>
29
  <show_in_store>1</show_in_store>
30
  </account>
 
 
 
 
 
 
 
31
  <log_enabled translate="label" module="emvemt">
32
  <label>Activate Sending Log</label>
33
  <frontend_type>select</frontend_type>
@@ -50,6 +66,7 @@
50
  </parameter_log_enabled>
51
  </fields>
52
  </transactional_service>
 
53
  <resending_mechanism translate="label" module="emvemt">
54
  <label>Resending Mechanism Configuration</label>
55
  <expanded>1</expanded>
@@ -89,8 +106,64 @@
89
  </fourth_delay>
90
  </fields>
91
  </resending_mechanism>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
92
  </groups>
93
  </emvemt>
94
  </sections>
95
- </config>
96
-
9
  <show_in_website>1</show_in_website>
10
  <show_in_store>1</show_in_store>
11
  <groups>
12
+ <extension_status translate="label">
13
+ <label>Plugin Status</label>
14
+ <frontend_model>emvemt/adminhtml_config_extensionStatus</frontend_model>
15
+ <sort_order>1</sort_order>
16
+ <frontend_type>text</frontend_type>
17
+ <show_in_default>1</show_in_default>
18
+ <show_in_website>1</show_in_website>
19
+ <show_in_store>1</show_in_store>
20
+ </extension_status>
21
  <transactional_service translate="label" module="emvemt">
22
  <label>General</label>
23
  <expanded>1</expanded>
24
  <frontend_type>text</frontend_type>
25
+ <sort_order>10</sort_order>
26
  <show_in_default>1</show_in_default>
27
  <show_in_website>1</show_in_website>
28
  <show_in_store>1</show_in_store>
30
  <account translate="label">
31
  <label>SmartFocus Account</label>
32
  <frontend_type>select</frontend_type>
33
+ <source_model>emvcore/adminhtml_system_config_source_account</source_model>
34
  <backend_model>emvemt/adminhtml_system_config_backend_account</backend_model>
35
  <sort_order>0</sort_order>
36
  <show_in_default>1</show_in_default>
37
  <show_in_website>1</show_in_website>
38
  <show_in_store>1</show_in_store>
39
  </account>
40
+ <validate_account translate="label">
41
+ <frontend_model>emvemt/adminhtml_system_config_validateAccount</frontend_model>
42
+ <sort_order>10</sort_order>
43
+ <show_in_default>1</show_in_default>
44
+ <show_in_website>1</show_in_website>
45
+ <show_in_store>1</show_in_store>
46
+ </validate_account>
47
  <log_enabled translate="label" module="emvemt">
48
  <label>Activate Sending Log</label>
49
  <frontend_type>select</frontend_type>
66
  </parameter_log_enabled>
67
  </fields>
68
  </transactional_service>
69
+
70
  <resending_mechanism translate="label" module="emvemt">
71
  <label>Resending Mechanism Configuration</label>
72
  <expanded>1</expanded>
106
  </fourth_delay>
107
  </fields>
108
  </resending_mechanism>
109
+
110
+ <log_cleanning translate="label" module="emvemt">
111
+ <label>Log Cleanning Configuration</label>
112
+ <expanded>1</expanded>
113
+ <sort_order>40</sort_order>
114
+ <show_in_default>1</show_in_default>
115
+ <fields>
116
+ <keeping_days translate="label" module="emvemt">
117
+ <label>Limit logging days</label>
118
+ <frontend_type>text</frontend_type>
119
+ <comment>How many days will sending logs be kept ?</comment>
120
+ <sort_order>20</sort_order>
121
+ <show_in_default>1</show_in_default>
122
+ </keeping_days>
123
+ <enabled translate="label" module="emvemt">
124
+ <label>Activate Log Cleanning Mechanism</label>
125
+ <frontend_type>select</frontend_type>
126
+ <source_model>adminhtml/system_config_source_yesno</source_model>
127
+ <sort_order>50</sort_order>
128
+ <show_in_default>1</show_in_default>
129
+ </enabled>
130
+ <frequency translate="label">
131
+ <label>Frequency</label>
132
+ <frontend_type>select</frontend_type>
133
+ <source_model>adminhtml/system_config_source_cron_frequency</source_model>
134
+ <backend_model>emvemt/adminhtml_system_config_backend_log_cron</backend_model>
135
+ <sort_order>60</sort_order>
136
+ <show_in_default>1</show_in_default>
137
+ <show_in_website>0</show_in_website>
138
+ <show_in_store>0</show_in_store>
139
+ </frequency>
140
+ <day>
141
+ <label>Day of the week</label>
142
+ <frontend_type>select</frontend_type>
143
+ <source_model>emvcore/adminhtml_system_config_source_cronDay</source_model>
144
+ <sort_order>65</sort_order>
145
+ <depends><frequency>W</frequency></depends>
146
+ <show_in_default>1</show_in_default>
147
+ </day>
148
+ <date>
149
+ <label>Date of the month</label>
150
+ <frontend_type>select</frontend_type>
151
+ <source_model>emvcore/adminhtml_system_config_source_cronDate</source_model>
152
+ <sort_order>70</sort_order>
153
+ <depends><frequency>M</frequency></depends>
154
+ <show_in_default>1</show_in_default>
155
+ </date>
156
+ <time translate="label">
157
+ <label>Start Time</label>
158
+ <frontend_type>time</frontend_type>
159
+ <sort_order>90</sort_order>
160
+ <show_in_default>1</show_in_default>
161
+ <show_in_website>0</show_in_website>
162
+ <show_in_store>0</show_in_store>
163
+ </time>
164
+ </fields>
165
+ </log_cleanning>
166
  </groups>
167
  </emvemt>
168
  </sections>
169
+ </config>
 
app/code/community/Emv/Report/controllers/Adminhtml/ConversionController.php CHANGED
@@ -200,6 +200,6 @@ class Emv_Report_Adminhtml_ConversionController extends Mage_Adminhtml_Controlle
200
  */
201
  protected function _isAllowed()
202
  {
203
- return Mage::getSingleton('admin/session')->isAllowed('emailvision/abandonment');
204
  }
205
  }
200
  */
201
  protected function _isAllowed()
202
  {
203
+ return Mage::getSingleton('admin/session')->isAllowed('emailvision/abandonment/conversion');
204
  }
205
  }
app/code/community/Emv/Report/etc/adminhtml.xml CHANGED
@@ -3,9 +3,14 @@
3
  <menu>
4
  <emailvision>
5
  <children>
6
- <abandonment translate="title" module="abandonment_report">
7
- <title>Abandoned Cart Conversion Report</title>
8
- <action>emv_report/conversion</action>
 
 
 
 
 
9
  </abandonment>
10
  </children>
11
  </emailvision>
@@ -14,10 +19,15 @@
14
  <resources>
15
  <admin>
16
  <children>
17
- <emailvision translate="title" module="reports">
18
  <children>
19
- <abandonment translate="title">
20
- <title>Abandoned Cart Conversion Report</title>
 
 
 
 
 
21
  </abandonment>
22
  </children>
23
  </emailvision>
3
  <menu>
4
  <emailvision>
5
  <children>
6
+ <abandonment>
7
+ <children>
8
+ <conversion translate="title" module="abandonment_report">
9
+ <title>Conversion Report</title>
10
+ <action>emv_report/conversion</action>
11
+ <sort_order>30</sort_order>
12
+ </conversion>
13
+ </children>
14
  </abandonment>
15
  </children>
16
  </emailvision>
19
  <resources>
20
  <admin>
21
  <children>
22
+ <emailvision>
23
  <children>
24
+ <abandonment>
25
+ <children>
26
+ <conversion>
27
+ <title>Conversion Report</title>
28
+ <sort_order>20</sort_order>
29
+ </conversion>
30
+ </children>
31
  </abandonment>
32
  </children>
33
  </emailvision>
app/code/community/Emv/Report/etc/config.xml CHANGED
@@ -31,7 +31,7 @@
31
  <layout>
32
  <updates>
33
  <abandonment_report>
34
- <file>emailvision/abandonment_report.xml</file>
35
  </abandonment_report>
36
  </updates>
37
  </layout>
31
  <layout>
32
  <updates>
33
  <abandonment_report>
34
+ <file>smartfocus/abandonment_report.xml</file>
35
  </abandonment_report>
36
  </updates>
37
  </layout>
app/design/adminhtml/default/default/layout/{emailvision → smartfocus}/abandonment_report.xml RENAMED
@@ -2,7 +2,7 @@
2
  <layout>
3
  <abandonment_report_conversion_index>
4
  <reference name="content">
5
- <block type="abandonment_report/adminhtml_conversion" template="emailvision/abandonment/grid/container.phtml" name="abandonment.report.grid.container">
6
  <block type="abandonment_report/adminhtml_conversion_form" name="abandonment.report.grid.filter.form">
7
  </block>
8
  </block>
2
  <layout>
3
  <abandonment_report_conversion_index>
4
  <reference name="content">
5
+ <block type="abandonment_report/adminhtml_conversion" template="smartfocus/abandonment/grid/container.phtml" name="abandonment.report.grid.container">
6
  <block type="abandonment_report/adminhtml_conversion_form" name="abandonment.report.grid.filter.form">
7
  </block>
8
  </block>
app/design/adminhtml/default/default/layout/smartfocus/core.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <layout>
3
+ <default translate="label" module="page">
4
+ <reference name="head">
5
+ <action method="addCss"><name>smartfocus.css</name></action>
6
+ </reference>
7
+ </default>
8
+ </layout>
app/design/adminhtml/default/default/template/emailvision/datasync/system/config/getfields.phtml DELETED
@@ -1,15 +0,0 @@
1
- <?php
2
- /**
3
- * @category Auguria
4
- * @package Auguria_EmailVision
5
- * @author Auguria
6
- * @license http://opensource.org/licenses/gpl-3.0.html GNU General Public License version 3 (GPLv3)
7
- *
8
- * EmailVision getFields button to call the concerned controller action
9
- */
10
- ?>
11
- <a href="<?php echo Mage::getSingleton('adminhtml/url')->getUrl('emv_datasync/dataSync/getMemberFields');?>">
12
- <button class="scalable" type="button">
13
- <span id="validation_result"><?php echo $this->__('Get SmartFocus member fields') ?></span>
14
- </button>
15
- </a>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/abandonment/grid/container.phtml RENAMED
File without changes
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/account/associated_urls.phtml RENAMED
File without changes
app/design/adminhtml/default/default/template/smartfocus/cartalert/system/config/promo_rule.phtml ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ // prepare js file magento/js/mage/adminhtml
3
+ $baseJsUrl = Mage::getBaseUrl('js');
4
+ $widgetJs = $baseJsUrl . 'mage/adminhtml/wysiwyg/widget.js';
5
+ ?>
6
+ <script type='text/javascript' src='<?php echo $widgetJs ?>'></script>
7
+
8
+ <?php
9
+ $widgetCss = Mage::getDesign()->getSkinUrl('lib/prototype/windows/themes/magento.css');
10
+ ?>
11
+ <link rel='stylesheet' type='text/css' href='<?php echo $widgetCss?>' />
12
+
13
+ <?php
14
+ $widgetCss = Mage::getBaseUrl('js') . 'prototype/windows/themes/magento.css';
15
+ ?>
16
+ <link rel='stylesheet' type='text/css' href='<?php echo $widgetCss?>' />
17
+
18
+ <?php
19
+ $wdgetCssDefault = Mage::getBaseUrl('js') . 'prototype/windows/themes/default.css';
20
+ ?>
21
+ <link rel='stylesheet' type='text/css' href='<?php echo $wdgetCssDefault ?>' />
22
+
23
+
24
+ <?php // chooser button template?>
25
+ <span id="salesrule_id"></span>
26
+ <label class="widget-option-label" id="salesrule_idc30d6133660369e799b882a1d5da011clabel">
27
+ <?php echo $this->getLabel()?>
28
+ </label>
29
+
30
+ <div id="salesrule_idc30d6133660369e799b882a1d5da011cadvice-container" class="hidden"></div>
31
+ <script type="text/javascript">//<![CDATA[
32
+ (function() {
33
+ var instantiateChooser = function() {
34
+ window.salesrule_idc30d6133660369e799b882a1d5da011c = new WysiwygWidget.chooser(
35
+ "salesrule_idc30d6133660369e799b882a1d5da011c",
36
+ "<?php echo $this->getUrl('*/promo_quote/chooser', array())?>uniq_id/salesrule_idc30d6133660369e799b882a1d5da011c/",
37
+ <?php echo $this->getButtonConfigInJson() ?>
38
+ );
39
+ if ($("salesrule_idc30d6133660369e799b882a1d5da011cvalue")) {
40
+ $("salesrule_idc30d6133660369e799b882a1d5da011cvalue").advaiceContainer = "salesrule_idc30d6133660369e799b882a1d5da011cadvice-container";
41
+ }
42
+ }
43
+
44
+ if (document.loaded) { //allow load over ajax
45
+ instantiateChooser();
46
+ } else {
47
+ document.observe("dom:loaded", instantiateChooser);
48
+ }
49
+ })();
50
+ //]]></script>
51
+ <p class="note" id="note_salesrule_id">
52
+ <span><?php echo Mage::helper('abandonment')->__('Promotion rule that reminders will advertise.')?></span>
53
+ </p>
54
+
55
+ <label for="choosersalesrule_id"></label>
56
+ <span id="choosersalesrule_id"></span>
57
+ <input id="salesrule_idc30d6133660369e799b882a1d5da011cvalue"
58
+ name="<?php echo $this->getElementName()?>" value="<?php echo $this->getRuleId()?>" readonly="" type="hidden"
59
+ />
60
+ <button id="salesrule_idc30d6133660369e799b882a1d5da011ccontrol" title="<?php echo Mage::helper('abandonment')->__('Select Promotion Rule')?>" type="button" class="scalable btn-chooser" onclick="salesrule_idc30d6133660369e799b882a1d5da011c.choose()" style="">
61
+ <span><span><span><?php echo Mage::helper('abandonment')->__('Select Promotion Rule')?></span></span></span>
62
+ </button>
63
+
64
+
65
+ <?php // reset promotion ?>
66
+ <button id="clearrule" title="<?php echo Mage::helper('abandonment')->__('Clear Selected Rule')?>"
67
+ type="button" class="scalable btn-chooser" onclick="clearRule()" style="">
68
+ <span><span><span><?php echo Mage::helper('abandonment')->__('Clear Selected Rule')?></span></span></span>
69
+ </button>
70
+ <script>
71
+ function clearRule() {
72
+ $('salesrule_idc30d6133660369e799b882a1d5da011cvalue').value = '';
73
+ $('salesrule_idc30d6133660369e799b882a1d5da011clabel').innerHTML = '<?php echo Mage::helper('widget')->__('Not Selected')?>';
74
+ }
75
+ </script>
app/design/adminhtml/default/default/template/smartfocus/config/extension_status.phtml ADDED
@@ -0,0 +1,61 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * @var $this Emv_Core_Block_Adminhtml_Config_ExtensionStatus
4
+ * */
5
+ ?>
6
+ <table class="smartfocus-selection" cellspacing="0">
7
+ <col width="75%" />
8
+ <col width="25%" />
9
+ <thead>
10
+ <tr>
11
+ <th><?php echo $this->escapeHtml($this->getExtensionVersion()) ?></th>
12
+ <?php if ($this->getHelpLink()) :?>
13
+ <th class="smartfocus-selection-info">
14
+ <a href="<?php echo $this->escapeHtml($this->getHelpLink()) ?>" target="blank"><?php echo Mage::helper('emvcore')->__('Help')?></a>
15
+ </th>
16
+ <?php endif;?>
17
+ </tr>
18
+ </thead>
19
+ <tbody>
20
+ <tr>
21
+ <td colspan="2">
22
+ <label><?php echo $this->getMagentoVersionStatus(); ?></label>
23
+ </td>
24
+ </tr>
25
+ <tr>
26
+ <td colspan="2">
27
+ <label><?php echo $this->getEmvModulesVersionStatus(); ?></label>
28
+ </td>
29
+ </tr>
30
+ <tr>
31
+ <td colspan="2">
32
+ <label><?php echo $this->getPhpEnvironmentStatus(); ?></label>
33
+ </td>
34
+ </tr>
35
+ <tr>
36
+ <td colspan="2">
37
+ <label><?php echo $this->getCronStatus(); ?></label>
38
+ </td>
39
+ </tr>
40
+ <tr>
41
+ <td colspan="2">
42
+ <label><?php echo $this->getMemoryStatus(); ?></label>
43
+ </td>
44
+ </tr>
45
+ <tr>
46
+ <td colspan="2">
47
+ <label><?php echo $this->getDirectoryPermissionStatus(); ?></label>
48
+ </td>
49
+ </tr>
50
+ <?php foreach($this->getOtherTestList() as $test) :?>
51
+ <?php $status = $this->getStatusForTest($test)?>
52
+ <?php if ($status) :?>
53
+ <tr>
54
+ <td colspan="2">
55
+ <label><?php echo $status; ?></label>
56
+ </td>
57
+ </tr>
58
+ <?php endif;?>
59
+ <?php endforeach;?>
60
+ </tbody>
61
+ </table>
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/datasync/system/config/form/field/array.phtml RENAMED
File without changes
app/design/adminhtml/default/default/template/smartfocus/datasync/system/config/getfields.phtml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*@var $this Emv_DataSync_Block_Adminhtml_System_Config_GetFields */
3
+
4
+ /**
5
+ * SmartFocus getFields button to call the concerned controller action
6
+ */
7
+ ?>
8
+ <a href="<?php echo $this->getGetFieldsUrl() ?>">
9
+ <button class="scalable" type="button">
10
+ <span id="validation_result"><?php echo $this->__('Get SmartFocus member fields') ?></span>
11
+ </button>
12
+ </a>
app/design/adminhtml/default/default/template/smartfocus/emt/system/config/account_validation.phtml ADDED
@@ -0,0 +1,96 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+
2
+ <?php
3
+ $checkUrl = Mage::getSingleton('adminhtml/url')->getUrl('emvemt/template/validateTemplate');
4
+ ?>
5
+
6
+ <div id="messages-connection" style="display: none;">
7
+ <ul class="messages">
8
+ <li class="error-msg error-connection">
9
+ </li>
10
+ <li class="success-msg success-connection">
11
+ </li>
12
+ </ul>
13
+ </div>
14
+ <button id="validate-button" class="scalable" type="button">
15
+ <span id="validation_result"><?php echo Mage::helper('emvemt')->__('Check and Configure your SmartFocus Account') ?></span>
16
+ </button>
17
+
18
+
19
+ <script type="text/javascript">
20
+ //<![CDATA[
21
+
22
+ var Emv_Check_Account = Class.create();
23
+ Emv_Check_Account.prototype = {
24
+ initialize : function()
25
+ {
26
+ this.loading = false;
27
+ this.loader = new varienLoader(false);
28
+ this.checkUrl = "<?php echo $checkUrl ?>";
29
+
30
+ this.bindCheckAccountButton();
31
+ },
32
+ bindCheckAccountButton : function()
33
+ {
34
+ var button = $('validate-button');
35
+ Event.observe(button, 'click', this.checkAccount.bind(this));
36
+ },
37
+ checkAccount : function(event)
38
+ {
39
+ if (this.loading == false) {
40
+ this.loading = true;
41
+ var params = {
42
+ 'account_id' : $('emvemt_transactional_service_account').value
43
+ };
44
+ this.loader.load(this.checkUrl, params, this.proceedMessageReturn.bind(this));
45
+ }
46
+ },
47
+ proceedMessageReturn : function(serverResponse) {
48
+ this.loading = false;
49
+ this.hideAndRemoveMessage();
50
+
51
+ if (serverResponse) {
52
+ data = eval('(' + serverResponse + ')');
53
+ if (typeof(data.error) == 'object' && data.error.length >= 1) {
54
+ var html = this.prepareHtmlMessage(data.error);
55
+ $$('.error-connection').first().innerHTML = html;
56
+ }
57
+ if (typeof(data.information) == 'object' && data.information.length >= 1) {
58
+ var html = this.prepareHtmlMessage(data.information);
59
+ $$('.success-connection').first().innerHTML = html;
60
+ }
61
+ this.showMessage();
62
+ }
63
+ },
64
+ prepareHtmlMessage : function(messages)
65
+ {
66
+ html = '<ul>';
67
+ for (var i = 0; i < messages.length; i++) {
68
+ html += '<li><span>' + messages[i] + '</span></li>';
69
+ }
70
+ html += '</ul>';
71
+
72
+ return html;
73
+ },
74
+ hideAndRemoveMessage : function()
75
+ {
76
+ $$('.error-connection').first().innerHTML = "";
77
+ $$('.error-connection').first().hide();
78
+ $$('.success-connection').first().innerHTML = "";
79
+ $$('.success-connection').first().hide();
80
+
81
+ $('messages-connection').hide();
82
+ },
83
+ showMessage : function()
84
+ {
85
+ if ($$('.error-connection').first().innerHTML != "") {
86
+ $$('.error-connection').first().show();
87
+ }
88
+ if ($$('.success-connection').first().innerHTML != "") {
89
+ $$('.success-connection').first().show();
90
+ }
91
+ $('messages-connection').show();
92
+ }
93
+ }
94
+ checkAccountApply = new Emv_Check_Account();
95
+ //]]>
96
+ </script>
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/common_js.phtml RENAMED
File without changes
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/edit.phtml RENAMED
File without changes
app/design/adminhtml/default/default/template/{emailvision → smartfocus}/emt/template/mapped_attributes.phtml RENAMED
File without changes
app/design/frontend/base/default/layout/{emailvision → smartfocus}/abandonment.xml RENAMED
@@ -17,7 +17,7 @@ Customer account home dashboard layout
17
  <abandonment_customer_manage>
18
  <update handle="customer_account"/>
19
  <reference name="my.account.wrapper">
20
- <block type="abandonment/customer_abandonment" name="customer_abandonment" as="info1" template="emailvision/abandonment/customer.phtml"/>
21
  </reference>
22
  </abandonment_customer_manage>
23
  </layout>
17
  <abandonment_customer_manage>
18
  <update handle="customer_account"/>
19
  <reference name="my.account.wrapper">
20
+ <block type="abandonment/customer_abandonment" name="customer_abandonment" as="info1" template="smartfocus/abandonment/customer.phtml"/>
21
  </reference>
22
  </abandonment_customer_manage>
23
  </layout>
app/design/frontend/base/default/template/{emailvision → smartfocus}/abandonment/customer.phtml RENAMED
File without changes
app/design/frontend/base/default/template/{emailvision → smartfocus}/abandonment/reminder/items.phtml RENAMED
@@ -23,10 +23,10 @@ $cart = $this->getCart();
23
  href="<?php echo $itemLink?>"
24
  title="Checkout Now" target="_blank">
25
  <img
26
- alt="<?php echo $this->escapeHtml($item->getName()) ?>"
27
- border="0" style="display: block;"
28
- src="<?php echo Mage::helper('abandonment')->getProductImageUrl($item->getProductId()) ?>"
29
- width="85" />
30
  </a>
31
  </td>
32
  <td width="8">&nbsp;</td>
23
  href="<?php echo $itemLink?>"
24
  title="Checkout Now" target="_blank">
25
  <img
26
+ alt="<?php echo $this->escapeHtml($item->getName()) ?>"
27
+ border="0" style="display: block;"
28
+ src="<?php echo Mage::helper('abandonment')->getProductImageUrl($item) ?>"
29
+ width="85" />
30
  </a>
31
  </td>
32
  <td width="8">&nbsp;</td>
app/locale/en_US/Emv_CartAlert.csv CHANGED
@@ -1,3 +1,5 @@
 
 
1
  "You are already unsubscribed from abandoned carts notifications.","You are already unsubscribed from abandoned carts notifications."
2
  "You were successfully unsubscribed from abandoned carts notifications.","You were successfully unsubscribed from abandoned carts notifications."
3
  "Cart Reminder Subscription","Cart Reminder Subscription"
@@ -7,10 +9,13 @@
7
  "The link cannot be used by registered customers.","The link cannot be used by registered customers."
8
  "The link is invalid.","The link is invalid."
9
  "SmartFocus - Abandonment cart configs","SmartFocus - Abandonment cart configs"
10
- "Abandonment Cart Alert","Abandonment Cart Alert"
11
  "Email Sender","Email Sender"
12
  "Image Size","Image Size"
13
- "Shopping Cart Prices Rule Id","Shopping Cart Prices Rule Id"
 
 
 
14
  "Coupon Code Length","Coupon Code Length"
15
  "Coupon Code Format","Coupon Code Format"
16
  "Coupon Code Prefix","Coupon Code Prefix"
@@ -18,22 +23,42 @@
18
  "Dash Every X Characters For Coupon Code","Dash Every X Characters For Coupon Code"
19
  "If empty no separation.","If empty no separation."
20
  "Excluding prefix, suffix and separators.","Excluding prefix, suffix and separators."
21
- "First Alert Configuration","First Alert Configuration"
22
- "First Email Alert Enable","First Email Alert Enable"
23
- "First Email Alert Delay (in hour)","First Email Alert Delay (in hour)"
24
- "First Email Alert Template","First Email Alert Template"
25
- "Second Alert Configuration","Second Alert Configuration"
26
- "Second Email Alert Enable","Second Email Alert Enable"
27
- "Second Email Alert Delay (in hour)","Second Email Alert Delay (in hour)"
28
- "Second Email Template","Second Email Template"
29
- "Third Alert Configuration","Third Alert Configuration"
30
- "Third Email Alert Enable","Third Email Alert Enable"
31
- "Third Email Alert Delay (in hour)","Third Email Alert Delay (in hour)"
32
- "Third Email Alert Template","Third Email Alert Template"
33
  "Cart Reminder Email Subscription","Cart Reminder Email Subscription"
34
  "Back","Back"
35
  "Save","Save"
36
  "Abandoned Cart 1","Abandoned Cart 1"
37
  "Abandoned Cart 2","Abandoned Cart 2"
38
  "Abandoned Cart 3","Abandoned Cart 3"
39
- "General","General"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Abandoned Carts","Abandoned Carts"
2
+ "List","List"
3
  "You are already unsubscribed from abandoned carts notifications.","You are already unsubscribed from abandoned carts notifications."
4
  "You were successfully unsubscribed from abandoned carts notifications.","You were successfully unsubscribed from abandoned carts notifications."
5
  "Cart Reminder Subscription","Cart Reminder Subscription"
9
  "The link cannot be used by registered customers.","The link cannot be used by registered customers."
10
  "The link is invalid.","The link is invalid."
11
  "SmartFocus - Abandonment cart configs","SmartFocus - Abandonment cart configs"
12
+ "Abandoned Cart Reminders","Abandoned Cart Reminders"
13
  "Email Sender","Email Sender"
14
  "Image Size","Image Size"
15
+ "Shopping Cart Prices Rule","Shopping Cart Prices Rule"
16
+ "Promotion rule that reminders will advertise.","Promotion rule that reminders will advertise."
17
+ "Select Promotion Rule","Select Promotion Rule"
18
+ "Clear Selected Rule","Clear Selected Rule"
19
  "Coupon Code Length","Coupon Code Length"
20
  "Coupon Code Format","Coupon Code Format"
21
  "Coupon Code Prefix","Coupon Code Prefix"
23
  "Dash Every X Characters For Coupon Code","Dash Every X Characters For Coupon Code"
24
  "If empty no separation.","If empty no separation."
25
  "Excluding prefix, suffix and separators.","Excluding prefix, suffix and separators."
26
+ "First Reminder Configuration","First Reminder Configuration"
27
+ "First Email Reminder Enable","First Email Reminder Enable"
28
+ "First Email Reminder Delay (in hours)","First Email Reminder Delay (in hours)"
29
+ "First Email Reminder Template","First Email Reminder Template"
30
+ "Second Reminder Configuration","Second Reminder Configuration"
31
+ "Second Email Reminder Enable","Second Email Reminder Enable"
32
+ "Second Email Reminder Delay (in hours)","Second Email Reminder Delay (in hours)"
33
+ "Second Email Reminder Template","Second Email Reminder Template"
34
+ "Third Reminder Configuration","Third Reminder Configuration"
35
+ "Third Email Reminder Enable","Third Email Reminder Enable"
36
+ "Third Email Reminder Delay (in hours)","Third Email Reminder Delay (in hours)"
37
+ "Third Email Reminder Template","Third Email Reminder Template"
38
  "Cart Reminder Email Subscription","Cart Reminder Email Subscription"
39
  "Back","Back"
40
  "Save","Save"
41
  "Abandoned Cart 1","Abandoned Cart 1"
42
  "Abandoned Cart 2","Abandoned Cart 2"
43
  "Abandoned Cart 3","Abandoned Cart 3"
44
+ "General","General"
45
+ "Maximum Abandoned Carts per One Run","Maximum Abandoned Carts per One Run"
46
+ "Abandoned Cart Reminders","Abandoned Cart Reminders"
47
+ "Cannot send reminder for cart #%s. Reason: %s","Cannot send reminder for cart #%s. Reason: %s"
48
+ "%s carts were successfully sent with %s","%s carts were successfully sent with %s"
49
+ "One cart was successfully sent with %s","One cart was successfully sent with %s"
50
+ "Abandoned Cart (customer email : %s - on store %s)","Abandoned Cart (customer email : %s - on store %s)"
51
+ "Customer ID","Customer ID"
52
+ "Sent Reminder","Sent Reminder"
53
+ "Reminder Last Update","Reminder Last Update"
54
+ "Subscribed to abandoned cart reminders","Subscribed to abandoned cart reminders"
55
+ "Reminder Coupon","Reminder Coupon"
56
+ "Test First Reminder","Test First Reminder"
57
+ "Test Second Reminder","Test Second Reminder"
58
+ "Test Third Reminder","Test Third Reminder"
59
+ "None","None"
60
+ "First Reminder","First Reminder"
61
+ "Second Reminder","Second Reminder"
62
+ "Third Reminder","Third Reminder"
63
+ "Number of Item Types","Number of Item Types"
64
+ "Number of Items","Number of Items"
app/locale/en_US/Emv_Core.csv CHANGED
@@ -24,7 +24,7 @@
24
  "Unable to find an account to delete.","Unable to find an account to delete."
25
  "The SmartFocus account has been saved.","The SmartFocus account has been saved."
26
  "Your selected account does not exist anymore!","Your selected account does not exist anymore!"
27
- "Could not verify the account. Network problems occured! Please Save again!","Could not verify the account. Network problems occured! Please Save again!"
28
  "Your account ""%s"" is not allowed for %s !","Your account ""%s"" is not allowed for %s !"
29
  "Please define a valid url for %s !","Please define a valid url for %s !"
30
  "Could not enable ""%s"" process ! Please select an account in the list !","Could not enable ""%s"" process ! Please select an account in the list !"
@@ -57,4 +57,34 @@
57
  "Please enter a valid url for %s!","Please enter a valid url for %s!"
58
  "Service","Service"
59
  "Url","Url"
60
- "Remove","Remove"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
24
  "Unable to find an account to delete.","Unable to find an account to delete."
25
  "The SmartFocus account has been saved.","The SmartFocus account has been saved."
26
  "Your selected account does not exist anymore!","Your selected account does not exist anymore!"
27
+ "Could not verify the selected account. Network problems occured!","Could not verify the selected account. Network problems occured!"
28
  "Your account ""%s"" is not allowed for %s !","Your account ""%s"" is not allowed for %s !"
29
  "Please define a valid url for %s !","Please define a valid url for %s !"
30
  "Could not enable ""%s"" process ! Please select an account in the list !","Could not enable ""%s"" process ! Please select an account in the list !"
57
  "Please enter a valid url for %s!","Please enter a valid url for %s!"
58
  "Service","Service"
59
  "Url","Url"
60
+ "Remove","Remove"
61
+ "SmartFocus Connector Status (Version %s)","SmartFocus Connector Status (Version %s)"
62
+ "<span class=""icon-status"">%s</span> Your Magento version is <strong>%s</strong>.","<span class=""icon-status"">%s</span> Your Magento version is <strong>%s</strong>."
63
+ "Required PHP version is <strong>%s</strong> - current version <strong>%s</strong>.","Required PHP version is <strong>%s</strong> - current version <strong>%s</strong>."
64
+ "Your PHP version (<strong>%s</strong>) is satisfied.","Your PHP version (<strong>%s</strong>) is satisfied."
65
+ "Required Php Extensions are <strong>%s</strong>.","Required Php Extensions are <strong>%s</strong>."
66
+ "The followings are missing : <strong>%s</strong>.","The followings are missing : <strong>%s</strong>."
67
+ "All the required Php Extensions (<strong>%s</strong>) are correctly installed.","All the required Php Extensions (<strong>%s</strong>) are correctly installed."
68
+ "<span class=""icon-status"">%s</span> Magento Cron Process has been correctly configured!","<span class=""icon-status"">%s</span> Magento Cron Process has been correctly configured!"
69
+ "<span class=""icon-status"">%s</span> Magento Cron Process has not been correctly activated!","<span class=""icon-status"">%s</span> Magento Cron Process has not been correctly activated!"
70
+ "<span class=""icon-status"">%s</span> memory_limit is set to <strong>%s</strong>.","<span class=""icon-status"">%s</span> memory_limit is set to <strong>%s</strong>."
71
+ "<span class=""icon-status"">%s</span> memory_limit should be set to at least <strong>%s M</strong> (currently %s).","<span class=""icon-status"">%s</span> memory_limit should be set to at least <strong>%s M</strong> (currently %s)."
72
+ "Data Sync","Data Sync"
73
+ "Title","Title"
74
+ "State","State"
75
+ "New","New"
76
+ "Processing","Processing"
77
+ "Failed","Failed"
78
+ "Success","Success"
79
+ "Status (%)","Status (%)"
80
+ "Terminated At","Terminated At"
81
+ "View Log","View Log"
82
+ "SmartFocus Data Process List","SmartFocus Data Process List"
83
+ "Data Process List","Data Process List"
84
+ "Error during get output file","Error during get output file"
85
+ "Error during get process log","Error during get process log"
86
+ "Please select something!","Please select something!"
87
+ "Unable to delete the process #%s. Reason: %s","Unable to delete the process #%s. Reason: %s"
88
+ "Unable to delete the process #%s","Unable to delete the process #%s"
89
+ "%s records were successfully deleted","%s records were successfully deleted"
90
+ "One record was successfully deleted","One record was successfully deleted"
app/locale/en_US/Emv_DataSync.csv CHANGED
@@ -41,4 +41,18 @@
41
  "Daily","Daily"
42
  "General","General"
43
  "Enabled","Enabled"
44
- "SmartFocus Entity Id","SmartFocus Entity Id"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
41
  "Daily","Daily"
42
  "General","General"
43
  "Enabled","Enabled"
44
+ "SmartFocus Entity Id","SmartFocus Entity Id"
45
+ "Customer Billing Address","Customer Billing Address"
46
+ "Customer Shipping Address","Customer Shipping Address"
47
+ "Customer","Customer"
48
+ "Newsletter Subscriber","Newsletter Subscriber"
49
+ "Newsletter Subscriber Queue","Newsletter Subscriber Queue"
50
+ "Customer Name","Customer Name"
51
+ "Last Sync","Last Sync"
52
+ "Last Data Update","Last Data Update"
53
+ "Last Unsubscription","Last Unsubscription"
54
+ "Scheduled","Scheduled"
55
+ "Schedule","Schedule"
56
+ "Stop","Stop"
57
+ "Get Csv File(s)","Get Csv File(s)"
58
+ "Manual Sync","Manual Sync"
app/locale/en_US/Emv_Emt.csv CHANGED
@@ -90,9 +90,9 @@ Mode","Mode"
90
  "Server Error","Server Error"
91
  "Network Problem","Network Problem"
92
  "Invalid SmartFocus Parameters","Invalid SmartFocus Parameters"
93
- "classic","Classic"
94
- "emv create","SmartFocus Template"
95
- "emv send","SmartFocus Routage"
96
  "Refresh All Attributes","Refresh All Attributes"
97
  "Insert Prepared Magento Variables","Insert Prepared Magento Variables"
98
  "Please select a template","Please select a template"
@@ -108,4 +108,6 @@ Mode","Mode"
108
  "Template Information","Template Information"
109
  "Are you sure to change the sending mode ? All your mapped attributes will be deleted !","Are you sure to change the sending mode ? All your mapped attributes will be deleted !"
110
  "SmartFocus Attribute","SmartFocus Attribute"
111
- "Are you sure to refresh all your mapped SmartFocus Attributes ?","Are you sure to refresh all your mapped SmartFocus Attributes ?"
 
 
90
  "Server Error","Server Error"
91
  "Network Problem","Network Problem"
92
  "Invalid SmartFocus Parameters","Invalid SmartFocus Parameters"
93
+ "Classic","Classic"
94
+ "SmartFocus Template","SmartFocus Template"
95
+ "SmartFocus Routage","SmartFocus Routage"
96
  "Refresh All Attributes","Refresh All Attributes"
97
  "Insert Prepared Magento Variables","Insert Prepared Magento Variables"
98
  "Please select a template","Please select a template"
108
  "Template Information","Template Information"
109
  "Are you sure to change the sending mode ? All your mapped attributes will be deleted !","Are you sure to change the sending mode ? All your mapped attributes will be deleted !"
110
  "SmartFocus Attribute","SmartFocus Attribute"
111
+ "Are you sure to refresh all your mapped SmartFocus Attributes ?","Are you sure to refresh all your mapped SmartFocus Attributes ?"
112
+ "Check and Configure your SmartFocus Account","Check and Configure your SmartFocus Account"
113
+ "Your account is correctly set up and ready to send emails","Your account is correctly set up and ready to send emails"
app/locale/en_US/template/email/emailvision/datasync/cron_errors.html DELETED
@@ -1,5 +0,0 @@
1
- <!--@subject Emailvision synchronization by cron process errors @-->
2
- <!--@vars
3
- {"var errors":"Cron errors"}
4
- @-->
5
- {{var errors}}
 
 
 
 
 
app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template1.html RENAMED
File without changes
app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template2.html RENAMED
File without changes
app/locale/en_US/template/email/{emailvision → smartfocus}/abandonment/template3.html RENAMED
File without changes
app/locale/en_US/template/email/smartfocus/datasync/cron_errors.html ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <!--@subject SmartFocus Synchronization by cron process errors @-->
2
+ <!--@vars
3
+ {"var errors":"Cron errors"}
4
+ @-->
5
+ {{var errors}}
app/locale/fr_FR/Emv_CartAlert.csv CHANGED
@@ -1,3 +1,5 @@
 
 
1
  "You are already unsubscribed from abandoned carts notifications.","Vous êtes déjà désinscrit des relances de paniers abandonnés."
2
  "You were successfully unsubscribed from abandoned carts notifications.","Vous avez été désinscrit des relances de paniers abandonnés avec succès"
3
  "Cart Reminder Subscription","Inscription aux relances paniers abandonnés"
@@ -8,7 +10,10 @@
8
  "The link is invalid.","Le lien est invalide."
9
  "Cart Reminder Email Subscription","Inscription Aux Emails Relances Paniers Abandonnés"
10
  "Image Size","Taille image"
11
- "Shopping Cart Prices Rule Id","Id de règle de prix du panier"
 
 
 
12
  "Coupon Code Length","Longueur du code coupon"
13
  "Coupon Code Format","Format du code coupon"
14
  "Coupon Code Prefix","Préfixe du code coupon"
@@ -19,22 +24,42 @@
19
  "Abandoned Cart 1","Panier Abandonné 1"
20
  "Abandoned Cart 2","Panier Abandonné 2"
21
  "Abandoned Cart 3","Panier Abandonné 3"
22
- "Abandonment Cart Alert","Relance panier abandonné"
23
- "First Alert Configuration","Configuration première relance"
24
- "First Email Alert Enable","Activation première relance"
25
- "First Email Alert Delay (in hour)","Délai première relance (en heure)"
26
- "First Email Alert Template","Template première relance"
27
- "Second Alert Configuration","Configuration deuxième relance"
28
- "Second Email Alert Enable","Activation deuxième relance"
29
- "Second Email Alert Delay (in hour)","Délai deuxième relance (en heure)"
30
- "Second Email Template","Template deuxième relance"
31
- "Third Alert Configuration","Configuration troisième relance"
32
- "Third Email Alert Enable","Activation troisième relance"
33
- "Third Email Alert Delay (in hour)","Délai troisième relance (en heure)"
34
- "Third Email Alert Template","Template troisième relance"
35
  "Sender Identity","Identité de l'expéditeur"
36
  "Email Sender","Expéditeur Email"
37
  "Back","Retour"
38
  "Save","Valider"
39
  "General","Général"
40
- "SmartFocus - Abandonment cart configs","SmartFocus - Configurations de la relance panier abandoné"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Abandoned Carts","Paniers abandonnés"
2
+ "List","Liste"
3
  "You are already unsubscribed from abandoned carts notifications.","Vous êtes déjà désinscrit des relances de paniers abandonnés."
4
  "You were successfully unsubscribed from abandoned carts notifications.","Vous avez été désinscrit des relances de paniers abandonnés avec succès"
5
  "Cart Reminder Subscription","Inscription aux relances paniers abandonnés"
10
  "The link is invalid.","Le lien est invalide."
11
  "Cart Reminder Email Subscription","Inscription Aux Emails Relances Paniers Abandonnés"
12
  "Image Size","Taille image"
13
+ "Shopping Cart Prices Rule","Règle de prix du panier"
14
+ "Promotion rule that reminders will advertise.","Règle de promotion pour laquelle rappels font de la publicité."
15
+ "Select Promotion Rule","Séléctioner règle de prix du panier"
16
+ "Clear Selected Rule","Supprimer la règle séléctionnée"
17
  "Coupon Code Length","Longueur du code coupon"
18
  "Coupon Code Format","Format du code coupon"
19
  "Coupon Code Prefix","Préfixe du code coupon"
24
  "Abandoned Cart 1","Panier Abandonné 1"
25
  "Abandoned Cart 2","Panier Abandonné 2"
26
  "Abandoned Cart 3","Panier Abandonné 3"
27
+ "Abandoned Cart Reminders","Relances panier abandonné"
28
+ "First Reminder Configuration","Configuration première relance"
29
+ "First Email Reminder Enable","Activation première relance"
30
+ "First Email Reminder Delay (in hours)","Délai première relance (en heures)"
31
+ "First Email Reminder Template","Template première relance"
32
+ "Second Reminder Configuration","Configuration deuxième relance"
33
+ "Second Email Reminder Enable","Activation deuxième relance"
34
+ "Second Email Reminder Delay (in hours)","Délai deuxième relance (en heures)"
35
+ "Second Email Reminder Template","Template deuxième relance"
36
+ "Third Reminder Configuration","Configuration troisième relance"
37
+ "Third Email Reminder Enable","Activation troisième relance"
38
+ "Third Email Reminder Delay (in hours)","Délai troisième relance (en heures)"
39
+ "Third Email Reminder Template","Template troisième relance"
40
  "Sender Identity","Identité de l'expéditeur"
41
  "Email Sender","Expéditeur Email"
42
  "Back","Retour"
43
  "Save","Valider"
44
  "General","Général"
45
+ "SmartFocus - Abandonment cart configs","SmartFocus - Configurations de la relance panier abandoné"
46
+ "Maximum Abandoned Carts per One Run","Nombre de paniers abandonés à traiter par lancement"
47
+ "Abandoned Cart Reminders","Rappels des paniers abandonés"
48
+ "Cannot send reminder for cart #%s. Reason: %s","Impossible d'envoyer le rappel pour le panier #%s. Raison : %s"
49
+ "%s carts were successfully sent with %s","%s paniers ont été énvoyé avec %s"
50
+ "One cart was successfully sent with %s","Un panier a été envoyé avec %s"
51
+ "Abandoned Cart (customer email : %s - on store %s)","Panier (attaché au mail : %s - passé sur le store %s)"
52
+ "Customer ID","ID Client"
53
+ "Sent Reminder","Rappel Envoyé"
54
+ "Reminder Last Update","Dernière mise à jour du rappel"
55
+ "Subscribed to abandoned cart reminders","Souscrit au rappel"
56
+ "Reminder Coupon","Coupon attaché au rappel"
57
+ "Test First Reminder","Testez premier rappel"
58
+ "Test Second Reminder","Testez deuxième rappel"
59
+ "Test Third Reminder","Testez troisième rappel"
60
+ "None","Aucun"
61
+ "First Reminder","Premier rappel"
62
+ "Second Reminder","Deuxième rappel"
63
+ "Third Reminder","Troisième rappel"
64
+ "Number of Item Types","Nombre de types de produits"
65
+ "Number of Items","Nombre d'articles"
app/locale/fr_FR/Emv_Core.csv CHANGED
@@ -22,7 +22,7 @@
22
  "SmartFocus account deleted.","Votre compte SmartFocus a été supprimé."
23
  "Unable to find an account to delete.","Aucun compte n'a été trouvé pour suppression."
24
  "Your selected account does not exist anymore!","Votre compte sélectionné n'existe plus!"
25
- "Could not verify the account. Network problems occured! Please Save again!","Connexion au webservice SmartFocus impossible, veuillez ré-essayer à nouveau!"
26
  "Your account ""%s"" is not allowed for %s !","Votre compte ""%s"" n'est pas autorisé pour %s !"
27
  "Please define a valid url for %s !","Merci de renseigner un valid url pour %s!"
28
  "Could not enable ""%s"" process ! Please select an account in the list !","Impossible d'activer ""%s"" process ! Veuillez sélectionner un compte dans la liste !"
@@ -58,4 +58,34 @@
58
  "Url","Url"
59
  "Add","Ajouter"
60
  "Remove","Supprimer"
61
- "General","Général"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
22
  "SmartFocus account deleted.","Votre compte SmartFocus a été supprimé."
23
  "Unable to find an account to delete.","Aucun compte n'a été trouvé pour suppression."
24
  "Your selected account does not exist anymore!","Votre compte sélectionné n'existe plus!"
25
+ "Could not verify the selected account. Network problems occured!","Impossible de vérifier le compte séléctionné. Connexion au webservice SmartFocus impossible, veuillez ré-essayer à nouveau!"
26
  "Your account ""%s"" is not allowed for %s !","Votre compte ""%s"" n'est pas autorisé pour %s !"
27
  "Please define a valid url for %s !","Merci de renseigner un valid url pour %s!"
28
  "Could not enable ""%s"" process ! Please select an account in the list !","Impossible d'activer ""%s"" process ! Veuillez sélectionner un compte dans la liste !"
58
  "Url","Url"
59
  "Add","Ajouter"
60
  "Remove","Supprimer"
61
+ "General","Général"
62
+ "SmartFocus Connector Status (Version %s)","Connecteur Magento statut (Version %s)"
63
+ "<span class=""icon-status"">%s</span> Your Magento version is <strong>%s</strong>.","<span class=""icon-status"">%s</span> Votre version de Magento est <strong>%s</strong>."
64
+ "Required PHP version is <strong>%s</strong> - current version <strong>%s</strong>.","Version PHP requise est <strong>%s</strong> - version actuelle <strong>%s</strong>."
65
+ "Your PHP version (<strong>%s</strong>) is satisfied.","Votre version PHP (<strong>%s</strong>) est satisfaite."
66
+ "Required Php Extensions are <strong>%s</strong>.","Les PHP extension obligatoire sont <strong>%s</strong>."
67
+ "The followings are missing : <strong>%s</strong>.","Les extensions suivantes sont manquantes : <strong>%s</strong>."
68
+ "All the required Php Extensions (<strong>%s</strong>) are correctly installed.","Toutes les extensions PHP obligatoires (<strong>%s </strong>) sont correctement installées."
69
+ "<span class=""icon-status"">%s</span> Magento Cron Process has been correctly configured!","<span class=""icon-status"">%s</span> Cron de Magento a été correctement configuré!"
70
+ "<span class=""icon-status"">%s</span> Magento Cron Process has not been correctly activated!","<span class=""icon-status"">%s </span> Cron de Magento n'a pas été correctement activé!"
71
+ "<span class=""icon-status"">%s</span> memory_limit is set to <strong>%s</strong>.","<span class=""icon-status"">%s</span> memory_limit est configuré à <strong>%s</strong>."
72
+ "<span class=""icon-status"">%s</span> memory_limit should be set to at least <strong>%s M</strong> (currently %s).","<span class=""icon-status"">%s </span> memory_limit doit être réglé à au moins <strong>%s M </strong> (actuellement %s)."
73
+ "Data Sync","Data Sync"
74
+ "Title","Titre"
75
+ "State","Etat"
76
+ "New","Nouveau"
77
+ "Processing","En cours de traitement"
78
+ "Failed","Echoué"
79
+ "Success","Succès"
80
+ "Status (%)","Statut (%)"
81
+ "Terminated At","Terminé à"
82
+ "View Log","Consulter le log"
83
+ "SmartFocus Data Process List","Liste des procès SmartFocus"
84
+ "Data Process List","Liste des procès"
85
+ "Error during get output file","Erreur lors de la lecture de fichier output"
86
+ "Error during get process log","Erreur lors de la récupérartion de log"
87
+ "Please select something!","Merci de choisir un élément!"
88
+ "Unable to delete the process #%s. Reason: %s","Impossible de supprimer le processus #%s. Raison: %s"
89
+ "Unable to delete the process #%s","Impossible de supprimer le processus #%s"
90
+ "%s records were successfully deleted","%s procès ont été supprimés."
91
+ "One record was successfully deleted","Un procès a été supprimé."
app/locale/fr_FR/Emv_DataSync.csv CHANGED
@@ -26,6 +26,7 @@
26
  "Add Field","Ajouter un champ"
27
  "Magento Fields","Champs Magento"
28
  "SmartFocus Member Fields","Champs de la table membre SmartFocus"
 
29
  "If enabled, Magento newsletter subscribers will be synced by their email address. By default, the SmartFocus Entity Id will be used.","Si activée, les abonnés à la newsletter Magento seront synchronisés par leur adresse e-mail. Par défaut, SmartFocus Id sera utilisé."
30
  "SmartFocus Entity Id","SmartFocus id"
31
  "Default field used to link a Magento newsletter subscriber to a SmartFocus member. CLIENTURN is selected by default.","Champ par défaut utilisé pour lier l'identifiant d'un abonné à la newsletter à un membre SmartFocus correspondant. CLIENTURN est utilisé par défaut."
@@ -42,4 +43,18 @@
42
  "Daily","Quotidiennement"
43
  "General","Général"
44
  "Enabled","Activé"
45
- "Frequency","Fréquence"
 
 
 
 
 
 
 
 
 
 
 
 
 
 
26
  "Add Field","Ajouter un champ"
27
  "Magento Fields","Champs Magento"
28
  "SmartFocus Member Fields","Champs de la table membre SmartFocus"
29
+ "Synchronize with email","Synchroniser avec email"
30
  "If enabled, Magento newsletter subscribers will be synced by their email address. By default, the SmartFocus Entity Id will be used.","Si activée, les abonnés à la newsletter Magento seront synchronisés par leur adresse e-mail. Par défaut, SmartFocus Id sera utilisé."
31
  "SmartFocus Entity Id","SmartFocus id"
32
  "Default field used to link a Magento newsletter subscriber to a SmartFocus member. CLIENTURN is selected by default.","Champ par défaut utilisé pour lier l'identifiant d'un abonné à la newsletter à un membre SmartFocus correspondant. CLIENTURN est utilisé par défaut."
43
  "Daily","Quotidiennement"
44
  "General","Général"
45
  "Enabled","Activé"
46
+ "Frequency","Fréquence"
47
+ "Customer Billing Address","Adresse de facturation"
48
+ "Customer Shipping Address","Adresse de livraison"
49
+ "Customer","Client"
50
+ "Newsletter Subscriber","Abonné à la newsletter"
51
+ "Newsletter Subscriber Queue","List d'attente des abonnés"
52
+ "Customer Name","Nom du client"
53
+ "Last Sync","Dernière Sync."
54
+ "Last Data Update","Dernière modification de données"
55
+ "Last Unsubscription","Dernière désinscription"
56
+ "Scheduled","Programmé"
57
+ "Schedule","Programmer"
58
+ "Stop","Stopper"
59
+ "Get Csv File(s)","Récupérer fichier(s) Csv"
60
+ "Manual Sync","Synchronisation manuelle"
app/locale/fr_FR/Emv_Emt.csv CHANGED
@@ -89,9 +89,9 @@ Mode","Mode"
89
  "Server Error","Serveur problème"
90
  "Network Problem","Problème de réseau"
91
  "Invalid SmartFocus Parameters","Paramètres d'envoi invalides"
92
- "classic","Classic"
93
- "emv create","SmartFocus Template"
94
- "emv send","SmartFocus Routage"
95
  "Refresh All Attributes","Actualiser tous les attributs"
96
  "Insert Prepared Magento Variables","Insérer les variables Magento"
97
  "Please select a template","Veuillez sélectionner un modèle"
@@ -108,4 +108,6 @@ Mode","Mode"
108
  "Are you sure to change the sending mode ? All your mapped attributes will be deleted !","Etes-vous sûr de changer le mode d\'envoi? Tous vos attributs mappés seront supprimés!"
109
  "SmartFocus Attribute","Attribut SmartFocus"
110
  "Are you sure to refresh all your mapped SmartFocus Attributes ?","Etes-vous sûr de rafraîchir tous vos attributs SmartFocus mappés?"
111
- ""Email Templates","Modèles d'email"
 
 
89
  "Server Error","Serveur problème"
90
  "Network Problem","Problème de réseau"
91
  "Invalid SmartFocus Parameters","Paramètres d'envoi invalides"
92
+ "Classic","Classic"
93
+ "SmartFocus Template","SmartFocus Template"
94
+ "SmartFocus Routage","SmartFocus Routage"
95
  "Refresh All Attributes","Actualiser tous les attributs"
96
  "Insert Prepared Magento Variables","Insérer les variables Magento"
97
  "Please select a template","Veuillez sélectionner un modèle"
108
  "Are you sure to change the sending mode ? All your mapped attributes will be deleted !","Etes-vous sûr de changer le mode d\'envoi? Tous vos attributs mappés seront supprimés!"
109
  "SmartFocus Attribute","Attribut SmartFocus"
110
  "Are you sure to refresh all your mapped SmartFocus Attributes ?","Etes-vous sûr de rafraîchir tous vos attributs SmartFocus mappés?"
111
+ ""Email Templates","Modèles d'email"
112
+ "Check and Configure your SmartFocus Account","Vérifier et configurer votre compte SmartFocus"
113
+ "Your account is correctly set up and ready to send emails","Votre compte est correctement configuré et prêt à envoyer des e-mails"
app/locale/fr_FR/Emv_Report.csv CHANGED
@@ -1,3 +1,4 @@
 
1
  "Total Abandoned Cart Report","Rapport de paniers abandonés"
2
  "the first reminders","les premières relances"
3
  "the second reminders","les secondes relances"
1
+ "Conversion Report","Rapport de conversion"
2
  "Total Abandoned Cart Report","Rapport de paniers abandonés"
3
  "the first reminders","les premières relances"
4
  "the second reminders","les secondes relances"
lib/EmailVision/Api/BatchMemberService.php CHANGED
@@ -22,10 +22,16 @@ class EmailVision_Api_BatchMemberService extends EmailVision_Api_Common
22
  const CSV_FIELD_ENCLOSURE = '"';
23
 
24
  /**
25
- * Max file size in byte
26
  */
27
- const MAX_FILESIZE = 50000000;
28
- const MAX_ROW = 150000;
 
 
 
 
 
 
29
 
30
  /**
31
  * File index
@@ -65,6 +71,56 @@ class EmailVision_Api_BatchMemberService extends EmailVision_Api_Common
65
  return self::$_statusOk;
66
  }
67
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
68
  /**
69
  * Create csv files for a given list of members
70
  * - you need
@@ -135,11 +191,11 @@ class EmailVision_Api_BatchMemberService extends EmailVision_Api_Common
135
  $rowCount++;
136
  $listMember[] = $id;
137
 
138
- // If filesize approach max uploadable (48Mb), close file and set a new one on next turn
139
  if (
140
- $fileSizeInBytes > self::MAX_FILESIZE
141
  || --$totalMemberCount == 0
142
- || $rowCount >= self::MAX_ROW
143
  ) {
144
  fclose($fileHandler);
145
  $fileHandler = null;
22
  const CSV_FIELD_ENCLOSURE = '"';
23
 
24
  /**
25
+ * Max file size in bytes (77 Mb)
26
  */
27
+ const MAX_FILESIZE = 80000000;
28
+ const MAX_ROW = 250000;
29
+
30
+ /**
31
+ * @var int
32
+ */
33
+ protected $_maxFilesize = false;
34
+ protected $_maxRow = false;
35
 
36
  /**
37
  * File index
71
  return self::$_statusOk;
72
  }
73
 
74
+ /**
75
+ * Set max file size in bytes
76
+ *
77
+ * @param int $size
78
+ * @return EmailVision_Api_BatchMemberService
79
+ */
80
+ public function setMaxFileSize($size)
81
+ {
82
+ $this->_maxFilesize = (int)$size;
83
+ return $this;
84
+ }
85
+
86
+ /**
87
+ * Set max row
88
+ *
89
+ * @param int $maxRow
90
+ * @return EmailVision_Api_BatchMemberService
91
+ */
92
+ public function setMaxRow($maxRow)
93
+ {
94
+ $this->_maxRow = (int)$maxRow;
95
+ return $this;
96
+ }
97
+
98
+ /**
99
+ * Get allowed max file size in bytes
100
+ *
101
+ * @return int
102
+ */
103
+ public function getMaxFileSize()
104
+ {
105
+ if (!$this->_maxFilesize) {
106
+ $this->_maxFilesize = self::MAX_FILESIZE;
107
+ }
108
+ return $this->_maxFilesize;
109
+ }
110
+
111
+ /**
112
+ * Get allowed max row
113
+ *
114
+ * @return int
115
+ */
116
+ public function getMaxRow()
117
+ {
118
+ if (!$this->_maxRow) {
119
+ $this->_maxRow = self::MAX_ROW;
120
+ }
121
+ return $this->_maxRow;
122
+ }
123
+
124
  /**
125
  * Create csv files for a given list of members
126
  * - you need
191
  $rowCount++;
192
  $listMember[] = $id;
193
 
194
+ // If file size approaches max uploadable, close file and set a new one on next turn
195
  if (
196
+ $fileSizeInBytes > $this->getMaxFileSize()
197
  || --$totalMemberCount == 0
198
+ || $rowCount >= $this->getMaxRow()
199
  ) {
200
  fclose($fileHandler);
201
  $fileHandler = null;
lib/EmailVision/Api/NotificationService.php CHANGED
@@ -38,14 +38,14 @@ class EmailVision_Api_NotificationService extends EmailVision_Api_Common
38
  const CURLE_OPERATION_TIMEDOUT = 28;
39
 
40
  /**
41
- * Connection time out for rest service - The number of seconds to wait while trying to connect.
42
  */
43
- const REST_CONNECTION_TIME = 1;
44
 
45
  /**
46
  * Time out for rest service - The maximum number of seconds to allow cURL functions to execute.
47
  */
48
- const REST_TIME_OUT = 2;
49
 
50
  /**
51
  * Convert an array of mapping into an array understandable by the webservice method sendObject
38
  const CURLE_OPERATION_TIMEDOUT = 28;
39
 
40
  /**
41
+ * Connection time out for rest service - The maximum number of seconds to wait while trying to connect.
42
  */
43
+ const REST_CONNECTION_TIME = 2;
44
 
45
  /**
46
  * Time out for rest service - The maximum number of seconds to allow cURL functions to execute.
47
  */
48
+ const REST_TIME_OUT = 3;
49
 
50
  /**
51
  * Convert an array of mapping into an array understandable by the webservice method sendObject
lib/EmailVision/Tools/File/Csv.php CHANGED
@@ -120,7 +120,10 @@ class EmailVision_Tools_File_Csv
120
  public function fputcsv(&$handle, $fields = array(), $delimiter = ',', $enclosure = '"') {
121
  $str = '';
122
  $escapeChar = '\\';
 
123
  foreach ($fields as $value) {
 
 
124
  if (
125
  strpos($value, $delimiter) !== false
126
  || strpos($value, $enclosure) !== false
@@ -132,7 +135,7 @@ class EmailVision_Tools_File_Csv
132
  $str2 = $enclosure;
133
  $escaped = 0;
134
  $len = strlen($value);
135
- for ($i=0;$i<$len;$i++) {
136
  if ($value[$i] == $escapeChar) {
137
  $escaped = 1;
138
  } else if (!$escaped && $value[$i] == $enclosure) {
120
  public function fputcsv(&$handle, $fields = array(), $delimiter = ',', $enclosure = '"') {
121
  $str = '';
122
  $escapeChar = '\\';
123
+
124
  foreach ($fields as $value) {
125
+ // remove new line character by space
126
+ $value = preg_replace("/[\r\n]+/", ' ', $value);
127
  if (
128
  strpos($value, $delimiter) !== false
129
  || strpos($value, $enclosure) !== false
135
  $str2 = $enclosure;
136
  $escaped = 0;
137
  $len = strlen($value);
138
+ for ($i=0; $i<$len; $i++) {
139
  if ($value[$i] == $escapeChar) {
140
  $escaped = 1;
141
  } else if (!$escaped && $value[$i] == $enclosure) {
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Campaign_Commander_Transactional_Email_1_5</name>
4
- <version>3.0.1</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.opensource.org/licenses/academic.php">Academic Free License (AFL)</license>
7
  <channel>community</channel>
@@ -19,15 +19,55 @@
19
  &#xD;
20
  3. Synchronize data for a complete view of the customer&#xD;
21
  * Automatically sychronize your Magento customer data with your SmartFocus marketing database</description>
22
- <notes>* New SmartFocus menus&#xD;
 
 
 
23
  &#xD;
24
- * New API implementation&#xD;
25
- &#xD;
26
- * New features enhance email sending, abandoned cart reminders, and data synchronization</notes>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
27
  <authors><author><name>SmartFocus</name><user>itgemailvision</user><email>EMVIntegrationsDevelopment@smartfocus.com</email></author></authors>
28
- <date>2014-02-05</date>
29
- <time>10:57:08</time>
30
- <contents><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><file name="campaign-commander.css" hash="7a48c4846463a3710661d4e19a36f150"/></dir></dir></dir></target><target name="magelib"><dir name="EmailVision"><dir name="Api"><file name="BatchMemberService.php" hash="48443e2dd252c3f089b7f0870316f503"/><file name="Common.php" hash="aa50e6fab781d0431aece5ea77630f8b"/><file name="Exception.php" hash="fbe812474106cb6a694e2ec21d304d7b"/><file name="MemberService.php" hash="f3dc742201351e99b3eedfd06a0b9a9d"/><file name="NotificationService.php" hash="1445b72b496d61528302f12d12bd8fe2"/><file name="TransactionalService.php" hash="7aa5530026dbc8f3972b4ef543cef348"/></dir><file name="SoapClient.php" hash="a764db42192da691ab8d01aceb4d3e8d"/><dir name="Tools"><dir name="File"><file name="Csv.php" hash="4fd8516f3b80ed60a8a919d217f2e8d3"/></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><dir name="emailvision"><dir name="abandonment"><file name="template1.html" hash="3eda1598c50876324609c0d634526624"/><file name="template2.html" hash="3eda1598c50876324609c0d634526624"/><file name="template3.html" hash="3eda1598c50876324609c0d634526624"/></dir><dir name="datasync"><file name="cron_errors.html" hash="bbf6122128d85d2291fd291d4096b6b2"/></dir></dir></dir></dir><file name="Emv_CartAlert.csv" hash="9fc25be18876d260c0b8e56735f14713"/><file name="Emv_Core.csv" hash="33f26cf37e6ca8c3c73a0a3b82bc2d13"/><file name="Emv_DataSync.csv" hash="94d468f0f3924e7713aa8be5939094c6"/><file name="Emv_Emt.csv" hash="f1a0246d49a5a3beaba3b8033785ba99"/><file name="Emv_Report.csv" hash="5f25d083b33cd20697ac1190e626782a"/></dir><dir name="fr_FR"><file name="Emv_CartAlert.csv" hash="0acb2fa39d9199c8f31849beea6b782a"/><file name="Emv_Core.csv" hash="e73b4ad1ee7853d7fb8f949c2e295906"/><file name="Emv_DataSync.csv" hash="d5d443e8511ca960e938cf92716d3f7e"/><file name="Emv_Emt.csv" hash="490f8bf088b342b2047e723ce95f7c6a"/><file name="Emv_Report.csv" hash="f586e64852651a4524b7f27eb2c3cd6a"/></dir></target><target name="mageetc"><dir name="modules"><file name="Emv_CartAlert.xml" hash="7c23ed23c48254c30e4aad7c11db1b62"/><file name="Emv_Core.xml" hash="e25dd0ea40fad09e0d1f6260f46e65ac"/><file name="Emv_DataSync.xml" hash="089e2b362da3cb466e1ba2dc79e63289"/><file name="Emv_Emt.xml" hash="d1e26edb25bce0b78e6c14792c07ac03"/><file name="Emv_Report.xml" hash="b41b407bbd282fc33e0bf6970082a08b"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="emailvision"><file name="abandonment_report.xml" hash="f60cff6610a8ea2756b9ae4139688a1d"/></dir></dir><dir name="template"><dir name="emailvision"><dir name="abandonment"><dir name="grid"><file name="container.phtml" hash="3375ac98f71cab4a81bb59ef64b3d6fc"/></dir></dir><dir name="account"><file name="associated_urls.phtml" hash="b0f41cede2009e3728c819403cb28426"/></dir><dir name="datasync"><dir name="system"><dir name="config"><dir name="form"><dir name="field"><file name="array.phtml" hash="e809c2a4c2aecc27f5ec3f51faed3c0a"/></dir></dir><file name="getfields.phtml" hash="e5680827bf0c2955b252d0f711dc90e8"/></dir></dir></dir><dir name="emt"><dir name="template"><file name="common_js.phtml" hash="b91b877122f3d48728c5c97423c3eb42"/><file name="edit.phtml" hash="f09b248f3187d2f83c90765ad17b7413"/><file name="mapped_attributes.phtml" hash="be2ea5d80b24ad044e351607aa76932e"/></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><dir name="emailvision"><file name="abandonment.xml" hash="c6f5b8cf0aec8cd0ac881b58167ff234"/></dir></dir><dir name="template"><dir name="emailvision"><dir name="abandonment"><file name="customer.phtml" hash="d63198ab64858039aa5b23f9964dd6d3"/><dir name="reminder"><file name="items.phtml" hash="c2e0211ac4c28d81c14199ecb7450a79"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magecommunity"><dir name="Emv"><dir name="CartAlert"><dir name="Block"><dir name="Cart"><file name="Items.php" hash="a6a99b56060cb4254a384e5c4eaef467"/></dir><dir name="Customer"><file name="Abandonment.php" hash="06dd3435302590f774d29271cea4d76e"/></dir></dir><file name="Constants.php" hash="b10c0a770bf2075a30408b54dc4b9824"/><dir name="Helper"><file name="Data.php" hash="25185f79349a728a0ce684829c59e720"/></dir><dir name="Model"><file name="Abandonment.php" hash="ac7111c71d744dfc9713ae2894b41cc8"/><dir name="Mysql4"><dir name="Abandonment"><file name="Collection.php" hash="4f06a6c5528ff4d067dd963bab96fca2"/></dir><file name="Abandonment.php" hash="ef528abb65db08c6bed6f99cbe0947ca"/><dir name="Orderflag"><file name="Collection.php" hash="3fc55bad9566113db73b6e7632af4ec7"/></dir><file name="Orderflag.php" hash="5163bd389466708b84001fbeb85af913"/><dir name="Stats"><file name="Collection.php" hash="24178657849cf0bdffd939816f3c8ba9"/></dir><file name="Stats.php" hash="a54399b037a210a719abba376b0415bc"/></dir><file name="Observer.php" hash="768f5503d719f58c885c6ac7a202cb93"/><file name="Orderflag.php" hash="5a6e33fce2512ba3f4ee93e90fc6f4e8"/><dir name="Resource"><file name="Setup.php" hash="0724e1d2ed5fd1b5ef93a2a267a4ee21"/></dir><file name="Stats.php" hash="33e9f3578d961cd3db55ade1df61ef7b"/></dir><dir name="controllers"><file name="CustomerController.php" hash="5c042b38b1a0dedd46cb7403ea9371cb"/><file name="GuestController.php" hash="8fa642676dc3fc057c44d1d870ff1f37"/></dir><dir name="etc"><file name="adminhtml.xml" hash="c28a61bac9988480fb403007daba54ee"/><file name="config.xml" hash="874654c8b45830a2adf94d96b9311c04"/><file name="system.xml" hash="3fa7067de36957004c16bb753058af65"/></dir><dir name="sql"><dir name="abandonment_setup"><file name="mysql4-install-0.1.0.php" hash="ee9bc7cabf23bec2867ee1394562ce27"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="d77033018e89d437a229ef462c786f97"/><file name="mysql4-upgrade-0.2.0-0.3.0.php" hash="3ad1df3e579e6a5d1c18aa09f764937b"/><file name="mysql4-upgrade-0.3.0-0.4.0.php" hash="b2c7e93739a101f6f844db6f3548b080"/><file name="mysql4-upgrade-0.4.0-0.5.0.php" hash="7403b4f3b3edcc8665e85f3571abb58f"/><file name="mysql4-upgrade-0.5.0-0.5.1.php" hash="c893dd6a2b0d2304204dabf0659cc75c"/><file name="mysql4-upgrade-0.5.1-0.5.2.php" hash="35d81990131a6e9cd0bec82eeb8cbe68"/></dir></dir></dir><dir name="Core"><dir name="Block"><dir name="Adminhtml"><dir name="Account"><dir name="Edit"><file name="AssociatedUrls.php" hash="4879c49496102f0f152f589249817fad"/><file name="Form.php" hash="64420bd3f05f502d84673aaf6fa0f1e9"/></dir><file name="Edit.php" hash="7817ac5fbe3d641c6e4bd49ea1a4cc45"/><file name="Grid.php" hash="d7d869a26decc54beb2fbc9574c10b00"/></dir><file name="Accounts.php" hash="078f85d162665246cf6d475b4c6cbc16"/></dir></dir><dir name="Helper"><file name="Data.php" hash="f493849c2a6261c3a232f489caba8b44"/></dir><dir name="Model"><file name="Account.php" hash="0ca3e88df84a27c8986c0836c9d39b74"/><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Account"><file name="Abstract.php" hash="d2b7f88918b2034284ce7ae042133229"/></dir><file name="Enabled.php" hash="b5b9c77a30d98097777dac3434d381b3"/></dir></dir></dir></dir><dir name="Mysql4"><dir name="Account"><file name="Collection.php" hash="f9dbdbb023051a3e412be801e7c1d5ec"/></dir><file name="Account.php" hash="b7949c5e00cb29efe2b067087933c6a4"/></dir><dir name="Resource"><file name="Setup.php" hash="1aed96e7fe8c8cb06b27b5ef56f8822f"/></dir><dir name="Service"><file name="Abstract.php" hash="6dca2afd30b6f2f3c23234663da6335f"/><file name="BatchMember.php" hash="b6cc28b33e169b40ddbb37b093cf13a1"/><file name="Member.php" hash="b46d65f710d9dbee42e8f805006b65b8"/><file name="Notification.php" hash="fd131bf3071e3b7b0614036ca3f76c63"/><file name="Transactional.php" hash="b16beffebe860b071110013b3d3d0571"/></dir><dir name="System"><dir name="Config"><dir name="Source"><file name="Account.php" hash="8e5ce5e669d481188c7e13cfee510697"/></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AccountController.php" hash="545158a529f9b3ac17d5ab02fee354e3"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="e8f219eefa333cc503c48b0c1586d403"/><file name="config.xml" hash="cbd11a1571fb5b72185ab1a00c2cd7fd"/><file name="system.xml" hash="85d9908f748a15c6247582418a1b606c"/></dir><dir name="sql"><dir name="emvcore_setup"><file name="mysql4-install-0.1.0.php" hash="b1319057a975d8dd2c829d6c00affc74"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="af4506f20cd8cdfa11c0394fdd78a06c"/></dir></dir></dir><dir name="DataSync"><dir name="Block"><dir name="Adminhtml"><dir name="Form"><dir name="Field"><file name="CustomerAttributes.php" hash="c6add4119550dae8a1d3db4e5bca9683"/><file name="EmailVisionFields.php" hash="67d9bb70184bd844cba669d4ac5c04ed"/></dir></dir><dir name="System"><dir name="Config"><file name="CustomerAttributes.php" hash="7508f9dc0df62e5c9faf9accd3361765"/><file name="Date.php" hash="1790331bd1bb06a441737ecf345df6da"/><file name="GetFields.php" hash="75291de3c2c5e0338e8c6069066264f5"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="7e3b1646ab8b9330f5585cf0a57661fb"/><file name="Service.php" hash="8f459e115ba5d2fbeba937852189e28b"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><dir name="ApiMember"><file name="Account.php" hash="09cfe4b6651eae737945ab16b25ce6bb"/><file name="Cron.php" hash="1e7a38db39c21d04b0249ec181c1993f"/><file name="Enabled.php" hash="19e91d89fa6a098010ea4d9582b72451"/></dir><dir name="BatchMember"><file name="Account.php" hash="844f3af6efd125d6b1d9ef8808984e79"/><file name="Cron.php" hash="572c1d835574039a9287da6760b7111d"/><file name="Enabled.php" hash="b00cce598c212933cc2fe1db4cc4d4b4"/></dir><dir name="Clean"><file name="Cron.php" hash="1e55644bb34417d3285bf9bca0aee646"/></dir></dir><dir name="Source"><file name="Fields.php" hash="5f469c279ddabaa6f1142616e6106089"/><file name="MemberCronTime.php" hash="0ed64e65649d2f8b783fcf2fb19f49f8"/></dir></dir></dir></dir><file name="Cron.php" hash="52bcf45cdad1c6d89f64ef242a5b085b"/><file name="Observer.php" hash="30d2a4ece7ebcf68ef04aa2caa74076c"/><dir name="Service"><file name="BatchMember.php" hash="de66836efdf1a913ce285f979c2930e7"/><file name="Member.php" hash="28176c130e55ee07fb93ece9c918c0af"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DataSyncController.php" hash="c4e46f74ea35132f564587c798cc88cc"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="0d0ba154e5cf38895a2b2b0d907797fb"/><file name="config.xml" hash="331af61703669c4c1dca3c93899c6602"/><file name="system.xml" hash="4d5cf9fe165760476ccb273ea5693f26"/></dir><dir name="sql"><dir name="emvdatasync_setup"><file name="mysql4-install-0.0.1.php" hash="073ecf5a0c8aae1572e3ac91a35633ff"/></dir></dir></dir><dir name="Emt"><dir name="Block"><dir name="Adminhtml"><dir name="Log"><dir name="Grid"><dir name="Renderer"><file name="GetError.php" hash="a7fb7e3075e611b0e5b672d0ecee3ddd"/></dir></dir><file name="Grid.php" hash="82ca5fdaeb5403c0a39fe1b17e0d9958"/></dir><file name="Log.php" hash="24551f106915450e8e775b2bb1324451"/><dir name="Resending"><file name="Grid.php" hash="f56672b844f848df3414668ffa2855c5"/></dir><file name="Resending.php" hash="beaad1da5f136d403f8881e21dc9639e"/><dir name="Template"><dir name="Edit"><dir name="Tab"><file name="EmvContent.php" hash="a540805b70ec00fc6b5cdcc32b1a1cfb"/><file name="EmvDyn.php" hash="2c3f5c8f739691b3eeb6d53de6b64e46"/><file name="General.php" hash="776675c177b6a147fd90c5c6d8a3e601"/></dir><file name="Tabs.php" hash="320b4c3e740ba5aacbbd5c602ffb041c"/></dir><file name="Edit.php" hash="5c672e813e76cf81755c80f54c78ea13"/><dir name="Grid"><dir name="Renderer"><file name="Emvname.php" hash="1cf0f98ad194b33c4d9c91f0195c8146"/><file name="MageTemplate.php" hash="e284d93be818c24016bd462e31c226ee"/></dir></dir><file name="Grid.php" hash="19ab59d96e2925d6fe2b14aad3111498"/></dir><file name="Templates.php" hash="12bcab5abc0be49e4e04b0d92eecf61c"/></dir></dir><dir name="Helper"><file name="Data.php" hash="067567bd92ed2d9c5ccd0c2f2d7d8cd2"/><file name="Emvtemplate.php" hash="97463f51b60d133d30d0e3655486b9d0"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><file name="Account.php" hash="301e5056ac13f4d00ba5c047a6eb79a8"/></dir></dir></dir></dir><file name="Attribute.php" hash="b0c369fcc0bc47f48ba7c5866dc72260"/><file name="Cron.php" hash="c5cec405088a1b951d2767309adf3461"/><file name="Emt.php" hash="45ca86eb4dfa46ce78a53f9f66d79bb2"/><file name="Log.php" hash="16a2e7e2bd1039f39a66d9fb61a324e9"/><dir name="Mage"><dir name="Core"><dir name="Email"><file name="Template.php" hash="e5c31cf93c5b2aa0b88e8176463f5a77"/></dir></dir></dir><file name="MageTemplate.php" hash="ddf98c89b163c6e59ceed1ac5dbe8f69"/><file name="Mailmode.php" hash="e08c76d5d72b21d3bd8b6b441ec06527"/><dir name="Mysql4"><dir name="Attribute"><file name="Collection.php" hash="3e3308be1178e99162606a668eace8ed"/></dir><file name="Attribute.php" hash="bd2854ed8ee4fb207b994543a0ecf9ba"/><dir name="Emt"><file name="Collection.php" hash="bbc3368b7276bbff83c1770b6a097c26"/></dir><file name="Emt.php" hash="7fd5ff6b090587b56ac09366289b369f"/><dir name="Log"><file name="Collection.php" hash="dc04e8d73fa3df064453f7c7ee12a400"/></dir><file name="Log.php" hash="f379a53b42152472dded21708572bce8"/><dir name="Resending"><dir name="Queue"><dir name="Message"><file name="Collection.php" hash="8b165985970886c74aef0c9d62140098"/></dir><file name="Message.php" hash="63b4e07ee46f64d7f1c8284f5f789f71"/></dir></dir></dir><dir name="Resending"><dir name="Queue"><file name="Message.php" hash="4830bc5ef750efcd8973ee46f424ec51"/></dir><file name="Queue.php" hash="bb2128bf1a9ecd5cf9fb8d06f8de845b"/><file name="Rule.php" hash="3accdc868f171f3a328e41658871e31c"/></dir><dir name="Resource"><file name="Setup.php" hash="b5fc87772ed86c16c54eb9262dd291a3"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="LogController.php" hash="05fbabe704020cddc12a8656cc9220bd"/><file name="RescheduleController.php" hash="5331244d0bb14e448fbde3b797fb680d"/><file name="TemplateController.php" hash="71c335b0d6455bc51ba9f9e45d7639a4"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="193ed52e7bc6f002b4526d697166c84d"/><file name="config.xml" hash="f6fed0b59662a2b43b9271d9d3a9a046"/><file name="system.xml" hash="a6293b65fc0e398db437e443a992c3cc"/></dir><dir name="sql"><dir name="emvemt_setup"><file name="mysql4-install-0.1.0.php" hash="a7d12df049f2c1377a072fa7899dcb6c"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="3b52221a751b221ae98e16a03807335a"/><file name="mysql4-upgrade-0.2.0-0.3.0.php" hash="0108cecb8c995004987e869fc008bf34"/><file name="mysql4-upgrade-0.3.0-0.4.0.php" hash="7ef46dc220aeb7265ef43cab5b17156f"/><file name="mysql4-upgrade-0.4.0-0.4.1.php" hash="a6eb1e85d8773af9c0935bacabcc06dd"/></dir></dir></dir><dir name="Report"><dir name="Block"><dir name="Adminhtml"><dir name="Conversion"><file name="Form.php" hash="9c537aa62d666816058130d257f75bb8"/></dir><file name="Conversion.php" hash="79959891324dcc99448d93f9cfa01724"/><dir name="Details"><file name="Grid.php" hash="beb3a98688d554cb8d49aa5a8613bd5a"/></dir><file name="Details.php" hash="a765998cb0a765423f89cd652a2d1dab"/></dir></dir><dir name="Helper"><file name="Data.php" hash="14fd1c74a2de74a85190394166c1e684"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ConversionController.php" hash="638f3ad969d3bc9fcec2f8e7b5c14854"/><file name="DetailsController.php" hash="653096279fbe200d6b5ac6208efe732a"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="973a0f60081aba81dc048f7a67963954"/><file name="config.xml" hash="f5a9c3e32da692808072c07be851a7de"/></dir></dir></dir><dir name="Mage"><dir name="SalesRule"><dir name="Helper"><file name="Coupon.php" hash="05d42b935bd31dad39c9e31052ef60c8"/></dir><dir name="Model"><dir name="Coupon"><file name="Massgenerator.php" hash="c5312f2a745bf79d2a8ac90c23fb79dc"/></dir><dir name="System"><dir name="Config"><dir name="Source"><dir name="Coupon"><file name="Format.php" hash="64236cb46364219d4a5702521898a249"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
31
  <compatible/>
32
  <dependencies><required><php><min>5.2.6</min><max>5.5.4</max></php></required></dependencies>
33
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>Campaign_Commander_Transactional_Email_1_5</name>
4
+ <version>3.1.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.opensource.org/licenses/academic.php">Academic Free License (AFL)</license>
7
  <channel>community</channel>
19
  &#xD;
20
  3. Synchronize data for a complete view of the customer&#xD;
21
  * Automatically sychronize your Magento customer data with your SmartFocus marketing database</description>
22
+ <notes>General Enhancement :&#xD;
23
+ * A list of the status of prerequisites and extensions is now available in the SmartFocus menu of the System Configuration section.&#xD;
24
+ * Cron jobs can now be configured to run on specific days of the week or on a specific day of the month.&#xD;
25
+ * The cron job processes scheduled in the Magento Connector can now be restarted even if a previous cron job process encountered an error and did not close. &#xD;
26
  &#xD;
27
+ Data Synchronization : &#xD;
28
+ * Data synchronization can now be configured to synchronize based on member email addresses.&#xD;
29
+ * The data synchronization process now runs faster than in previous versions of the Magento Connector.&#xD;
30
+ * You can now configure data synchronization for different stores with different SmartFocus accounts.&#xD;
31
+ * In the Mapping feature:&#xD;
32
+ ** fields have been arranged into different categories,&#xD;
33
+ ** the following new fields for Calculated Purchase Information category have been added:&#xD;
34
+ Used Email Addresses&#xD;
35
+ Base Currency Code&#xD;
36
+ List of Order #&#xD;
37
+ Total Orders Purchased&#xD;
38
+ Total Items Purchased&#xD;
39
+ Average Items Purchased per Order&#xD;
40
+ Total Order Amount Spent&#xD;
41
+ Average Order Amount Spent per Purchase&#xD;
42
+ Total Discount Amount&#xD;
43
+ Average Discount Amount per Purchase&#xD;
44
+ Total Shipping Amount&#xD;
45
+ Average Shipping Amount per Purchase&#xD;
46
+ Minimum Purchase Total&#xD;
47
+ Maximum Purchase Total&#xD;
48
+ First Purchase&#xD;
49
+ Last Purchase&#xD;
50
+ Minimum Items Purchased&#xD;
51
+ Maximum Items Purchased&#xD;
52
+ Shipping Methods&#xD;
53
+ Payment Methods&#xD;
54
+ Used Coupons&#xD;
55
+ Total Purchases With Discount &#xD;
56
+ * The menu Data Process List has been added to the Magento Connector, allowing you to monitor the progress of your scheduled synchronizations at a glance. &#xD;
57
+ &#xD;
58
+ Transactional Emails &#xD;
59
+ * You can now verify that your SmartFocus account is compatible with the Magento Connector in the Transactional Messages (NMP) menu and configure your account if you have modified the credentials for your account.&#xD;
60
+ * A log clean-up process has been created. &#xD;
61
+ &#xD;
62
+ &#xD;
63
+ Abandoned Carts Feature&#xD;
64
+ * You can now process more than 8,000 abandoned carts simultaneously.&#xD;
65
+ * You can now enable the test mode to send abandoned cart reminders in minutes rather than hours, and configure how long the cart will be able to receive reminders in hours.&#xD;
66
+ * In the new menu 'List in the Abandoned Cart menu, you can access the list of abandoned cart reminder information. </notes>
67
  <authors><author><name>SmartFocus</name><user>itgemailvision</user><email>EMVIntegrationsDevelopment@smartfocus.com</email></author></authors>
68
+ <date>2014-06-09</date>
69
+ <time>09:10:14</time>
70
+ <contents><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><file name="campaign-commander.css" hash=""/><file name="smartfocus.css" hash="a01e61afdefd15460460cc2b4c0d256a"/><dir name="images"><dir name="smartfocus"><file name="tick.png" hash="9fb629c79fc4a487088ac4aeeb23e40b"/><file name="untick.gif" hash="017f884ab4a0fe9292b264bd0e219aa9"/><file name="warning.png" hash="aa8b5badc048b2e7111c8ec4bfcf7483"/></dir></dir></dir></dir></dir></target><target name="magelib"><dir name="EmailVision"><dir name="Api"><file name="BatchMemberService.php" hash="3aca1b0b9d1a7cb45a2063a33129d5d5"/><file name="Common.php" hash="aa50e6fab781d0431aece5ea77630f8b"/><file name="Exception.php" hash="fbe812474106cb6a694e2ec21d304d7b"/><file name="MemberService.php" hash="f3dc742201351e99b3eedfd06a0b9a9d"/><file name="NotificationService.php" hash="d5bd7b97e7272a015ceb0fffd9316fc1"/><file name="TransactionalService.php" hash="7aa5530026dbc8f3972b4ef543cef348"/></dir><file name="SoapClient.php" hash="a764db42192da691ab8d01aceb4d3e8d"/><dir name="Tools"><dir name="File"><file name="Csv.php" hash="843067dfbf1c5269661b02ec7b6b29de"/></dir></dir></dir></target><target name="magelocale"><dir name="en_US"><dir name="template"><dir name="email"><dir name="smartfocus"><dir name="abandonment"><file name="template1.html" hash="3eda1598c50876324609c0d634526624"/><file name="template2.html" hash="3eda1598c50876324609c0d634526624"/><file name="template3.html" hash="3eda1598c50876324609c0d634526624"/></dir><dir name="datasync"><file name="cron_errors.html" hash="f480c390cc733b7e0fd76198358a8af4"/></dir></dir></dir></dir><file name="Emv_CartAlert.csv" hash="cd92c0dac35ff9a37c5658c159ad9ad1"/><file name="Emv_Core.csv" hash="19398a647210dbadb44f1bab5120b1d5"/><file name="Emv_DataSync.csv" hash="e20d8614368bdb0f97935632ecfc2cea"/><file name="Emv_Emt.csv" hash="ea0dae37802a0ef00f92b77a2e033a50"/><file name="Emv_Report.csv" hash="5f25d083b33cd20697ac1190e626782a"/></dir><dir name="fr_FR"><file name="Emv_CartAlert.csv" hash="5d7c80d74dfc1f444c3c7a3e5c59dc04"/><file name="Emv_Core.csv" hash="6427a15fe17908c9fda4c2f643ccd8a8"/><file name="Emv_DataSync.csv" hash="48d852a65fa6835787b10f341fc6f853"/><file name="Emv_Emt.csv" hash="24ccd134f052439239a3688aaa41f219"/><file name="Emv_Report.csv" hash="5728ce4bb676a9351d0922ff9843dc4c"/></dir></target><target name="mageetc"><dir name="modules"><file name="Emv_CartAlert.xml" hash="7c23ed23c48254c30e4aad7c11db1b62"/><file name="Emv_Core.xml" hash="e25dd0ea40fad09e0d1f6260f46e65ac"/><file name="Emv_DataSync.xml" hash="089e2b362da3cb466e1ba2dc79e63289"/><file name="Emv_Emt.xml" hash="d1e26edb25bce0b78e6c14792c07ac03"/><file name="Emv_Report.xml" hash="b41b407bbd282fc33e0bf6970082a08b"/></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="smartfocus"><file name="abandonment_report.xml" hash="4a0422b60e5c5402bd84f78fd038d6fe"/><file name="core.xml" hash="e167045d8ae09689cfcb8235970dbc2a"/></dir></dir><dir name="template"><dir name="smartfocus"><dir name="abandonment"><dir name="grid"><file name="container.phtml" hash="3375ac98f71cab4a81bb59ef64b3d6fc"/></dir></dir><dir name="account"><file name="associated_urls.phtml" hash="b0f41cede2009e3728c819403cb28426"/></dir><dir name="cartalert"><dir name="system"><dir name="config"><file name="promo_rule.phtml" hash="f3951f3e4e4142743f68bef73a3a00bf"/></dir></dir></dir><dir name="config"><file name="extension_status.phtml" hash="968f83f3cddc81582b2214049cdb5d76"/></dir><dir name="datasync"><dir name="system"><dir name="config"><dir name="form"><dir name="field"><file name="array.phtml" hash="e809c2a4c2aecc27f5ec3f51faed3c0a"/></dir></dir><file name="getfields.phtml" hash="3eb4952d74ec7fcf688324b0075b5b97"/></dir></dir></dir><dir name="emt"><dir name="system"><dir name="config"><file name="account_validation.phtml" hash="8c978f3afe3ed3a0ee4d4cffb1106449"/></dir></dir><dir name="template"><file name="common_js.phtml" hash="b91b877122f3d48728c5c97423c3eb42"/><file name="edit.phtml" hash="f09b248f3187d2f83c90765ad17b7413"/><file name="mapped_attributes.phtml" hash="be2ea5d80b24ad044e351607aa76932e"/></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><dir name="smartfocus"><file name="abandonment.xml" hash="b455deed2daab8c61fdeb9efdd339ce3"/></dir></dir><dir name="template"><dir name="smartfocus"><dir name="abandonment"><file name="customer.phtml" hash="d63198ab64858039aa5b23f9964dd6d3"/><dir name="reminder"><file name="items.phtml" hash="9139b91b3741db43aa60020e3764d0a7"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magecommunity"><dir name="Emv"><file name="CHANGELOG" hash="091cadf2668aa522c5b01e230cb191b4"/><dir name="CartAlert"><dir name="Block"><dir name="Adminhtml"><dir name="List"><dir name="Grid"><dir name="Column"><dir name="Renderer"><file name="Currency.php" hash="cdca5ab59c34296803dbca2d60a22860"/></dir></dir></dir><file name="Grid.php" hash="797337ce3b749215540eeb9950daca02"/></dir><file name="List.php" hash="e3c1cc7e8602c882d9cd116df6e411a7"/><dir name="Quote"><file name="Grid.php" hash="693103ebe4a66130c54d23900b7fd091"/></dir><file name="Quote.php" hash="7fc83c25075b054bdd100ef6bdbdf61a"/><dir name="System"><dir name="Config"><file name="PromoRule.php" hash="f8aa6fc6087cde870648082f1dfce95f"/></dir></dir></dir><dir name="Cart"><file name="Items.php" hash="2cc9a9938786d5cecf96c7420bf8e67c"/></dir><dir name="Customer"><file name="Abandonment.php" hash="06dd3435302590f774d29271cea4d76e"/></dir></dir><file name="Constants.php" hash="2ab5ea9260640bed0fedfb8ba5d5e07b"/><dir name="Helper"><file name="Data.php" hash="de6ddbe68f2d54a96154628ed6f1521c"/></dir><dir name="Model"><file name="Abandonment.php" hash="ac7111c71d744dfc9713ae2894b41cc8"/><dir name="Mysql4"><dir name="Abandonment"><file name="Collection.php" hash="4f06a6c5528ff4d067dd963bab96fca2"/></dir><file name="Abandonment.php" hash="ef528abb65db08c6bed6f99cbe0947ca"/><dir name="Orderflag"><file name="Collection.php" hash="3fc55bad9566113db73b6e7632af4ec7"/></dir><file name="Orderflag.php" hash="5163bd389466708b84001fbeb85af913"/><dir name="Stats"><file name="Collection.php" hash="24178657849cf0bdffd939816f3c8ba9"/></dir><file name="Stats.php" hash="a54399b037a210a719abba376b0415bc"/></dir><file name="Observer.php" hash="3b3c7564754b4988c7131c747f628022"/><file name="Orderflag.php" hash="5a6e33fce2512ba3f4ee93e90fc6f4e8"/><dir name="Resource"><file name="Setup.php" hash="0724e1d2ed5fd1b5ef93a2a267a4ee21"/></dir><file name="Stats.php" hash="33e9f3578d961cd3db55ade1df61ef7b"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="AbandonmentController.php" hash="6901bbc8ae461ee6cb884df01ef9f467"/></dir><file name="CustomerController.php" hash="5c042b38b1a0dedd46cb7403ea9371cb"/><file name="GuestController.php" hash="8fa642676dc3fc057c44d1d870ff1f37"/></dir><dir name="etc"><file name="adminhtml.xml" hash="2e56a9df99da4eea8e587e3d7694fde8"/><file name="config.xml" hash="9eced8b4ba1b86e58963330fc3a3407c"/><file name="system.xml" hash="67f22e901da002039f599570aeda1d74"/></dir><dir name="sql"><dir name="abandonment_setup"><file name="mysql4-install-0.1.0.php" hash="ee9bc7cabf23bec2867ee1394562ce27"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="d77033018e89d437a229ef462c786f97"/><file name="mysql4-upgrade-0.2.0-0.3.0.php" hash="3ad1df3e579e6a5d1c18aa09f764937b"/><file name="mysql4-upgrade-0.3.0-0.4.0.php" hash="b2c7e93739a101f6f844db6f3548b080"/><file name="mysql4-upgrade-0.4.0-0.5.0.php" hash="7403b4f3b3edcc8665e85f3571abb58f"/><file name="mysql4-upgrade-0.5.0-0.5.1.php" hash="c893dd6a2b0d2304204dabf0659cc75c"/><file name="mysql4-upgrade-0.5.1-0.5.2.php" hash="35d81990131a6e9cd0bec82eeb8cbe68"/><file name="mysql4-upgrade-0.5.2-0.5.3.php" hash="d2e1816a3165241e61142506425a24b5"/><file name="mysql4-upgrade-0.5.3-0.5.4.php" hash="f43b364613d900c6d14ada3e41d1acc6"/></dir></dir></dir><dir name="Core"><dir name="Block"><dir name="Adminhtml"><dir name="Account"><dir name="Edit"><file name="AssociatedUrls.php" hash="648a706a7434c01d5206b1cace7d7afa"/><file name="Form.php" hash="64420bd3f05f502d84673aaf6fa0f1e9"/></dir><file name="Edit.php" hash="7817ac5fbe3d641c6e4bd49ea1a4cc45"/><file name="Grid.php" hash="d7d869a26decc54beb2fbc9574c10b00"/></dir><file name="Accounts.php" hash="078f85d162665246cf6d475b4c6cbc16"/><dir name="Config"><file name="ExtensionStatus.php" hash="6bb415f6c5615db0e02ad1e64f6745dd"/></dir><dir name="DataProcessing"><dir name="Process"><dir name="Grid"><dir name="Column"><dir name="Renderer"><file name="Links.php" hash="3bf7651e1898d36a3e39abde0dfb7a6d"/><file name="Output.php" hash="d3053e0ac56aac200e49f453ce7f403a"/></dir></dir></dir><file name="Grid.php" hash="f4cff586e899709902f9e26aff0520fb"/></dir><file name="Process.php" hash="3c5053cd7a0eef6ad6fd2e2d78f3fc07"/></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="aadeed8ac77c3430c9d982568c375803"/></dir><dir name="Model"><file name="Account.php" hash="1d8f3e158c0622caba50131886d7f771"/><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><dir name="Account"><file name="Abstract.php" hash="9d92fbd42157a62472a145c88bb032a0"/></dir><file name="Cron.php" hash="b34d3ace2db9784cc27e8efd4a483c38"/><file name="Enabled.php" hash="b5b9c77a30d98097777dac3434d381b3"/></dir><dir name="Source"><file name="Account.php" hash="46dbc9d51348e04cc5a052c97af0328c"/><file name="CronDate.php" hash="95205d5ebe42cff980390646ad072d8a"/><file name="CronDay.php" hash="604b0e9c32a03fdba91a2ed09747fb24"/></dir></dir></dir></dir><dir name="DataProcessing"><file name="Exception.php" hash="0cd21857de30348ee36f6f494a358a1a"/><dir name="Process"><file name="Log.php" hash="05eecaa8cff9719b229d0454bbd97100"/></dir><file name="Process.php" hash="c1318749346daae89912051b54413df7"/><dir name="Profile"><file name="Interface.php" hash="8a9f763fcce353aed2b57e4ec10a4ec2"/></dir><file name="Profile.php" hash="bb45569a4c72bbdb68199e2167b27a54"/></dir><dir name="Mysql4"><dir name="Account"><file name="Collection.php" hash="f9dbdbb023051a3e412be801e7c1d5ec"/></dir><file name="Account.php" hash="b7949c5e00cb29efe2b067087933c6a4"/><dir name="DataProcessing"><dir name="Process"><file name="Collection.php" hash="be74cb9e732fc382af4b1ed27bf00a2c"/></dir><file name="Process.php" hash="ed751ed6cae58c83af340e1bd34ce774"/></dir></dir><dir name="Resource"><file name="Setup.php" hash="1aed96e7fe8c8cb06b27b5ef56f8822f"/></dir><dir name="Service"><file name="Abstract.php" hash="8bf7819516d9c07dcd1d96effd1c923e"/><file name="BatchMember.php" hash="b6cc28b33e169b40ddbb37b093cf13a1"/><file name="Member.php" hash="b46d65f710d9dbee42e8f805006b65b8"/><file name="Notification.php" hash="40dfc88a9db3dbfbda6b712ed90b03b0"/><file name="Transactional.php" hash="6b4caa0898a437a1cf75256a71610506"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="AccountController.php" hash="6b36539b47115ac5f8f752e7cb4f75de"/><file name="DataProcessingController.php" hash="3d7c50f4157b64c064ddb80c6c9bf8ff"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="4d34e179b76354ddef639fcb5463977c"/><file name="config.xml" hash="b68de4615e2ab7844c135c5e2e58062e"/><file name="system.xml" hash="85d9908f748a15c6247582418a1b606c"/></dir><file name="functions.php" hash="66186dbf8024c0c2a0b291495d406c89"/><dir name="sql"><dir name="emvcore_setup"><file name="mysql4-install-0.1.0.php" hash="b1319057a975d8dd2c829d6c00affc74"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="af4506f20cd8cdfa11c0394fdd78a06c"/><file name="mysql4-upgrade-0.2.0-0.3.0.php" hash="faf42db141fd0e3a06916f33c9a7d5c6"/></dir></dir></dir><dir name="DataSync"><dir name="Block"><dir name="Adminhtml"><dir name="Form"><dir name="Field"><file name="CustomerAttributes.php" hash="0d7abe47b8c6af18d09d674f97df2dc7"/><file name="EmailVisionFields.php" hash="67d9bb70184bd844cba669d4ac5c04ed"/></dir></dir><dir name="Newsletter"><dir name="Subscriber"><file name="Grid.php" hash="d39d0f8cf8941e6eb2468838370d1578"/></dir><file name="Subscriber.php" hash="cd11fa85a33c2a5e10f497bfcf13db78"/></dir><dir name="System"><dir name="Config"><file name="CustomerAttributes.php" hash="4e5445a45a0ee3ddad4256dea2fdaa01"/><file name="Date.php" hash="1790331bd1bb06a441737ecf345df6da"/><file name="GetFields.php" hash="88dba41a38becc0861c172ddc6440893"/></dir></dir></dir></dir><dir name="Helper"><file name="Data.php" hash="45c8c81ecd1b5d87c46574c8c16c637b"/><file name="Service.php" hash="da0481194392ee400d5f030b0b958266"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><dir name="ApiMember"><file name="Account.php" hash="09cfe4b6651eae737945ab16b25ce6bb"/><file name="Cron.php" hash="1e7a38db39c21d04b0249ec181c1993f"/><file name="Enabled.php" hash="19e91d89fa6a098010ea4d9582b72451"/></dir><dir name="BatchMember"><file name="Account.php" hash="844f3af6efd125d6b1d9ef8808984e79"/><file name="Cron.php" hash="8b9dcd2ee474d2b779de240c000b1d82"/><file name="Enabled.php" hash="b00cce598c212933cc2fe1db4cc4d4b4"/></dir><dir name="Clean"><file name="Cron.php" hash="728bd3cfe90b303dd7944684d92748b7"/></dir><dir name="PurchaseProcess"><file name="Cron.php" hash="87c3e0a93e97bd9d10c685f140e46c8f"/></dir></dir><dir name="Source"><file name="Fields.php" hash="5f469c279ddabaa6f1142616e6106089"/><file name="MemberCronTime.php" hash="0ed64e65649d2f8b783fcf2fb19f49f8"/></dir></dir></dir></dir><dir name="AttributeProcessing"><file name="Config.php" hash="4dba5219305e882461a71b93ba80bf55"/><dir name="Handler"><file name="Abstract.php" hash="de180f7fcc0b4e0bff2980814a6d34e8"/><file name="Customer.php" hash="4235914c273f56ed183faeb7d9814604"/><file name="Newsletter.php" hash="7569eb7038d47432eb3aaba7ee6dd310"/><file name="PurchaseInformation.php" hash="9d9525d1e66d0aeeeec0b36ee964c47e"/></dir></dir><file name="Cron.php" hash="fd73cc2fa685b60b7f772a008b21c5c0"/><dir name="DataProcess"><file name="PurchaseInformation.php" hash="390c8d87f7f3570e8f452cf157ce8717"/></dir><dir name="Mysql4"><dir name="DataProcess"><dir name="PurchaseInformation"><file name="Collection.php" hash="48d6087490407cf456cfc7342bbe9e98"/></dir><file name="PurchaseInformation.php" hash="788e7740eb558b474c826dc89bc20723"/></dir></dir><file name="Observer.php" hash="a2ec393b456d2c2cc48ef9628e8091dc"/><dir name="Service"><file name="BatchMember.php" hash="bff9371be7498558211da6087588e96c"/><file name="DataProcess.php" hash="80caa339fc5c5a56b4091d0969c7f981"/><file name="Member.php" hash="e97677a37e170945160a4fe7c84a8fc9"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="DataSyncController.php" hash="4dc71b5186f049b06f9029a7029c5f76"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="f0caeee8c126f14e007ce5a9e8763017"/><file name="config.xml" hash="7c13a5266c6c12ab59cd41c2fb174ec6"/><file name="system.xml" hash="2c4dff513fbd45611f2e68c3baa93eec"/></dir><dir name="sql"><dir name="emvdatasync_setup"><file name="mysql4-install-0.0.1.php" hash="818dda964561417281aaa757f809664b"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="f452f8d95d30a1fc33049cc2ea90742d"/><file name="mysql4-upgrade-0.2.0-0.2.1.php" hash="7a876d71e9213f8031edc71e775bc07e"/></dir></dir></dir><dir name="Emt"><dir name="Block"><dir name="Adminhtml"><dir name="Config"><file name="ExtensionStatus.php" hash="12166dcdca2fd436b410889f8bea8afd"/></dir><dir name="Log"><dir name="Grid"><dir name="Renderer"><file name="GetError.php" hash="a7fb7e3075e611b0e5b672d0ecee3ddd"/></dir></dir><file name="Grid.php" hash="152ccd45c016803970f42008e3dd8880"/></dir><file name="Log.php" hash="24551f106915450e8e775b2bb1324451"/><dir name="Resending"><file name="Grid.php" hash="2a8b666807239ef14bf56475a69c8baa"/></dir><file name="Resending.php" hash="beaad1da5f136d403f8881e21dc9639e"/><dir name="System"><dir name="Config"><file name="ValidateAccount.php" hash="7b0e245225a48044e84ead1eaf87768a"/></dir></dir><dir name="Template"><dir name="Edit"><dir name="Tab"><file name="EmvContent.php" hash="a540805b70ec00fc6b5cdcc32b1a1cfb"/><file name="EmvDyn.php" hash="f12852b4e788197ba72d4e806f941798"/><file name="General.php" hash="aac30c1f6e0b85d08e42de4958bf3cf4"/></dir><file name="Tabs.php" hash="320b4c3e740ba5aacbbd5c602ffb041c"/></dir><file name="Edit.php" hash="1112cc25a74337a740647d4c5b6dc67e"/><dir name="Grid"><dir name="Renderer"><file name="Emvname.php" hash="1cf0f98ad194b33c4d9c91f0195c8146"/><file name="MageTemplate.php" hash="e284d93be818c24016bd462e31c226ee"/></dir></dir><file name="Grid.php" hash="19ab59d96e2925d6fe2b14aad3111498"/></dir><file name="Templates.php" hash="12bcab5abc0be49e4e04b0d92eecf61c"/></dir></dir><dir name="Helper"><file name="Data.php" hash="067567bd92ed2d9c5ccd0c2f2d7d8cd2"/><file name="Emvtemplate.php" hash="ab97b960d47434035b0664b0eb53ceb0"/></dir><dir name="Model"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Backend"><file name="Account.php" hash="946f8389c4f2ef1a365757ced0707daa"/><dir name="Log"><file name="Cron.php" hash="bc0c0db43127e17c616b22f9d3d74dcc"/></dir></dir></dir></dir></dir><file name="Attribute.php" hash="b0c369fcc0bc47f48ba7c5866dc72260"/><file name="Cron.php" hash="e1b81f126a847170fe45b25e63aa22b3"/><file name="Emt.php" hash="86f759a61dd7d637ed41e635f6354625"/><file name="Log.php" hash="440c8bd3969f5e36d7d6402fb01d0246"/><dir name="Mage"><dir name="Core"><dir name="Email"><file name="Template.php" hash="e5c31cf93c5b2aa0b88e8176463f5a77"/></dir></dir></dir><file name="MageTemplate.php" hash="ddf98c89b163c6e59ceed1ac5dbe8f69"/><file name="Mailmode.php" hash="9f59dc4b0b797037fcb25553c19f2d49"/><dir name="Mysql4"><dir name="Attribute"><file name="Collection.php" hash="3e3308be1178e99162606a668eace8ed"/></dir><file name="Attribute.php" hash="bd2854ed8ee4fb207b994543a0ecf9ba"/><dir name="Emt"><file name="Collection.php" hash="bbc3368b7276bbff83c1770b6a097c26"/></dir><file name="Emt.php" hash="7fd5ff6b090587b56ac09366289b369f"/><dir name="Log"><file name="Collection.php" hash="dc04e8d73fa3df064453f7c7ee12a400"/></dir><file name="Log.php" hash="cec89e175333d33add521063b2aa96a9"/><dir name="Resending"><dir name="Queue"><dir name="Message"><file name="Collection.php" hash="8b165985970886c74aef0c9d62140098"/></dir><file name="Message.php" hash="63b4e07ee46f64d7f1c8284f5f789f71"/></dir></dir></dir><file name="Observer.php" hash="184b868bac92421a27a406bff438c938"/><dir name="Resending"><dir name="Queue"><file name="Message.php" hash="4830bc5ef750efcd8973ee46f424ec51"/></dir><file name="Queue.php" hash="bb2128bf1a9ecd5cf9fb8d06f8de845b"/><file name="Rule.php" hash="b48897eeb2ca670b90e6f3356a5f5b43"/></dir><dir name="Resource"><file name="Setup.php" hash="b5fc87772ed86c16c54eb9262dd291a3"/></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="LogController.php" hash="05fbabe704020cddc12a8656cc9220bd"/><file name="RescheduleController.php" hash="5331244d0bb14e448fbde3b797fb680d"/><file name="TemplateController.php" hash="98c751db95da7cbf62a2305946fcd1b1"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="193ed52e7bc6f002b4526d697166c84d"/><file name="config.xml" hash="62e761edea0e32139c26f93796ab29e7"/><file name="system.xml" hash="bb3dddf31ac07675beb0cdd448bb4dc6"/></dir><dir name="sql"><dir name="emvemt_setup"><file name="mysql4-install-0.1.0.php" hash="a7d12df049f2c1377a072fa7899dcb6c"/><file name="mysql4-upgrade-0.1.0-0.2.0.php" hash="3b52221a751b221ae98e16a03807335a"/><file name="mysql4-upgrade-0.2.0-0.3.0.php" hash="0108cecb8c995004987e869fc008bf34"/><file name="mysql4-upgrade-0.3.0-0.4.0.php" hash="7ef46dc220aeb7265ef43cab5b17156f"/><file name="mysql4-upgrade-0.4.0-0.4.1.php" hash="a6eb1e85d8773af9c0935bacabcc06dd"/></dir></dir></dir><dir name="Report"><dir name="Block"><dir name="Adminhtml"><dir name="Conversion"><file name="Form.php" hash="9c537aa62d666816058130d257f75bb8"/></dir><file name="Conversion.php" hash="79959891324dcc99448d93f9cfa01724"/><dir name="Details"><file name="Grid.php" hash="beb3a98688d554cb8d49aa5a8613bd5a"/></dir><file name="Details.php" hash="a765998cb0a765423f89cd652a2d1dab"/></dir></dir><dir name="Helper"><file name="Data.php" hash="14fd1c74a2de74a85190394166c1e684"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="ConversionController.php" hash="38723e8c66a90950ed814c93a9a71fc1"/><file name="DetailsController.php" hash="653096279fbe200d6b5ac6208efe732a"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="68373b55dda02598730b80d61d313758"/><file name="config.xml" hash="34763aa8d9413c592e698e479bf00a79"/></dir></dir></dir><dir name="Mage"><dir name="SalesRule"><dir name="Helper"><file name="Coupon.php" hash="05d42b935bd31dad39c9e31052ef60c8"/></dir><dir name="Model"><dir name="Coupon"><file name="Massgenerator.php" hash="c5312f2a745bf79d2a8ac90c23fb79dc"/></dir><dir name="System"><dir name="Config"><dir name="Source"><dir name="Coupon"><file name="Format.php" hash="64236cb46364219d4a5702521898a249"/></dir></dir></dir></dir></dir></dir></dir></target></contents>
71
  <compatible/>
72
  <dependencies><required><php><min>5.2.6</min><max>5.5.4</max></php></required></dependencies>
73
  </package>
skin/adminhtml/default/default/campaign-commander.css DELETED
@@ -1,14 +0,0 @@
1
- .emv_attributes .va-middle{
2
- vertical-align: middle;
3
- }
4
- .emv_attributes .content-header {
5
- margin-bottom: 10px;
6
- border-bottom: 4px solid #FFF;
7
- }
8
- .emv_attributes textarea{
9
- width: 90%;
10
- margin-top: 2px;
11
- }
12
- .emv_attributes th{
13
- height: 30px;
14
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
skin/adminhtml/default/default/images/smartfocus/tick.png ADDED
Binary file
skin/adminhtml/default/default/images/smartfocus/untick.gif ADDED
Binary file
skin/adminhtml/default/default/images/smartfocus/warning.png ADDED
Binary file
skin/adminhtml/default/default/smartfocus.css ADDED
@@ -0,0 +1,25 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ .emv_attributes .va-middle{
2
+ vertical-align: middle;
3
+ }
4
+ .emv_attributes .content-header {
5
+ margin-bottom: 10px;
6
+ border-bottom: 4px solid #FFF;
7
+ }
8
+ .emv_attributes textarea{
9
+ width: 90%;
10
+ margin-top: 2px;
11
+ }
12
+ .emv_attributes th{
13
+ height: 30px;
14
+ }
15
+ .grid tr.on-progress { background-color: #fcf5dd; }
16
+ .smartfocus-selection { border-collapse:collapse; width:100%; }
17
+ .smartfocus-selection .smartfocus-selection-info { text-align:right; }
18
+ .smartfocus-selection th { font-size:13px; padding:5px 0; text-align:left; vertical-align:middle; }
19
+ .smartfocus-selection td { background:#f2f2f2; border-bottom:5px solid #fff; padding:5px; vertical-align:top; }
20
+ .smartfocus-selection .smartfocus-selection-simplified { background:#fff; padding-left:35px; }
21
+ .smartfocus-selection td a { color:#2997d8; }
22
+ .smartfocus-selection td strong { color:#3c616a; }
23
+ .smartfocus-selection td label { display:block; padding-left:30px; text-indent:-30px;padding-top:3px; }
24
+ .smartfocus-selection td div label { display:inline; padding:0; text-indent:0; }
25
+ .smartfocus-selection td input { height:13px; overflow:hidden; margin-right:15px; position:relative; top:-1px; width:13px; vertical-align:middle; }