Cloudiq_Cartaudit - Version 1.0.0

Version Notes

Initial release.

Download this release

Release Info

Developer cloud.IQ
Extension Cloudiq_Cartaudit
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (32) hide show
  1. app/code/community/Cloudiq/Cartaudit/Block/Adminhtml/Config/Edit/Tab/Cartaudit.php +139 -0
  2. app/code/community/Cloudiq/Cartaudit/Block/Tag.php +24 -0
  3. app/code/community/Cloudiq/Cartaudit/Helper/Data.php +5 -0
  4. app/code/community/Cloudiq/Cartaudit/Helper/Options.php +49 -0
  5. app/code/community/Cloudiq/Cartaudit/Model/Api/Cartaudit/Store/Cartaudit.php +98 -0
  6. app/code/community/Cloudiq/Cartaudit/Model/Config.php +195 -0
  7. app/code/community/Cloudiq/Cartaudit/Model/Observer.php +82 -0
  8. app/code/community/Cloudiq/Cartaudit/Test/Config/Base.php +28 -0
  9. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit.php +122 -0
  10. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testCartauditResponseMissing.txt +16 -0
  11. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testCartauditResponseUnsuccessful.txt +19 -0
  12. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testResponseSuccessful.txt +19 -0
  13. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testResponseUnsuccessful.txt +16 -0
  14. app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/providers/testRequestRequiredParameter.yaml +12 -0
  15. app/code/community/Cloudiq/Cartaudit/Test/Model/Config.php +146 -0
  16. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCalculateDropOffRate.yaml +6 -0
  17. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCalculateRevenueLost.yaml +6 -0
  18. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCanEstimateRevenueLostMissingField.yaml +6 -0
  19. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testIsConfiguredMissingField.yaml +4 -0
  20. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testOptionalField.yaml +6 -0
  21. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testRequiredField.yaml +12 -0
  22. app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testSave.yaml +11 -0
  23. app/code/community/Cloudiq/Cartaudit/Test/fixtures/empty_config.yaml +10 -0
  24. app/code/community/Cloudiq/Cartaudit/Test/fixtures/valid_config.yaml +11 -0
  25. app/code/community/Cloudiq/Cartaudit/etc/config.xml +74 -0
  26. app/code/community/Cloudiq/Cartaudit/sql/cloudiq_cartaudit_setup/mysql4-install-1.0.0.php +55 -0
  27. app/design/adminhtml/default/default/layout/cloudiq/cartaudit.xml +21 -0
  28. app/design/adminhtml/default/default/template/cloudiq/cartaudit/tab/config.phtml +46 -0
  29. app/design/frontend/base/default/layout/cloudiq/cartaudit.xml +8 -0
  30. app/etc/modules/Cloudiq_Cartaudit.xml +12 -0
  31. package.xml +20 -0
  32. skin/adminhtml/default/default/cloudiq/cartaudit.css +3 -0
app/code/community/Cloudiq/Cartaudit/Block/Adminhtml/Config/Edit/Tab/Cartaudit.php ADDED
@@ -0,0 +1,139 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Block_Adminhtml_Config_Edit_Tab_Cartaudit extends Mage_Adminhtml_Block_Widget_Form implements Mage_Adminhtml_Block_Widget_Tab_Interface {
4
+
5
+ /** @var Cloudiq_Cartaudit_Model_Config $_config */
6
+ protected $_config;
7
+
8
+ /** @var Cloudiq_Cartaudit_Helper_Options $_options */
9
+ protected $_options;
10
+
11
+ /** @var Varien_Object $_input */
12
+ protected $_input;
13
+
14
+ public function _construct() {
15
+ parent::_construct();
16
+
17
+ $this->_config = Mage::getModel('cloudiq_cartaudit/config');
18
+ $this->_config->load();
19
+
20
+ $this->_options = Mage::helper('cloudiq_cartaudit/options');
21
+
22
+ $input_data = Mage::getSingleton('adminhtml/session')->getData('cartaudit_form_data', true);
23
+ if ($input_data && count($input_data->getData()) > 0) {
24
+ $this->_input = $input_data;
25
+ }
26
+
27
+ $this->setTemplate('cloudiq/cartaudit/tab/config.phtml');
28
+ }
29
+
30
+ protected function _prepareForm() {
31
+ $form = new Varien_Data_Form();
32
+
33
+ $this->_addServiceFieldset($form);
34
+ $this->_addCartFieldset($form);
35
+
36
+ $this->setForm($form);
37
+ }
38
+
39
+ protected function _addServiceFieldset($form) {
40
+ $fieldset = $form->addFieldset('service', array('legend' => $this->__('Service')));
41
+
42
+ $fieldset->addField('cartaudit[enabled]', 'select', array(
43
+ 'label' => $this->__('Enable?'),
44
+ 'title' => $this->__('Enable?'),
45
+ 'name' => 'cartaudit[enabled]',
46
+ 'value' => ($this->_input) ? $this->_input->getData('enabled') : $this->_config->getEnabled(),
47
+ 'values' => Mage::getSingleton('adminhtml/system_config_source_yesno')->toOptionArray()
48
+ ));
49
+ }
50
+
51
+ protected function _addCartFieldset($form) {
52
+ $fieldset = $form->addFieldset('cart', array('legend' => $this->__('Tell us about your cart')));
53
+
54
+ $fieldset->addField('cartaudit[cart][app_name]', 'text', array(
55
+ 'label' => $this->__('Company Name'),
56
+ 'title' => $this->__('Company Name'),
57
+ 'name' => 'cartaudit[cart][app_name]',
58
+ 'value' => ($this->_input) ? $this->_input->getData('cart/app_name') : $this->_config->getAppName(),
59
+ 'required' => true
60
+ ));
61
+
62
+ $industry_options = $this->_options->getIndustryOptions();
63
+ array_unshift($industry_options, array('value' => '', 'label' => 'Please select...'));
64
+
65
+ $fieldset->addField('cartaudit[cart][industry]', 'select', array(
66
+ 'label' => $this->__('Industry'),
67
+ 'text' => $this->__('Industry'),
68
+ 'name' => 'cartaudit[cart][industry]',
69
+ 'value' => ($this->_input) ? $this->_input->getData('cart/industry') : $this->_config->getIndustry(),
70
+ 'values' => $industry_options,
71
+ 'required' => false,
72
+ ));
73
+
74
+ $fieldset->addField('cartaudit[cart][website_url]', 'text', array(
75
+ 'label' => $this->__('Website URL'),
76
+ 'title' => $this->__('Website URL'),
77
+ 'note' => $this->__("Please tell us your site's URL."),
78
+ 'name' => 'cartaudit[cart][website_url]',
79
+ 'value' => ($this->_input) ? $this->_input->getData('cart/website_url') : $this->_config->getWebsiteUrl(),
80
+ 'required' => true,
81
+ 'class' => 'validate-url'
82
+ ));
83
+
84
+ $fieldset->addField('cartaudit[cart][cart_confirmation_url]', 'text', array(
85
+ 'label' => $this->__('Confirmation page URL'),
86
+ 'title' => $this->__('Confirmation page URL'),
87
+ 'name' => 'cartaudit[cart][cart_confirmation_url]',
88
+ 'value' => ($this->_input) ? $this->_input->getData('cart/cart_confirmation_url') : $this->_config->getCartConfirmationUrl(),
89
+ 'required' => false,
90
+ 'class' => 'validate-url'
91
+ ));
92
+
93
+ $fieldset->addField('cartaudit[cart][average_cart_value]', 'text', array(
94
+ 'label' => $this->__('Average cart value'),
95
+ 'title' => $this->__('Average cart value'),
96
+ 'note' => $this->__("Estimate the average value of a cart transaction completed on your site. We use this to estimate the revenue that could be recovered."),
97
+ 'name' => 'cartaudit[cart][average_cart_value]',
98
+ 'value' => ($this->_input) ? $this->_input->getData('cart/average_cart_value') : $this->_config->getAverageCartValue(),
99
+ 'required' => true,
100
+ 'class' => 'validate-number'
101
+ ));
102
+
103
+ $fieldset->addField('cartaudit[cart][carts_started_per_month]', 'text', array(
104
+ 'label' => $this->__('Carts started per month'),
105
+ 'title' => $this->__('Carts started per month'),
106
+ 'note' => $this->__("How many users start but don't complete a cart in a month? We use this for reporting purposes."),
107
+ 'name' => 'cartaudit[cart][carts_started_per_month]',
108
+ 'value' => ($this->_input) ? $this->_input->getData('cart/carts_started_per_month') : $this->_config->getCartsStartedPerMonth(),
109
+ 'required' => true,
110
+ 'class' => 'validate-digits'
111
+ ));
112
+
113
+ $fieldset->addField('cartaudit[cart][carts_completed_per_month]', 'text', array(
114
+ 'label' => $this->__('Carts completed per month'),
115
+ 'title' => $this->__('Carts completed per month'),
116
+ 'note' => $this->__("Estimate the number of carts successfully completed in a month. We use this to calculate drop out rates."),
117
+ 'name' => 'cartaudit[cart][carts_completed_per_month]',
118
+ 'value' => ($this->_input) ? $this->_input->getData('cart/carts_completed_per_month') : $this->_config->getCartsCompletedPerMonth(),
119
+ 'required' => true,
120
+ 'class' => 'validate-digits'
121
+ ));
122
+ }
123
+
124
+ public function getTabLabel() {
125
+ return $this->__('cartAudit Settings');
126
+ }
127
+
128
+ public function getTabTitle() {
129
+ return $this->__('cartAudit Settings');
130
+ }
131
+
132
+ public function canShowTab() {
133
+ return Mage::helper('cloudiq_core/config')->hasBeenSetUp();
134
+ }
135
+
136
+ public function isHidden() {
137
+ return !(Mage::helper('cloudiq_core/config')->hasBeenSetUp());
138
+ }
139
+ }
app/code/community/Cloudiq/Cartaudit/Block/Tag.php ADDED
@@ -0,0 +1,24 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Block_Tag extends Mage_Core_Block_Abstract {
4
+
5
+ /** @var Cloudiq_Cartaudit_Model_Config $_config */
6
+ protected $_config;
7
+
8
+ public function _construct() {
9
+ $this->_config = Mage::getModel('cloudiq_cartaudit/config');
10
+ $this->_config->load();
11
+ }
12
+
13
+ /**
14
+ * Return the cloud.IQ tag as HTML.
15
+ *
16
+ * @return string
17
+ */
18
+ protected function _toHtml() {
19
+ if ($this->_config->isConfigured()) {
20
+ return $this->_config->getCloudiqTag();
21
+ }
22
+ return "";
23
+ }
24
+ }
app/code/community/Cloudiq/Cartaudit/Helper/Data.php ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Helper_Data extends Mage_Core_Helper_Abstract {
4
+
5
+ }
app/code/community/Cloudiq/Cartaudit/Helper/Options.php ADDED
@@ -0,0 +1,49 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Helper_Options extends Mage_Core_Helper_Abstract {
4
+
5
+ /**
6
+ * Return the list of available options for the Industry drop down.
7
+ *
8
+ * @return array
9
+ */
10
+ public function getIndustryOptions() {
11
+ return array(
12
+ array('value' => 'automotive', 'label' => $this->__("Automotive")),
13
+ array('value' => 'agriculture', 'label' => $this->__("Agriculture")),
14
+ array('value' => 'banking_finance', 'label' => $this->__("Banking & Finance")),
15
+ array('value' => 'books_stationary', 'label' => $this->__("Books & Stationary")),
16
+ array('value' => 'construction', 'label' => $this->__("Construction")),
17
+ array('value' => 'consulting', 'label' => $this->__("Consulting")),
18
+ array('value' => 'education', 'label' => $this->__("Education")),
19
+ array('value' => 'electronics', 'label' => $this->__("Electronics")),
20
+ array('value' => 'engineering', 'label' => $this->__("Engineering")),
21
+ array('value' => 'entertainment', 'label' => $this->__("Entertainment")),
22
+ array('value' => 'environmental', 'label' => $this->__("Environmental")),
23
+ array('value' => 'fashion', 'label' => $this->__("Fashion")),
24
+ array('value' => 'food_beverage', 'label' => $this->__("Food & Beverage")),
25
+ array('value' => 'government', 'label' => $this->__("Government")),
26
+ array('value' => 'healthcare_beauty', 'label' => $this->__("Healthcare & Beauty")),
27
+ array('value' => 'hospitality', 'label' => $this->__("Hospitality")),
28
+ array('value' => 'household_goods', 'label' => $this->__("Household Goods")),
29
+ array('value' => 'insurance', 'label' => $this->__("Insurance")),
30
+ array('value' => 'jewellery', 'label' => $this->__("Jewellery")),
31
+ array('value' => 'kids_toys', 'label' => $this->__("Kids/Toys")),
32
+ array('value' => 'lifestyle_sports_goods', 'label' => $this->__("Lifestyle/Sports Goods")),
33
+ array('value' => 'leisure_tourism', 'label' => $this->__("Leisure & Tourism")),
34
+ array('value' => 'machinery', 'label' => $this->__("Machinery")),
35
+ array('value' => 'manufacturing', 'label' => $this->__("Manufacturing")),
36
+ array('value' => 'media', 'label' => $this->__("Media")),
37
+ array('value' => 'not_for_profit', 'label' => $this->__("Not For Profit")),
38
+ array('value' => 'other', 'label' => $this->__("Other")),
39
+ array('value' => 'public_sector', 'label' => $this->__("Public Sector")),
40
+ array('value' => 'property', 'label' => $this->__("Property")),
41
+ array('value' => 'retail', 'label' => $this->__("Retail")),
42
+ array('value' => 'security', 'label' => $this->__("Security")),
43
+ array('value' => 'shipping', 'label' => $this->__("Shipping")),
44
+ array('value' => 'technology', 'label' => $this->__("Technology")),
45
+ array('value' => 'telecommunications', 'label' => $this->__("Telecommunications")),
46
+ array('value' => 'utilities', 'label' => $this->__("Utilities"))
47
+ );
48
+ }
49
+ }
app/code/community/Cloudiq/Cartaudit/Model/Api/Cartaudit/Store/Cartaudit.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Model_Api_Cartaudit_Store_Cartaudit extends Cloudiq_Core_Model_Api_Abstract {
4
+
5
+ protected $response_error_message;
6
+
7
+ /**
8
+ * Create a cloud.IQ API request for the "store cartaudit" function from the given config.
9
+ *
10
+ * @param array $arguments Array of arguments, must contain an instance of Cloudiq_Cartaudit_Model_Config
11
+ * as the 'config' argument.
12
+ * @return Cloudiq_Core_Model_Api_Request
13
+ */
14
+ public function buildRequest($arguments) {
15
+ if (!array_key_exists('config', $arguments) || ! ($arguments['config'] instanceof Cloudiq_Cartaudit_Model_Config)) {
16
+ return null;
17
+ }
18
+
19
+ $parameters = $this->_convertConfigToParameters($arguments['config']);
20
+ $parameters['mode'] = 'store';
21
+ $parameters['action'] = 'cartaudit';
22
+
23
+ /** @var Cloudiq_Core_Model_Api_Request $request */
24
+ $request = $this->_getRequestObject()->setParameters($parameters);
25
+
26
+ return $request;
27
+ }
28
+
29
+ /**
30
+ * Check if the given cloud.IQ API response is a successful cartAudit response.
31
+ *
32
+ * @param Cloudiq_Core_Model_Api_Response $response
33
+ *
34
+ * @return boolean
35
+ */
36
+ public function isResponseSuccessful($response) {
37
+ $this->response_error_message = null;
38
+
39
+ // Check if we have a response
40
+ if (!$response) {
41
+ $this->response_error_message = "No API response received.";
42
+ return false;
43
+ }
44
+
45
+ // Check if the response was successful
46
+ if (!$response->wasSuccessful()) {
47
+ $this->response_error_message = $response->getErrorMessage();
48
+ return false;
49
+ }
50
+
51
+ // Check if a cartAudit response was returned
52
+ $cartaudit_response = $response->getResponse()->cartAudit;
53
+ if (is_null($cartaudit_response)) {
54
+ $this->response_error_message = "Unknown cartAudit response status.";
55
+ return false;
56
+ }
57
+
58
+ // Check if the cartAudit response was successful
59
+ if ($cartaudit_response['status'] != Cloudiq_Core_Model_Api_Response::STATUS_SUCCESS) {
60
+ if ($cartaudit_response->errorMessages) {
61
+ $this->response_error_message = sprintf("%s", $cartaudit_response->errorMessages);
62
+ } else {
63
+ $this->response_error_message = $response->getApiStatusCodeDescription($cartaudit_response['status']);
64
+ }
65
+ return false;
66
+ }
67
+
68
+ // All checks passed
69
+ return true;
70
+ }
71
+
72
+ /**
73
+ * Return the error message generated by the last call to isResponseSuccessful().
74
+ *
75
+ * @return string
76
+ */
77
+ public function getResponseErrorMessage() {
78
+ return $this->response_error_message;
79
+ }
80
+
81
+ /**
82
+ * Create an array of parameters used by the "store cartaudit" API function from the provided config.
83
+ *
84
+ * @param Cloudiq_Cartaudit_Model_Config $config
85
+ * @return array
86
+ */
87
+ protected function _convertConfigToParameters(Cloudiq_Cartaudit_Model_Config $config) {
88
+ $parameters = $config->toCamelCaseArray();
89
+
90
+ // Remove parameters not used by the API
91
+ unset(
92
+ $parameters["enabled"],
93
+ $parameters["cloudiqTag"]
94
+ );
95
+
96
+ return $parameters;
97
+ }
98
+ }
app/code/community/Cloudiq/Cartaudit/Model/Config.php ADDED
@@ -0,0 +1,195 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class Cloudiq_Cartaudit_Model_Config
5
+ *
6
+ * @method getEnabled()
7
+ * @method getAppId()
8
+ * @method setAppId()
9
+ * @method getCloudiqTag()
10
+ * @method setCloudiqTab()
11
+ * @method getAppName()
12
+ * @method getIndustry()
13
+ * @method getWebsiteUrl()
14
+ * @method getCartConfirmationUrl()
15
+ * @method hasAverageCartValue()
16
+ * @method getAverageCartValue()
17
+ * @method hasCartsStartedPerMonth()
18
+ * @method getCartsStartedPerMonth()
19
+ * @method hasCartsCompletedPerMonth()
20
+ * @method getCartsCompletedPerMonth()
21
+ */
22
+ class Cloudiq_Cartaudit_Model_Config extends Varien_Object {
23
+
24
+ const CONFIG_KEY_PREFIX = "cloudiq/cartaudit";
25
+
26
+ /**
27
+ * Load the config data from the database.
28
+ *
29
+ * @return Cloudiq_Cartaudit_Model_Config
30
+ */
31
+ public function load() {
32
+ $config_data = Mage::getStoreConfig(self::CONFIG_KEY_PREFIX);
33
+
34
+ $this->unsetData();
35
+
36
+ if (is_array($config_data) && !empty($config_data)) {
37
+ foreach ($config_data as $key => $value) {
38
+ $this->setData($key, $value);
39
+ }
40
+ }
41
+
42
+ return $this;
43
+ }
44
+
45
+ /**
46
+ * Save the config data to the database.
47
+ *
48
+ * @return Cloudiq_Cartaudit_Model_Config
49
+ */
50
+ public function save() {
51
+ $errors = $this->validate();
52
+
53
+ if (empty($errors)) {
54
+ $data = $this->getData();
55
+
56
+ $system_config = Mage::getConfig();
57
+
58
+ foreach ($data as $key => $value) {
59
+ $system_config->saveConfig(self::CONFIG_KEY_PREFIX . "/" . $key, $value);
60
+ }
61
+
62
+ $system_config->reinit();
63
+ Mage::app()->reinitStores();
64
+ } else {
65
+ Mage::throwException("Could not save Cloudiq_Cartaudit_Model_Config due to validation errors: " . implode(", ", $errors));
66
+ }
67
+
68
+ return $this;
69
+ }
70
+
71
+ /**
72
+ * Validate the config data. Return an array of validation errors, or an empty array if validation passed.
73
+ *
74
+ * @return array validation error messages.
75
+ */
76
+ public function validate() {
77
+ $errors = array();
78
+
79
+ // Enabled = 0|1
80
+ if (!Zend_Validate::is($this->getEnabled(), "InArray", array("haystack" => array("0", "1")))) {
81
+ $errors["enabled"] = "Enabled must be set to 0 or 1.";
82
+ }
83
+
84
+ // App Name must not be empty
85
+ if (!Zend_Validate::is($this->getAppName(), "NotEmpty")) {
86
+ $errors["appName"] = "App Name can not be empty.";
87
+ }
88
+
89
+ // Industry must match one of the available options
90
+ if ($this->getIndustry() && !Zend_Validate::is($this->getIndustry(), "InArray", array("haystack" => array_map(function ($el) { return $el["value"]; }, Mage::helper('cloudiq_cartaudit/options')->getIndustryOptions())))) {
91
+ $errors["industry"] = "Invalid Industry value.";
92
+ }
93
+
94
+ // Site URL must be valid
95
+ if (!filter_var($this->getWebsiteUrl(), FILTER_VALIDATE_URL)) {
96
+ $errors["websiteUrl"] = "Website URL must be a valid URL.";
97
+ }
98
+
99
+ // Cart Confirmation URL must be valid
100
+ if ($this->getCartConfirmationUrl() && !filter_var($this->getCartConfirmationUrl(), FILTER_VALIDATE_URL)) {
101
+ $errors["cartConfirmationUrl"] = "Cart Confirmation URL must be a valid URL.";
102
+ }
103
+
104
+ // Average Cart Value must be present
105
+ if (!Zend_Validate::is($this->getAverageCartValue(), "NotEmpty")) {
106
+ $errors["averageCartValue"] = "Average Cart Value can not be empty.";
107
+ }
108
+
109
+ // Carts Started Per Month must be an integer
110
+ if (!Zend_Validate::is($this->getCartsStartedPerMonth(), "Int")) {
111
+ $errors["cartsStartedPerMonth"] = "Carts Started Per Month must be an number.";
112
+ }
113
+
114
+ // Carts Completed Per Month must be an integer
115
+ if (!Zend_Validate::is($this->getCartsCompletedPerMonth(), "Int")) {
116
+ $errors["cartsCompletedPerMonth"] = "Cars Completed Per Month must be an number.";
117
+ }
118
+
119
+ return $errors;
120
+ }
121
+
122
+ /**
123
+ * Check if the config contains the data needed to estimate the revenue lost due to uncompleted carts.
124
+ *
125
+ * @return bool
126
+ */
127
+ public function canEstimateRevenueLost() {
128
+ return (
129
+ $this->hasAverageCartValue()
130
+ && $this->hasCartsStartedPerMonth()
131
+ && $this->hasCartsCompletedPerMonth()
132
+ );
133
+ }
134
+
135
+ /**
136
+ * Calculate the drop off rate based on the number of carts started and completed per month.
137
+ *
138
+ * @return float The drop off rate as a percentage.
139
+ */
140
+ public function calculateDropOffRate() {
141
+ if (!$this->canEstimateRevenueLost()) {
142
+ return null;
143
+ }
144
+
145
+ $carts_started = intval($this->getCartsStartedPerMonth());
146
+ $carts_completed = intval($this->getCartsCompletedPerMonth());
147
+
148
+ if ($carts_started == $carts_completed) {
149
+ return 0;
150
+ }
151
+
152
+ return (100 / $carts_started) * ($carts_started - $carts_completed);
153
+ }
154
+
155
+ /**
156
+ * Calculate the estimated revenue lost based on the number of incomplete carts per month.
157
+ *
158
+ * @return float
159
+ */
160
+ public function calculateRevenueLost() {
161
+ if (!$this->canEstimateRevenueLost()) {
162
+ return null;
163
+ }
164
+
165
+ $carts_started = intval($this->getCartsStartedPerMonth());
166
+ $carts_completed = intval($this->getCartsCompletedPerMonth());
167
+ $average_cart = floatval($this->getAverageCartValue());
168
+
169
+ return ($carts_started - $carts_completed) * $average_cart;
170
+ }
171
+
172
+ /**
173
+ * Check if the model is configured to print the cloud.IQ tag.
174
+ *
175
+ * @return bool
176
+ */
177
+ public function isConfigured() {
178
+ return ($this->getEnabled() && $this->getCloudiqTag() != "");
179
+ }
180
+
181
+ /**
182
+ * Convert all the attributes to an array with camelCase keys
183
+ *
184
+ * @param array $attributes array of attributes to include.
185
+ * @return array
186
+ */
187
+ public function toCamelCaseArray(array $attributes = array()) {
188
+ $data = $this->__toArray($attributes);
189
+ $camelData = array();
190
+ foreach ($data as $key => $value) {
191
+ $camelData[lcfirst($this->_camelize($key))] = $value;
192
+ }
193
+ return $camelData;
194
+ }
195
+ }
app/code/community/Cloudiq/Cartaudit/Model/Observer.php ADDED
@@ -0,0 +1,82 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Model_Observer extends Varien_Object {
4
+
5
+ /**
6
+ * Save the cartAudit data when the cloud.IQ configuration is saved.
7
+ *
8
+ * @param $observer
9
+ */
10
+ public function observeCloudiqCoreConfigSave($observer) {
11
+ $request = $observer->getRequest();
12
+
13
+ /** @var Cloudiq_Cartaudit_Helper_Data $helper */
14
+ $helper = Mage::helper('cloudiq_cartaudit');
15
+
16
+ /** @var Mage_Adminhtml_Model_Session $admin_session */
17
+ $admin_session = Mage::getSingleton('adminhtml/session');
18
+
19
+ $form_data = new Varien_Object($request->getParam('cartaudit'));
20
+
21
+ if (count($form_data->getData()) == 0) {
22
+ // No form data, nothing to save
23
+ return;
24
+ }
25
+
26
+ // Save the form data in session to repopulate the fields in case or errors
27
+ $admin_session->setData('cartaudit_form_data', $form_data);
28
+
29
+ /** @var Cloudiq_Cartaudit_Model_Config $config */
30
+ $config = Mage::getModel('cloudiq_cartaudit/config');
31
+ $config->load();
32
+
33
+ // Update config with the form data
34
+ $config->addData(array(
35
+ 'enabled' => $form_data->getData('enabled'),
36
+
37
+ 'app_name' => $form_data->getData('cart/app_name'),
38
+ 'industry' => $form_data->getData('cart/industry'),
39
+
40
+ 'website_url' => $form_data->getData('cart/website_url'),
41
+ 'cart_confirmation_url' => $form_data->getData('cart/cart_confirmation_url'),
42
+
43
+ 'average_cart_value' => $form_data->getData('cart/average_cart_value'),
44
+
45
+ 'carts_started_per_month' => $form_data->getData('cart/carts_started_per_month'),
46
+ 'carts_completed_per_month' => $form_data->getData('cart/carts_completed_per_month'),
47
+ ));
48
+
49
+ // Validate the new config values
50
+ $errors = $config->validate();
51
+ if (!empty($errors)) {
52
+ foreach ($errors as $field => $message) {
53
+ $admin_session->addError($helper->__("cartAudit: " . $message));
54
+ }
55
+ return;
56
+ }
57
+
58
+ // Submit the changes to the API
59
+ /** @var Cloudiq_Cartaudit_Model_Api_Cartaudit_Store_Cartaudit $api */
60
+ $api = Mage::getModel('cloudiq_cartaudit/api_cartaudit_store_cartaudit');
61
+
62
+ $request = $api->buildRequest(array("config" => $config));
63
+ $response = $request->send(Zend_Http_Client::POST);
64
+
65
+ if ($api->isResponseSuccessful($response)) {
66
+ // API call succeeded, update the appId and cloudiqTag
67
+ $response_data = $response->getResponse()->cartAudit;
68
+ if ($response_data->appId && is_numeric((string) $response_data->appId)) {
69
+ $config->setAppId((string) $response_data->appId);
70
+ }
71
+ if ($response_data->cloudIqTag) {
72
+ $config->setCloudiqTag(html_entity_decode((string) $response_data->cloudIqTag));
73
+ }
74
+ } else {
75
+ $admin_session->addError("cartAudit API error: " . $api->getResponseErrorMessage());
76
+ return;
77
+ }
78
+
79
+ $config->save();
80
+ $admin_session->addSuccess($helper->__("cartAudit: Configuration saved."));
81
+ }
82
+ }
app/code/community/Cloudiq/Cartaudit/Test/Config/Base.php ADDED
@@ -0,0 +1,28 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Test_Config_Base extends EcomDev_PHPUnit_Test_Case_Config {
4
+
5
+ /**
6
+ * @test
7
+ */
8
+ public function testBasicConfiguration() {
9
+ $this->assertModuleCodePool('community');
10
+ $this->assertModuleVersion('1.0.0');
11
+ }
12
+
13
+ /**
14
+ * @test
15
+ */
16
+ public function testClassAliases() {
17
+ $this->assertHelperAlias('cloudiq_cartaudit', 'Cloudiq_Cartaudit_Helper_Data');
18
+ $this->assertModelAlias('cloudiq_cartaudit/test', 'Cloudiq_Cartaudit_Model_Test');
19
+ $this->assertBlockAlias('cloudiq_cartaudit/test', 'Cloudiq_Cartaudit_Block_Test');
20
+ }
21
+
22
+ /**
23
+ * @test
24
+ */
25
+ public function testDataHelperExists() {
26
+ $this->assertInstanceOf('Cloudiq_Cartaudit_Helper_Data', Mage::helper('cloudiq_cartaudit'));
27
+ }
28
+ }
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit.php ADDED
@@ -0,0 +1,122 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Test_Model_Api_Cartaudit_Store_Cartaudit extends EcomDev_PHPUnit_Test_Case {
4
+
5
+ /** @var Cloudiq_Cartaudit_Model_Api_Cartaudit_Store_Cartaudit $_model */
6
+ protected $_model;
7
+
8
+ public function setUp() {
9
+ $this->_model = Mage::getModel('cloudiq_cartaudit/api_cartaudit_store_cartaudit');
10
+ }
11
+
12
+ public function tearDown() {
13
+ $this->_model = null;
14
+ }
15
+
16
+ /**
17
+ * @test
18
+ * @loadFixture ~/valid_config.yaml
19
+ */
20
+ public function testRequestEndpoint() {
21
+ /** @var Cloudiq_Cartaudit_Model_Config $config */
22
+ $config = Mage::getModel('cloudiq_cartaudit/config');
23
+ $config->load();
24
+
25
+ /** @var Cloudiq_Core_Model_Api_Request $request */
26
+ $request = $this->_model->buildRequest(array('config' => $config));
27
+ $request_parameters = $request->getParameters();
28
+
29
+ $this->assertTrue(is_array($request_parameters), 'Request parameters missing.');
30
+ $this->assertArrayHasKey("mode", $request_parameters);
31
+ $this->assertEquals("store", $request_parameters["mode"]);
32
+ $this->assertArrayHasKey("action", $request_parameters);
33
+ $this->assertEquals("cartaudit", $request_parameters["action"]);
34
+ }
35
+
36
+ /**
37
+ * @test
38
+ * @loadFixture ~/valid_config.yaml
39
+ * @dataProvider dataProvider
40
+ */
41
+ public function testRequestRequiredParameter($parameter) {
42
+ /** @var Cloudiq_Cartaudit_Model_Config $config */
43
+ $config = Mage::getModel('cloudiq_cartaudit/config');
44
+ $config->load();
45
+
46
+ /** @var Cloudiq_Core_Model_Api_Request $request */
47
+ $request = $this->_model->buildRequest(array('config' => $config));
48
+ $request_parameters = $request->getParameters();
49
+
50
+ $this->assertTrue(is_array($request_parameters), 'Request parameters missing.');
51
+ $this->assertArrayHasKey($parameter, $request_parameters);
52
+ }
53
+
54
+ /**
55
+ * @test
56
+ */
57
+ public function testResponseSuccessful() {
58
+ /** @var Cloudiq_Core_Model_Api_Response $response */
59
+ $response = Mage::getModel('cloudiq_core/api_response');
60
+ $response->populate($this->_loadHttpResponseFromFile("testResponseSuccessful.txt"));
61
+
62
+ $this->assertTrue($this->_model->isResponseSuccessful($response));
63
+ }
64
+
65
+ /**
66
+ * @test
67
+ */
68
+ public function testResponseUnsuccessful() {
69
+ /** @var Cloudiq_Core_Model_Api_Response $response */
70
+ $response = Mage::getModel('cloudiq_core/api_response');
71
+ $response->populate($this->_loadHttpResponseFromFile("testResponseUnsuccessful.txt"));
72
+
73
+ $this->assertFalse($this->_model->isResponseSuccessful($response));
74
+ }
75
+
76
+ /**
77
+ * @test
78
+ */
79
+ public function testResponseMissing() {
80
+ $this->assertFalse($this->_model->isResponseSuccessful(null));
81
+ }
82
+
83
+ /**
84
+ * @test
85
+ */
86
+ public function testCartauditResponseUnsuccessful() {
87
+ /** @var Cloudiq_Core_Model_Api_Response $response */
88
+ $response = Mage::getModel('cloudiq_core/api_response');
89
+ $response->populate($this->_loadHttpResponseFromFile("testCartauditResponseUnsuccessful.txt"));
90
+
91
+ $this->assertFalse($this->_model->isResponseSuccessful($response));
92
+ }
93
+
94
+ /**
95
+ * @test
96
+ */
97
+ public function testCartauditResponseMissing() {
98
+ /** @var Cloudiq_Core_Model_Api_Response $response */
99
+ $response = Mage::getModel('cloudiq_core/api_response');
100
+ $response->populate($this->_loadHttpResponseFromFile("testCartauditResponseMissing.txt"));
101
+
102
+ $this->assertFalse($this->_model->isResponseSuccessful($response));
103
+ }
104
+
105
+ /**
106
+ * Create a Zend_Http_Response object using raw HTTP response data from the specified file.
107
+ *
108
+ * @param $filename Raw response file, relative to Test/Model/Api/Cartaudit/Store/Cartaudit/data/
109
+ *
110
+ * @return Zend_Http_Response
111
+ */protected function _loadHttpResponseFromFile($filename) {
112
+ $directory_tree = array(
113
+ Mage::getModuleDir('', 'Cloudiq_Cartaudit'),
114
+ 'Test', 'Model', 'Api', 'Cartaudit', 'Store', 'Cartaudit',
115
+ 'data',
116
+ $filename
117
+ );
118
+ $file_path = join(DS, $directory_tree);
119
+
120
+ return Zend_Http_Response::fromString(file_get_contents($file_path));
121
+ }
122
+ }
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testCartauditResponseMissing.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HTTP/1.1 202 Accepted
2
+ Date: Mon, 12 Aug 2013 14:46:37 GMT
3
+ Server: Apache-Coyote/1.1
4
+ X-powered-by: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5
5
+ Content-type: text/html;charset=ISO-8859-1
6
+ Content-length: 276
7
+ Via: 1.1 nimbus.cloud-iq.com
8
+ Connection: Keep-Alive
9
+
10
+ <?xml version="1.0" encoding="utf-8" ?>
11
+ <response status="1">
12
+ <description>Success</description>
13
+ <requestId>300176</requestId>
14
+ <dateTime>2013-08-12T14:46:36Z</dateTime>
15
+ <timeZone>GMT</timeZone>
16
+ </response>
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testCartauditResponseUnsuccessful.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HTTP/1.1 202 Accepted
2
+ Date: Mon, 12 Aug 2013 14:46:37 GMT
3
+ Server: Apache-Coyote/1.1
4
+ X-powered-by: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5
5
+ Content-type: text/html;charset=ISO-8859-1
6
+ Content-length: 276
7
+ Via: 1.1 nimbus.cloud-iq.com
8
+ Connection: Keep-Alive
9
+
10
+ <?xml version="1.0" encoding="utf-8" ?>
11
+ <response status="1">
12
+ <description>Success</description>
13
+ <requestId>300176</requestId>
14
+ <dateTime>2013-08-12T14:46:36Z</dateTime>
15
+ <timeZone>GMT</timeZone>
16
+ <cartAudit status="200">
17
+ <errorMessages></errorMessages>
18
+ </cartAudit>
19
+ </response>
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testResponseSuccessful.txt ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HTTP/1.1 202 Accepted
2
+ Date: Mon, 12 Aug 2013 14:46:37 GMT
3
+ Server: Apache-Coyote/1.1
4
+ X-powered-by: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5
5
+ Content-type: text/html;charset=ISO-8859-1
6
+ Content-length: 276
7
+ Via: 1.1 nimbus.cloud-iq.com
8
+ Connection: Keep-Alive
9
+
10
+ <?xml version="1.0" encoding="utf-8" ?>
11
+ <response status="1">
12
+ <description>Success</description>
13
+ <requestId>300176</requestId>
14
+ <dateTime>2013-08-12T14:46:36Z</dateTime>
15
+ <timeZone>GMT</timeZone>
16
+ <cartAudit status="1">
17
+ <cloudIqTag>&lt;script type=&quot;text/javascript&quot; id=&quot;cloudiq_cartrecovery&quot;&gt;(function(){function e(){var e=document.createElement(&quot;script&quot;);e.type=&quot;text/javascript&quot;;e.async=true;e.src=&quot;http://nimbus.cloud-iq.com/nc_uat_cartrecovery/store.js?app_id=1234&quot;;var t=document.getElementById(&quot;cloudiq_cartrecovery&quot;);t.parentNode.insertBefore(e,t)}if(window.attachEvent)window.attachEvent(&quot;onload&quot;,e);else window.addEventListener(&quot;load&quot;,e,false)})()&lt;/script&gt;</cloudIqTag>
18
+ </cartAudit>
19
+ </response>
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/data/testResponseUnsuccessful.txt ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ HTTP/1.1 202 Accepted
2
+ Date: Mon, 12 Aug 2013 14:44:58 GMT
3
+ Server: Apache-Coyote/1.1
4
+ X-powered-by: Servlet 2.4; JBoss-4.0.5.GA (build: CVSTag=Branch_4_0 date=200610162339)/Tomcat-5.5
5
+ Content-type: text/html;charset=ISO-8859-1
6
+ Content-length: 242
7
+ Via: 1.1 nimbus.cloud-iq.com
8
+ Connection: Keep-Alive
9
+
10
+ <?xml version="1.0" encoding="utf-8" ?>
11
+ <response status="104">
12
+ <description>Request missing a mandatory parameter</description>
13
+ <requestId>300175</requestId>
14
+ <dateTime>2013-08-12T14:44:58Z</dateTime>
15
+ <timeZone>GMT</timeZone>
16
+ </response>
app/code/community/Cloudiq/Cartaudit/Test/Model/Api/Cartaudit/Store/Cartaudit/providers/testRequestRequiredParameter.yaml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -
2
+ - appName
3
+ -
4
+ - websiteUrl
5
+ -
6
+ - cartConfirmationUrl
7
+ -
8
+ - averageCartValue
9
+ -
10
+ - cartsStartedPerMonth
11
+ -
12
+ - cartsCompletedPerMonth
app/code/community/Cloudiq/Cartaudit/Test/Model/Config.php ADDED
@@ -0,0 +1,146 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class Cloudiq_Cartaudit_Test_Model_Config extends EcomDev_PHPUnit_Test_Case {
4
+
5
+ /** @var Cloudiq_Cartaudit_Model_Config $_model */
6
+ protected $_model;
7
+
8
+ public function setUp() {
9
+ $this->_model = Mage::getModel('cloudiq_cartaudit/config');
10
+ }
11
+
12
+ public function tearDown() {
13
+ $this->_model = null;
14
+ }
15
+
16
+ /**
17
+ * @test
18
+ */
19
+ public function testInstance() {
20
+ $this->assertInstanceOf('Cloudiq_Cartaudit_Model_Config', $this->_model);
21
+ }
22
+
23
+ /**
24
+ *
25
+ * @test
26
+ * @loadFixture ~/valid_config.yaml
27
+ */
28
+ public function testLoad() {
29
+ $this->assertEquals('123', Mage::getStoreConfig('cloudiq/cartaudit/app_id'));
30
+ $this->_model->load();
31
+ $this->assertEquals('123', $this->_model->getAppId());
32
+ }
33
+
34
+ /**
35
+ * @test
36
+ * @loadFixture ~/empty_config.yaml
37
+ * @dataProvider dataProvider
38
+ */
39
+ public function testSave($data) {
40
+ $this->_model->setData($data);
41
+ $this->_model->save();
42
+ $this->assertEquals('123', Mage::getStoreConfig('cloudiq/cartaudit/app_id'));
43
+ }
44
+
45
+ /**
46
+ * @test
47
+ * @loadFixture ~/valid_config.yaml
48
+ * @dataProvider dataProvider
49
+ */
50
+ public function testRequiredField($fieldname) {
51
+ $this->_model->load();
52
+
53
+ $this->_model->unsetData($fieldname);
54
+
55
+ $validation_result = $this->_model->validate();
56
+
57
+ $this->assertTrue(is_array($validation_result));
58
+ $this->assertEquals(1, count($validation_result));
59
+ }
60
+
61
+ /**
62
+ * @test
63
+ * @fixture ~/valid_config.yaml
64
+ * @dataProvider dataProvider
65
+ */
66
+ public function testOptionalField($fieldname) {
67
+ $this->_model->load();
68
+
69
+ $this->_model->unsetData($fieldname);
70
+
71
+ $validation_result = $this->_model->validate();
72
+
73
+ $this->assertTrue(is_array($validation_result));
74
+ $this->assertTrue(empty($validation_result));
75
+ }
76
+
77
+ /**
78
+ * @test
79
+ * @fixture ~/valid_config.yaml
80
+ */
81
+ public function testCanEstimateRevenueLost() {
82
+ $this->_model->load();
83
+
84
+ $this->assertTrue($this->_model->canEstimateRevenueLost());
85
+ }
86
+
87
+ /**
88
+ * @test
89
+ * @fixture ~/valid_config.yaml
90
+ * @dataProvider dataProvider
91
+ */
92
+ public function testCanEstimateRevenueLostMissingField($fieldname) {
93
+ $this->_model->load();
94
+
95
+ $this->_model->unsetData($fieldname);
96
+
97
+ $this->assertFalse($this->_model->canEstimateRevenueLost());
98
+ $this->assertNull($this->_model->calculateDropOffRate());
99
+ $this->assertNull($this->_model->calculateRevenueLost());
100
+ }
101
+
102
+ /**
103
+ * @test
104
+ * @dataProvider dataProvider
105
+ */
106
+ public function testCalculateDropOffRate($data, $expected_rate) {
107
+ $this->_model->setData($data);
108
+
109
+ $this->assertTrue($this->_model->canEstimateRevenueLost());
110
+ $this->assertEquals($expected_rate, $this->_model->calculateDropOffRate());
111
+ }
112
+
113
+ /**
114
+ * @test
115
+ * @dataProvider dataProvider
116
+ */
117
+ public function testCalculateRevenueLost($data, $expected_loss) {
118
+ $this->_model->setData($data);
119
+
120
+ $this->assertTrue($this->_model->canEstimateRevenueLost());
121
+ $this->assertEquals($expected_loss, $this->_model->calculateRevenueLost());
122
+ }
123
+
124
+ /**
125
+ * @test
126
+ * @fixture ~/valid_config.yaml
127
+ */
128
+ public function testIsConfigured() {
129
+ $this->_model->load();
130
+
131
+ $this->assertTrue($this->_model->isConfigured());
132
+ }
133
+
134
+ /**
135
+ * @test
136
+ * @fixture ~/valid_config.yaml
137
+ * @dataProvider dataProvider
138
+ */
139
+ public function testIsConfiguredMissingField($fieldname) {
140
+ $this->_model->load();
141
+
142
+ $this->_model->unsetData($fieldname);
143
+
144
+ $this->assertFalse($this->_model->isConfigured());
145
+ }
146
+ }
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCalculateDropOffRate.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ -
2
+ -
3
+ average_cart_value: 250
4
+ carts_started_per_month: 1000
5
+ carts_completed_per_month: 300
6
+ - 70
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCalculateRevenueLost.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ -
2
+ -
3
+ average_cart_value: 250
4
+ carts_started_per_month: 1000
5
+ carts_completed_per_month: 300
6
+ - 175000.00
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testCanEstimateRevenueLostMissingField.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ -
2
+ - average_cart_value
3
+ -
4
+ - carts_started_per_month
5
+ -
6
+ - carts_completed_per_month
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testIsConfiguredMissingField.yaml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ -
2
+ - enabled
3
+ -
4
+ - cloudiq_tag
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testOptionalField.yaml ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ -
2
+ - app_id
3
+ -
4
+ - industry
5
+ -
6
+ - cart_confirmation_url
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testRequiredField.yaml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ -
2
+ - enabled
3
+ -
4
+ - app_name
5
+ -
6
+ - website_url
7
+ -
8
+ - average_cart_value
9
+ -
10
+ - carts_started_per_month
11
+ -
12
+ - carts_completed_per_month
app/code/community/Cloudiq/Cartaudit/Test/Model/Config/providers/testSave.yaml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ -
2
+ -
3
+ enabled: 1
4
+ app_id: 123
5
+ app_name: cloud.IQ
6
+ industry: technology
7
+ website_url: http://www.cloud-iq.com/
8
+ cart_confirmation_url: http://www.cloud-iq.com/checkout/success
9
+ average_cart_value: 9.99
10
+ carts_started_per_month: 100
11
+ carts_completed_per_month: 30
app/code/community/Cloudiq/Cartaudit/Test/fixtures/empty_config.yaml ADDED
@@ -0,0 +1,10 @@
 
 
 
 
 
 
 
 
 
 
1
+ config:
2
+ default/cloudiq/cartaudit/enabled:
3
+ default/cloudiq/cartaudit/app_id:
4
+ default/cloudiq/cartaudit/app_name:
5
+ default/cloudiq/cartaudit/industry:
6
+ default/cloudiq/cartaudit/website_url:
7
+ default/cloudiq/cartaudit/cart_confirmation_url:
8
+ default/cloudiq/cartaudit/average_cart_value:
9
+ default/cloudiq/cartaudit/carts_started_per_month:
10
+ default/cloudiq/cartaudit/carts_completed_per_month:
app/code/community/Cloudiq/Cartaudit/Test/fixtures/valid_config.yaml ADDED
@@ -0,0 +1,11 @@
 
 
 
 
 
 
 
 
 
 
 
1
+ config:
2
+ default/cloudiq/cartaudit/enabled: 1
3
+ default/cloudiq/cartaudit/app_id: 123
4
+ default/cloudiq/cartaudit/cloudiq_tag: test
5
+ default/cloudiq/cartaudit/app_name: cloud.IQ
6
+ default/cloudiq/cartaudit/industry: technology
7
+ default/cloudiq/cartaudit/website_url: http://www.cloud-iq.com/
8
+ default/cloudiq/cartaudit/cart_confirmation_url: http://www.cloud-iq.com/checkout/success
9
+ default/cloudiq/cartaudit/average_cart_value: 9.99
10
+ default/cloudiq/cartaudit/carts_started_per_month: 100
11
+ default/cloudiq/cartaudit/carts_completed_per_month: 30
app/code/community/Cloudiq/Cartaudit/etc/config.xml ADDED
@@ -0,0 +1,74 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Cloudiq_Cartaudit>
5
+ <version>1.0.0</version>
6
+ </Cloudiq_Cartaudit>
7
+ </modules>
8
+
9
+ <global>
10
+ <blocks>
11
+ <cloudiq_cartaudit>
12
+ <class>Cloudiq_Cartaudit_Block</class>
13
+ </cloudiq_cartaudit>
14
+ </blocks>
15
+ <models>
16
+ <cloudiq_cartaudit>
17
+ <class>Cloudiq_Cartaudit_Model</class>
18
+ </cloudiq_cartaudit>
19
+ </models>
20
+ <helpers>
21
+ <cloudiq_cartaudit>
22
+ <class>Cloudiq_Cartaudit_Helper</class>
23
+ </cloudiq_cartaudit>
24
+ </helpers>
25
+
26
+ <resources>
27
+ <cloudiq_cartaudit_setup>
28
+ <setup>
29
+ <module>Cloudiq_Cartaudit</module>
30
+ </setup>
31
+ </cloudiq_cartaudit_setup>
32
+ </resources>
33
+
34
+ <events>
35
+ <cloudiq_core_config_save>
36
+ <observers>
37
+ <cloudiq_cartaudit>
38
+ <type>singleton</type>
39
+ <class>cloudiq_cartaudit/observer</class>
40
+ <method>observeCloudiqCoreConfigSave</method>
41
+ </cloudiq_cartaudit>
42
+ </observers>
43
+ </cloudiq_core_config_save>
44
+ </events>
45
+ </global>
46
+
47
+ <frontend>
48
+ <layout>
49
+ <updates>
50
+ <cloudiq_cartaudit>
51
+ <file>cloudiq/cartaudit.xml</file>
52
+ </cloudiq_cartaudit>
53
+ </updates>
54
+ </layout>
55
+ </frontend>
56
+
57
+ <adminhtml>
58
+ <layout>
59
+ <updates>
60
+ <cloudiq_cartaudit>
61
+ <file>cloudiq/cartaudit.xml</file>
62
+ </cloudiq_cartaudit>
63
+ </updates>
64
+ </layout>
65
+ </adminhtml>
66
+
67
+ <phpunit>
68
+ <suite>
69
+ <modules>
70
+ <Cloudiq_Cartaudit/>
71
+ </modules>
72
+ </suite>
73
+ </phpunit>
74
+ </config>
app/code/community/Cloudiq/Cartaudit/sql/cloudiq_cartaudit_setup/mysql4-install-1.0.0.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /** @var Mage_Core_Model_Resource_Setup $installer */
4
+ $installer = $this;
5
+
6
+ $adapter = $installer->getConnection();
7
+
8
+ /** @var Mage_Core_Model_Store $store */
9
+ $store = Mage::app()->getStore()->resetConfig();
10
+
11
+ $installer->startSetup();
12
+
13
+ /**
14
+ * Set the default values for cartAudit configuration fields
15
+ */
16
+
17
+ $installer->setConfigData('cloudiq/cartaudit/app_name', Mage::getStoreConfig('general/store_information/name', $store));
18
+
19
+ $installer->setConfigData('cloudiq/cartaudit/website_url', $store->getBaseUrl());
20
+
21
+ /** @var Mage_Sales_Model_Resource_Quote_Collection $quotes_collection */
22
+ $quotes_collection = Mage::getResourceModel('sales/quote_collection');
23
+ $quotes_collection
24
+ ->removeAllFieldsFromSelect()
25
+ ->addFieldToSelect(new Zend_Db_Expr('COUNT(DISTINCT(main_table.entity_id))'), 'quote_count')
26
+ ->addFieldToFilter('created_at', array('from' => new Zend_Db_Expr('DATE_SUB(NOW(), INTERVAL 1 MONTH)')))
27
+ ->load();
28
+
29
+ if ($quotes_collection->getFirstItem()) {
30
+ $installer->setConfigData('cloudiq/cartaudit/carts_started_per_month', $quotes_collection->getFirstItem()->getQuoteCount());
31
+ }
32
+
33
+ /** @var Mage_Sales_Model_Resource_Order_Collection $orders_collection */
34
+ $orders_collection = Mage::getResourceModel('sales/order_collection')
35
+ ->removeAllFieldsFromSelect()
36
+ ->addFieldToSelect(new Zend_Db_Expr(sprintf('AVG((%s - %s - %s - (%s - %s - %s)) * %s)',
37
+ 'IFNULL(main_table.base_total_invoiced, 0)',
38
+ 'IFNULL(main_table.base_tax_invoiced, 0)',
39
+ 'IFNULL(main_table.base_shipping_invoiced, 0)',
40
+ 'IFNULL(main_table.base_total_refunded, 0)',
41
+ 'IFNULL(main_table.base_tax_refunded, 0)',
42
+ 'IFNULL(main_table.base_shipping_refunded, 0)',
43
+ 'main_table.base_to_global_rate'
44
+ )), 'average_value')
45
+ ->addFieldToSelect(new Zend_Db_Expr('COUNT(DISTINCT(main_table.entity_id))'), 'order_count')
46
+ ->addFieldToFilter('created_at', array('from' => new Zend_Db_Expr('DATE_SUB(NOW(), INTERVAL 1 MONTH)')))
47
+ ->addFieldToFilter('state', array('neq' => Mage_Sales_Model_Order::STATE_CANCELED))
48
+ ->load();
49
+
50
+ if ($orders_collection->getFirstItem()) {
51
+ $installer->setConfigData('cloudiq/cartaudit/average_cart_value', round($orders_collection->getFirstItem()->getAverageValue(), 2));
52
+ $installer->setConfigData('cloudiq/cartaudit/carts_completed_per_month', $orders_collection->getFirstItem()->getOrderCount());
53
+ }
54
+
55
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/cloudiq/cartaudit.xml ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <adminhtml_cloudiq_edit>
4
+ <reference name="head">
5
+ <action method="addCss"><stylesheet>cloudiq/cartaudit.css</stylesheet></action>
6
+ </reference>
7
+ <reference name="left">
8
+ <reference name="cloudiq.config.edit.tabs">
9
+ <block type="cloudiq_cartaudit/adminhtml_config_edit_tab_cartaudit" name="cloudiq.config.edit.tab.cartaudit">
10
+ <action method="setAfter">
11
+ <after>global_section</after>
12
+ </action>
13
+ </block>
14
+ <action method="addTab">
15
+ <name>cartaudit_section</name>
16
+ <block>cloudiq.config.edit.tab.cartaudit</block>
17
+ </action>
18
+ </reference>
19
+ </reference>
20
+ </adminhtml_cloudiq_edit>
21
+ </layout>
app/design/adminhtml/default/default/template/cloudiq/cartaudit/tab/config.phtml ADDED
@@ -0,0 +1,46 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Form template for the Cloudiq_Cartaudit configuration form.
4
+ *
5
+ * Based on default/default/template/widget/form.phtml
6
+ */
7
+
8
+ /** @var Cloudiq_Cartaudit_Block_Adminhtml_Config_Edit_Tab_Cartaudit $this */
9
+ ?>
10
+ <div class="entry-edit">
11
+ <?php echo $this->getFormHtml();?>
12
+ <?php if($this->_config->canEstimateRevenueLost()): ?>
13
+ <div class="entry-edit-head">
14
+ <h4><?php echo $this->__("Save your details and we'll calculate what you could potentially recover"); ?></h4>
15
+ </div>
16
+ <div class="fieldset">
17
+ <div class="hor-scroll">
18
+ <table cellspacing="0" class="form-list">
19
+ <tbody>
20
+ <tr>
21
+ <td class="label"><?php echo $this->__('Average cart value'); ?></td>
22
+ <td class="value"><?php echo Mage::helper('core')->formatCurrency($this->_config->getAverageCartValue()); ?></td>
23
+ </tr>
24
+ <tr>
25
+ <td class="label"><?php echo $this->__('Carts started per month'); ?></td>
26
+ <td class="value"><?php echo $this->_config->getCartsStartedPerMonth(); ?></td>
27
+ </tr>
28
+ <tr>
29
+ <td class="label"><?php echo $this->__('Carts completed per month'); ?></td>
30
+ <td class="value"><?php echo $this->_config->getCartsCompletedPerMonth(); ?></td>
31
+ </tr>
32
+ <tr>
33
+ <td class="label"><?php echo $this->__('Drop off rate'); ?></td>
34
+ <td class="value"><?php echo round($this->_config->calculateDropOffRate(), 2); ?>%</td>
35
+ </tr>
36
+ <tr>
37
+ <td class="label"><?php echo $this->__('Revenue lost'); ?></td>
38
+ <td class="value"><?php echo Mage::helper('core')->formatCurrency($this->_config->calculateRevenueLost()); ?></td>
39
+ </tr>
40
+ </tbody>
41
+ </table>
42
+ </div>
43
+ </div>
44
+ <?php endif; ?>
45
+ </div>
46
+ <?php echo $this->getChildHtml('form_after');?>
app/design/frontend/base/default/layout/cloudiq/cartaudit.xml ADDED
@@ -0,0 +1,8 @@
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout version="0.1.0">
3
+ <default>
4
+ <reference name="head">
5
+ <block type="cloudiq_cartaudit/tag" name="cloudiq.cartaudit.tag" />
6
+ </reference>
7
+ </default>
8
+ </layout>
app/etc/modules/Cloudiq_Cartaudit.xml ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <Cloudiq_Cartaudit>
5
+ <active>true</active>
6
+ <codePool>community</codePool>
7
+ <depends>
8
+ <Cloudiq_Core/>
9
+ </depends>
10
+ </Cloudiq_Cartaudit>
11
+ </modules>
12
+ </config>
package.xml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>Cloudiq_Cartaudit</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.cloud-iq.com">Commercial License</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>cartAudit extension provides a free interactive dashboard tracking cart abandonment and an option to send recovery emails if you upgrade to a paid account.</summary>
10
+ <description>cartAudit extension provides a free interactive dashboard that collects insights on your abandonment opportunity; how many customers abandon, what %, their average value and the total monthly amount of revenue you could make from these customers with an email re-marketing solution.&#xD;
11
+ &#xD;
12
+ You can choose to upgrade to a paid account and start sending recovery emails, which let you stay in front of mind with your shoppers and convert up to 20% of abandoned shopping carts back to sale. Choose 3 email templates (Abandoned, Reminder and Thank You emails), customise the content and automatically send up to 3 different emails over 3 days.</description>
13
+ <notes>Initial release.</notes>
14
+ <authors><author><name>cloud.IQ</name><user>cloud_iq</user><email>sales@cloud-iq.com</email></author></authors>
15
+ <date>2013-09-09</date>
16
+ <time>09:50:26</time>
17
+ <contents><target name="mageetc"><dir name="modules"><file name="Cloudiq_Cartaudit.xml" hash="25a2c5aab9fa120766c4bf3ad0dd7f9b"/></dir></target><target name="magecommunity"><dir name="Cloudiq"><dir name="Cartaudit"><dir name="Block"><dir name="Adminhtml"><dir name="Config"><dir name="Edit"><dir name="Tab"><file name="Cartaudit.php" hash="c8f44e6aea4b7cde8f689d23aa3d9a2d"/></dir></dir></dir></dir><file name="Tag.php" hash="d8e1be6b9f31f4c22baff50bdbbbf45b"/></dir><dir name="Helper"><file name="Data.php" hash="50e2c29a76b72b743eaf06cb120620e1"/><file name="Options.php" hash="f9b402845065739be2fc0b319bb99e46"/></dir><dir name="Model"><dir name="Api"><dir name="Cartaudit"><dir name="Store"><file name="Cartaudit.php" hash="b23de19d51ece5f37bbb2b807e1f1fa1"/></dir></dir></dir><file name="Config.php" hash="b308bbc04940f99c47a41ecb7f9c66dd"/><file name="Observer.php" hash="ea24f00a1d60a02bb0c6e23dcad53d44"/></dir><dir name="Test"><dir name="Config"><file name="Base.php" hash="963474625856caa73fa42d2da22f2b8e"/></dir><dir name="Model"><dir name="Api"><dir name="Cartaudit"><dir name="Store"><dir name="Cartaudit"><dir name="data"><file name="testCartauditResponseMissing.txt" hash="868a31de60713a6efd4a5820281a3c54"/><file name="testCartauditResponseUnsuccessful.txt" hash="25d6bff811de3bd61460ab5974d055ee"/><file name="testResponseSuccessful.txt" hash="72b62722884addc1a94169a0f33c9aa0"/><file name="testResponseUnsuccessful.txt" hash="fa760fd8fee03b2dd9f3963077dc1e66"/></dir><dir name="providers"><file name="testRequestRequiredParameter.yaml" hash="f5a423e174ffa91e7d4e564d2d2f9ac9"/></dir></dir><file name="Cartaudit.php" hash="230ccec2dfebe6ee298f72dcfcc60c52"/></dir></dir></dir><dir name="Config"><dir name="providers"><file name="testCalculateDropOffRate.yaml" hash="88f2f564d1bd2ffe9eb172e7a0aa4e0e"/><file name="testCalculateRevenueLost.yaml" hash="c1099cc75ddbc1422ec96811712ca495"/><file name="testCanEstimateRevenueLostMissingField.yaml" hash="cccbd0abd5c545ead2e10ec0607ec6e6"/><file name="testIsConfiguredMissingField.yaml" hash="d308de9bca53eb137ae3cdba0d3bc7bc"/><file name="testOptionalField.yaml" hash="5fe30483fc1294eb68b26c317812d4bb"/><file name="testRequiredField.yaml" hash="08fea1caa3ade854450cb0a3243caf46"/><file name="testSave.yaml" hash="2fbe87c14279092a625714f2ec738c38"/></dir></dir><file name="Config.php" hash="b71e64399a3ffaf96ed49a1a0ab8e435"/></dir><dir name="fixtures"><file name="empty_config.yaml" hash="f2efa4bcf3fd5b90f31eb142e6365c90"/><file name="valid_config.yaml" hash="20eb71d95cc1a0993ab6d3e172a53697"/></dir></dir><dir name="etc"><file name="config.xml" hash="427044c5f8af7a8f308a41c169551379"/></dir><dir name="sql"><dir name="cloudiq_cartaudit_setup"><file name="mysql4-install-1.0.0.php" hash="5101bae9da13f7848f676692b51605c1"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><dir name="cloudiq"><file name="cartaudit.xml" hash="8d40d03132f498894f63079cadf6fe3c"/></dir></dir><dir name="template"><dir name="cloudiq"><dir name="cartaudit"><dir name="tab"><file name="config.phtml" hash="80e6628fddb872d91198e7b4316e619f"/></dir></dir></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><dir name="cloudiq"><file name="cartaudit.xml" hash="e994f7046fcf3e9656146092b826cc2d"/></dir></dir></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="cloudiq"><file name="cartaudit.css" hash="70ac2539220031c2a11b72806597e2d2"/></dir></dir></dir></dir></target></contents>
18
+ <compatible/>
19
+ <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php><package><name>Cloudiq_Core</name><channel>community</channel><min>1.0.0</min><max/></package></required></dependencies>
20
+ </package>
skin/adminhtml/default/default/cloudiq/cartaudit.css ADDED
@@ -0,0 +1,3 @@
 
 
 
1
+ #cloudiq_config_edit_tabs_cartaudit_section_content .fieldset td.value input {
2
+ width: 95%;
3
+ }