A4s_Pricemotion - Version 0.2.15

Version Notes

Pricemotion is een prijsvergelijker voor webwinkeliers. Je kunt de prijzen van je concurrenten opvragen in Magento en je hebt prijsregels om prijzen (automatisch) aan te passen

Download this release

Release Info

Developer Sebastian Pruteanu
Extension A4s_Pricemotion
Version 0.2.15
Comparing to
See all releases


Version 0.2.15

Files changed (31) hide show
  1. app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Action/Rules.php +37 -0
  2. app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Grid.php +66 -0
  3. app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Pricerules.php +119 -0
  4. app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Tab.php +192 -0
  5. app/code/local/A4s/Pricemotion/Block/Adminhtml/Form/Element/Errormsg.php +29 -0
  6. app/code/local/A4s/Pricemotion/Block/Adminhtml/Form/Element/Prices.php +43 -0
  7. app/code/local/A4s/Pricemotion/Helper/Catalog/Product/Action.php +57 -0
  8. app/code/local/A4s/Pricemotion/Helper/Data.php +366 -0
  9. app/code/local/A4s/Pricemotion/Model/Mysql4/Rules.php +16 -0
  10. app/code/local/A4s/Pricemotion/Model/Mysql4/Rules/Collection.php +18 -0
  11. app/code/local/A4s/Pricemotion/Model/Observer.php +753 -0
  12. app/code/local/A4s/Pricemotion/Model/Resource/Eav/Mysql4/Setup.php +12 -0
  13. app/code/local/A4s/Pricemotion/Model/Rules.php +23 -0
  14. app/code/local/A4s/Pricemotion/Model/System/Config/Source/Product/Attributes.php +37 -0
  15. app/code/local/A4s/Pricemotion/controllers/Adminhtml/ActionController.php +88 -0
  16. app/code/local/A4s/Pricemotion/etc/config.xml +174 -0
  17. app/code/local/A4s/Pricemotion/etc/system.xml +169 -0
  18. app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-install-0.1.0.php +72 -0
  19. app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.10-0.2.11.php +41 -0
  20. app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.12-0.2.13.php +12 -0
  21. app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.8-0.2.9.php +22 -0
  22. app/design/adminhtml/default/default/layout/pricemotion.xml +26 -0
  23. app/design/adminhtml/default/default/template/pricemotion/mass_price_rules.phtml +47 -0
  24. app/design/adminhtml/default/default/template/pricemotion/price_rules.phtml +41 -0
  25. app/etc/modules/A4s_Pricemotion.xml +9 -0
  26. app/locale/en_US/Pricemotion.csv +33 -0
  27. app/locale/en_US/template/email/pricemotion.html +54 -0
  28. app/locale/nl_NL/Pricemotion.csv +38 -0
  29. app/locale/nl_NL/template/email/pricemotion.html +54 -0
  30. package.xml +18 -0
  31. skin/adminhtml/default/default/pricemotion/pricemotion.css +6 -0
app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Action/Rules.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Mass PriceRules edit
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Action_Rules extends Mage_Adminhtml_Block_Widget_Form_Container {
12
+
13
+ public function __construct() {
14
+ parent::__construct();
15
+ $this->_removeButton('reset');
16
+ $this->_updateButton('back', 'onclick', "setLocation('" . Mage::helper('adminhtml')->getUrl('adminhtml/catalog_product') . "')");
17
+ }
18
+
19
+ /**
20
+ * Retrive header text
21
+ *
22
+ * @return string
23
+ */
24
+ public function getHeaderText() {
25
+ return Mage::helper('pricemotion')->__('Mass Edit PriceRules');
26
+ }
27
+
28
+ /**
29
+ * Retrieve Tag Save URL
30
+ *
31
+ * @return string
32
+ */
33
+ public function getSaveUrl()
34
+ {
35
+ return $this->getUrl('*/*/save', array('_current'=>true));
36
+ }
37
+ }
app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Grid.php ADDED
@@ -0,0 +1,66 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion products grid
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Grid extends Mage_Adminhtml_Block_Catalog_Product_Grid {
12
+
13
+ /**
14
+ * Prepare grid columns. Add 'lowest price' and 'price difference' columns
15
+ *
16
+ * @return Mage_Adminhtml_Block_Widget_Grid
17
+ */
18
+ protected function _prepareColumns() {
19
+ $store = $this->_getStore();
20
+ if(Mage::helper("pricemotion")->getLowestPriceAtt()) {
21
+ $this->addColumnAfter(Mage::helper("pricemotion")->getLowestPriceAtt(),
22
+ array(
23
+ 'header'=> Mage::helper('pricemotion')->__('Lowest Price'),
24
+ 'type' => 'price',
25
+ 'currency_code' => $store->getBaseCurrency()->getCode(),
26
+ 'index' => Mage::helper("pricemotion")->getLowestPriceAtt(),
27
+ 'width' => '100px'
28
+ ), 'sku');
29
+ }
30
+
31
+ if(Mage::helper("pricemotion")->getPriceDiffAtt()) {
32
+ $this->addColumnAfter(Mage::helper("pricemotion")->getPriceDiffAtt(),
33
+ array(
34
+ 'header'=> Mage::helper('pricemotion')->__('Price Difference'),
35
+ 'index' => Mage::helper("pricemotion")->getPriceDiffAtt(),
36
+ 'width' => '100px'
37
+ ), 'sku');
38
+ }
39
+
40
+ $this->addColumnAfter('enable_pricemotion',
41
+ array(
42
+ 'header'=> Mage::helper('pricemotion')->__('Show PriceMotion Prices'),
43
+ 'width' => '70px',
44
+ 'index' => 'enable_pricemotion',
45
+ 'type' => 'options',
46
+ 'options' => Mage::getSingleton('eav/entity_attribute_source_boolean')->getOptionArray(),
47
+ ), 'visibility');
48
+
49
+ $this->sortColumnsByOrder();
50
+ return parent::_prepareColumns();
51
+ }
52
+
53
+ /**
54
+ * Prepare grid massaction actions. Add 'Update PriceMotion Price Rules' action
55
+ *
56
+ * @return A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Grid
57
+ */
58
+ protected function _prepareMassaction() {
59
+ parent::_prepareMassaction();
60
+ $this->getMassactionBlock()->addItem('pm_pricerules', array(
61
+ 'label' => Mage::helper('pricemotion')->__('Update PriceMotion Price Rules'),
62
+ 'url' => $this->getUrl('pricemotion/adminhtml_action/rules', array('_current'=>true))
63
+ ));
64
+ return $this;
65
+ }
66
+ }
app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Pricerules.php ADDED
@@ -0,0 +1,119 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceRules product tab block
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Pricerules
12
+ extends Mage_Adminhtml_Block_Template
13
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface {
14
+
15
+ /**
16
+ * Set the template for the block
17
+ *
18
+ */
19
+ public function _construct()
20
+ {
21
+ parent::_construct();
22
+ $this->setTemplate('pricemotion/price_rules.phtml');
23
+ }
24
+
25
+ /**
26
+ * Get Pricemotion price rules for the current product
27
+ * @return A4s_Pricemotion_Model_Rules
28
+ */
29
+ public function getProductRules() {
30
+ $product_id = Mage::registry('product')->getId();
31
+ return Mage::getModel('pricemotion/rules')->load($product_id, 'product_id');
32
+ }
33
+
34
+ /**
35
+ * Retrieve the label used for the tab relating to this block
36
+ *
37
+ * @return string
38
+ */
39
+ public function getTabLabel()
40
+ {
41
+ return $this->__('PriceMotion Price Rules');
42
+ }
43
+
44
+ /**
45
+ * Retrieve the title used by this tab
46
+ *
47
+ * @return string
48
+ */
49
+ public function getTabTitle()
50
+ {
51
+ return $this->__('PriceMotion Price Rules');
52
+ }
53
+
54
+ /**
55
+ * Determines whether to display the tab
56
+ * Add logic here to decide whether you want the tab to display
57
+ *
58
+ * @return bool
59
+ */
60
+ public function canShowTab()
61
+ {
62
+ $product = Mage::registry('product');
63
+ if($product->getEnablePricemotion()) return true;
64
+ return false;
65
+ }
66
+
67
+ /**
68
+ * Stops the tab being hidden
69
+ *
70
+ * @return bool
71
+ */
72
+ public function isHidden()
73
+ {
74
+ return false;
75
+ }
76
+
77
+ /**
78
+ * AJAX TAB's
79
+ * If you want to use an AJAX tab, uncomment the following functions
80
+ * Please note that you will need to setup a controller to recieve
81
+ * the tab content request
82
+ *
83
+ */
84
+ /**
85
+ * Retrieve the class name of the tab
86
+ * Return 'ajax' here if you want the tab to be loaded via Ajax
87
+ *
88
+ * return string
89
+ */
90
+ # public function getTabClass()
91
+ # {
92
+ # return 'my-custom-tab';
93
+ # }
94
+
95
+ /**
96
+ * Determine whether to generate content on load or via AJAX
97
+ * If true, the tab's content won't be loaded until the tab is clicked
98
+ * You will need to setup a controller to handle the tab request
99
+ *
100
+ * @return bool
101
+ */
102
+ # public function getSkipGenerateContent()
103
+ # {
104
+ # return false;
105
+ # }
106
+
107
+ /**
108
+ * Retrieve the URL used to load the tab content
109
+ * Return the URL here used to load the content by Ajax
110
+ * see self::getSkipGenerateContent & self::getTabClass
111
+ *
112
+ * @return string
113
+ */
114
+ # public function getTabUrl()
115
+ # {
116
+ # return null;
117
+ # }
118
+
119
+ }
app/code/local/A4s/Pricemotion/Block/Adminhtml/Catalog/Product/Tab.php ADDED
@@ -0,0 +1,192 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion product tab block
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Tab
12
+ extends Mage_Adminhtml_Block_Widget_Form
13
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface {
14
+
15
+ /**
16
+ * Set the template for the block
17
+ *
18
+ */
19
+ public function _construct()
20
+ {
21
+ parent::_construct();
22
+ }
23
+
24
+ /**
25
+ * Prepare form before rendering HTML
26
+ *
27
+ * @return Mage_Adminhtml_Block_Widget_Form
28
+ */
29
+
30
+ protected function _prepareForm() {
31
+ $form = new Varien_Data_Form();
32
+
33
+ $fieldset = $form->addFieldset('prices', array(
34
+ 'legend' => Mage::helper('pricemotion')->__('Price Information')
35
+ ));
36
+
37
+ $fieldset->addType('error','A4s_Pricemotion_Block_Adminhtml_Form_Element_Errormsg');
38
+ $fieldset->addType('prices','A4s_Pricemotion_Block_Adminhtml_Form_Element_Prices');
39
+
40
+ $pricemotion_info = Mage::helper('pricemotion')->getPricemotion(Mage::registry('product'));
41
+
42
+ if(!$pricemotion_info['success']) {
43
+ $fieldset->addField('error', 'error', array(
44
+ 'label' => Mage::helper('pricemotion')->__('Error'),
45
+ 'title' => Mage::helper('pricemotion')->__('Error'),
46
+ 'message' => $pricemotion_info['message']
47
+ ));
48
+ } else {
49
+ $fieldset->addField('highest_price', 'text', array(
50
+ 'name' => 'highest_price',
51
+ 'label' => Mage::helper('pricemotion')->__('Highest Price'),
52
+ 'title' => Mage::helper('pricemotion')->__('Highest Price'),
53
+ 'disabled' => true
54
+ ));
55
+
56
+ $fieldset->addField('average_price', 'text', array(
57
+ 'name' => 'average_price',
58
+ 'label' => Mage::helper('pricemotion')->__('Average Price'),
59
+ 'title' => Mage::helper('pricemotion')->__('Average Price'),
60
+ 'disabled' => true
61
+ ));
62
+
63
+ $fieldset->addField('lowest_price', 'text', array(
64
+ 'name' => 'lowest_price',
65
+ 'label' => Mage::helper('pricemotion')->__('Lowest Price'),
66
+ 'title' => Mage::helper('pricemotion')->__('Lowest Price'),
67
+ 'disabled' => true
68
+ ));
69
+
70
+ $fieldset->addField('pricemotion_name', 'text', array(
71
+ 'name' => 'pricemotion_name',
72
+ 'label' => Mage::helper('pricemotion')->__('Pricemotion name'),
73
+ 'title' => Mage::helper('pricemotion')->__('Pricemotion name'),
74
+ 'disabled' => true
75
+ ));
76
+
77
+ $fieldset->addField('pricemotion_ean', 'text', array(
78
+ 'name' => 'pricemotion_ean',
79
+ 'label' => Mage::helper('pricemotion')->__('Pricemotion EAN'),
80
+ 'title' => Mage::helper('pricemotion')->__('Pricemotion EAN'),
81
+ 'disabled' => true
82
+ ));
83
+
84
+ $fieldset->addField('pricemotion_prices', 'prices', array(
85
+ 'name' => 'pricemotion_prices',
86
+ 'label' => Mage::helper('pricemotion')->__('Prices'),
87
+ 'title' => Mage::helper('pricemotion')->__('Prices'),
88
+ 'tablehead' => array(Mage::helper('pricemotion')->__('Vendor'),Mage::helper('pricemotion')->__('Price'))
89
+ ));
90
+
91
+ $form_data['highest_price'] = $pricemotion_info['info']['highest'];
92
+ $form_data['average_price'] = $pricemotion_info['info']['average'];
93
+ $form_data['lowest_price'] = $pricemotion_info['info']['lowest'];
94
+ $form_data['pricemotion_name'] = trim($pricemotion_info['info']['name']);
95
+ $form_data['pricemotion_ean'] = trim($pricemotion_info['info']['ean']);
96
+ $form_data['pricemotion_prices'] = $pricemotion_info['prices'];
97
+
98
+ $form->setValues($form_data);
99
+ }
100
+
101
+ $this->setForm($form);
102
+
103
+ return parent::_prepareForm();
104
+
105
+ }
106
+
107
+ /**
108
+ * Retrieve the label used for the tab relating to this block
109
+ *
110
+ * @return string
111
+ */
112
+ public function getTabLabel()
113
+ {
114
+ return $this->__('PriceMotion Prices');
115
+ }
116
+
117
+ /**
118
+ * Retrieve the title used by this tab
119
+ *
120
+ * @return string
121
+ */
122
+ public function getTabTitle()
123
+ {
124
+ return $this->__('PriceMotion Prices');
125
+ }
126
+
127
+ /**
128
+ * Determines whether to display the tab
129
+ * Add logic here to decide whether you want the tab to display
130
+ *
131
+ * @return bool
132
+ */
133
+ public function canShowTab()
134
+ {
135
+ $product = Mage::registry('product');
136
+ if($product->getEnablePricemotion()) return true;
137
+ return false;
138
+ }
139
+
140
+ /**
141
+ * Stops the tab being hidden
142
+ *
143
+ * @return bool
144
+ */
145
+ public function isHidden()
146
+ {
147
+ return false;
148
+ }
149
+
150
+ /**
151
+ * AJAX TAB's
152
+ * If you want to use an AJAX tab, uncomment the following functions
153
+ * Please note that you will need to setup a controller to recieve
154
+ * the tab content request
155
+ *
156
+ */
157
+ /**
158
+ * Retrieve the class name of the tab
159
+ * Return 'ajax' here if you want the tab to be loaded via Ajax
160
+ *
161
+ * return string
162
+ */
163
+ # public function getTabClass()
164
+ # {
165
+ # return 'my-custom-tab';
166
+ # }
167
+
168
+ /**
169
+ * Determine whether to generate content on load or via AJAX
170
+ * If true, the tab's content won't be loaded until the tab is clicked
171
+ * You will need to setup a controller to handle the tab request
172
+ *
173
+ * @return bool
174
+ */
175
+ # public function getSkipGenerateContent()
176
+ # {
177
+ # return false;
178
+ # }
179
+
180
+ /**
181
+ * Retrieve the URL used to load the tab content
182
+ * Return the URL here used to load the content by Ajax
183
+ * see self::getSkipGenerateContent & self::getTabClass
184
+ *
185
+ * @return string
186
+ */
187
+ # public function getTabUrl()
188
+ # {
189
+ # return null;
190
+ # }
191
+
192
+ }
app/code/local/A4s/Pricemotion/Block/Adminhtml/Form/Element/Errormsg.php ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion element renderer to display errors
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Form_Element_Errormsg extends Varien_Data_Form_Element_Abstract {
12
+ public function __construct($attributes=array())
13
+ {
14
+ parent::__construct($attributes);
15
+ }
16
+
17
+ /**
18
+ * Generates element html
19
+ *
20
+ * @return string
21
+ */
22
+ public function getElementHtml()
23
+ {
24
+ $html = '<ul class="messages"><li class="error-msg"><ul><li><span>';
25
+ $html .= $this->getMessage();
26
+ $html .= '</span></li></ul></li></ul>';
27
+ return $html;
28
+ }
29
+ }
app/code/local/A4s/Pricemotion/Block/Adminhtml/Form/Element/Prices.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion element renderer to display prices
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Block_Adminhtml_Form_Element_Prices extends Varien_Data_Form_Element_Abstract {
12
+ public function __construct($attributes=array())
13
+ {
14
+ parent::__construct($attributes);
15
+ }
16
+
17
+ /**
18
+ * Generates element html
19
+ *
20
+ * @return string
21
+ */
22
+ public function getElementHtml()
23
+ {
24
+ $html = '<div class="grid"><table cellspacing="0" class="data">
25
+ <thead>
26
+ <tr class="headings">';
27
+ foreach($this->getTablehead() as $th) {
28
+ $html .= "<th>{$th}</th>";
29
+ }
30
+ $html .= '<tbody>';
31
+ foreach($this->getValue() as $tr) {
32
+ $html .= "<tr>";
33
+ $html .= "<td>{$tr['seller']}</td>";
34
+ $html .= "<td>{$tr['price']}</td>";
35
+ $html .= "</tr>";
36
+ }
37
+ $html .= '</tbody>';
38
+ $html .= '</tr>
39
+ </thead>';
40
+ $html .= '</table></div>';
41
+ return $html;
42
+ }
43
+ }
app/code/local/A4s/Pricemotion/Helper/Catalog/Product/Action.php ADDED
@@ -0,0 +1,57 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Pricemotion Catalog Product Action Helper
4
+ *
5
+ * @package Pricemotion
6
+ * @copyright Aim4Solutions s.r.l.
7
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
8
+ */
9
+ class A4s_Pricemotion_Helper_Catalog_Product_Action extends Mage_Core_Helper_Data
10
+ {
11
+ /**
12
+ * Selected products for mass-update
13
+ *
14
+ * @var Mage_Catalog_Model_Entity_Product_Collection
15
+ */
16
+ protected $_products;
17
+
18
+
19
+ /**
20
+ * Return product collection with selected product filter
21
+ * Product collection didn't load
22
+ *
23
+ * @return Mage_Catalog_Model_Resource_Eav_Mysql4_Product_Collection
24
+ */
25
+ public function getProducts()
26
+ {
27
+ if (is_null($this->_products)) {
28
+ $productsIds = $this->getProductIds();
29
+
30
+ if (!is_array($productsIds)) {
31
+ $productsIds = array(0);
32
+ }
33
+
34
+ $this->_products = Mage::getResourceModel('catalog/product_collection')
35
+ ->addIdFilter($productsIds);
36
+ }
37
+
38
+ return $this->_products;
39
+ }
40
+
41
+ /**
42
+ * Return array of selected product ids from post or session
43
+ *
44
+ * @return array|null
45
+ */
46
+ public function getProductIds()
47
+ {
48
+ $session = Mage::getSingleton('adminhtml/session');
49
+
50
+ if ($this->_getRequest()->isPost() && $this->_getRequest()->getActionName() == 'rules') {
51
+ $session->setProductIds($this->_getRequest()->getParam('product', null));
52
+ }
53
+
54
+ return $session->getProductIds();
55
+ }
56
+
57
+ }
app/code/local/A4s/Pricemotion/Helper/Data.php ADDED
@@ -0,0 +1,366 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion helper
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+
11
+ class A4s_Pricemotion_Helper_Data extends Mage_Core_Helper_Abstract {
12
+
13
+ /**
14
+ * Url path used to get the ean from the name. The base url will be fetch from config
15
+ */
16
+ const NAME_TO_EAN_URL = "name_to_ean.php";
17
+
18
+ /**
19
+ * Url path used to get the product info based on the ean. The base url will be fetch from config
20
+ */
21
+ const EAN_URL = "&ean=";
22
+
23
+ /**
24
+ * Url path for the name. The base url will be fetch from config
25
+ */
26
+ const NAME_URL = "&name=";
27
+
28
+ /**
29
+ * String to add the serial to the url
30
+ */
31
+ const SERIAL_URL = "?serial=";
32
+
33
+ /**
34
+ * Shortcut to get the NAME_TO_EAN_URL constant
35
+ * @return string
36
+ */
37
+ public static function getNameToEanUrl() {
38
+ return self::NAME_TO_EAN_URL;
39
+ }
40
+
41
+ /**
42
+ * Shortcut to get the EAN_URL constant
43
+ * @return string
44
+ */
45
+ public static function getEanUrl() {
46
+ return self::EAN_URL;
47
+ }
48
+
49
+ /**
50
+ * Shortcut to get the SERIAL_URL constant
51
+ * @return string
52
+ */
53
+ public static function getSerialUrl() {
54
+ return self::SERIAL_URL;
55
+ }
56
+
57
+ /**
58
+ * Get the service url
59
+ * @return string
60
+ */
61
+ public function getServiceUrl() {
62
+ return Mage::getStoreConfig('pricemotion_options/default/url');
63
+ }
64
+
65
+ /**
66
+ * Get the messages url
67
+ * @return string
68
+ */
69
+ public function getMessagesUrl() {
70
+ return Mage::getStoreConfig('pricemotion_options/default/messages_url');
71
+ }
72
+
73
+ /**
74
+ * Get the attributes in which the EAN is saved
75
+ * @return string
76
+ */
77
+ public function getEanAtt() {
78
+ return Mage::getStoreConfig('pricemotion_options/default/ean_att');
79
+ }
80
+
81
+ /**
82
+ * Get the attributes in which the name is saved
83
+ * @return string
84
+ */
85
+ public function getNameAtt() {
86
+ return Mage::getStoreConfig('pricemotion_options/default/name_att');
87
+ }
88
+
89
+ /**
90
+ * Get the attributes in which the price cost is saved
91
+ * @return string
92
+ */
93
+ public function getCostPriceAtt() {
94
+ return Mage::getStoreConfig('pricemotion_options/default/cost_price_att');
95
+ }
96
+
97
+ /**
98
+ * Get the attributes in which the lowest price is saved
99
+ * @return string
100
+ */
101
+ public function getLowestPriceAtt() {
102
+ return Mage::getStoreConfig('pricemotion_options/default/lowestprice_att');
103
+ }
104
+
105
+ /**
106
+ * Get the attributes in which the price difference is saved
107
+ * @return string
108
+ */
109
+ public function getPriceDiffAtt() {
110
+ return Mage::getStoreConfig('pricemotion_options/default/pricediff_att');
111
+ }
112
+
113
+ /**
114
+ * Check if prices should be rounded or not.
115
+ * @return bool
116
+ */
117
+ public function isRoundedPrice() {
118
+ return Mage::getStoreConfig('pricemotion_options/default/rounded_prices');
119
+ }
120
+
121
+ /**
122
+ * Get the Pricemotion serial
123
+ * @return string
124
+ */
125
+ public function getSerial() {
126
+ return Mage::getStoreConfig('pricemotion_options/default/serial');
127
+ }
128
+
129
+ /**
130
+ * Get emails enabled
131
+ * @return string
132
+ */
133
+ public function getEmailsEnabled() {
134
+ return Mage::getStoreConfig('pricemotion_options/emails/enabled');
135
+ }
136
+
137
+ /**
138
+ * Get send email to
139
+ * @return string
140
+ */
141
+ public function getEmailTo() {
142
+ return Mage::getStoreConfig('pricemotion_options/emails/recipient_email');
143
+ }
144
+ /**
145
+ * Get special price config
146
+ * @return boolean
147
+ */
148
+ public function getSpecialPrice() {
149
+ return Mage::getStoreConfig('pricemotion_options/default/special_price');
150
+ }
151
+
152
+ /**
153
+ * Get pricemotion information
154
+ * @param Mage_Catalog_Model_Product $product
155
+ * @return array
156
+ */
157
+ public function getPricemotion($product, $with_currency_symbol = true, $with_seller = true, $display_log = false) {
158
+ $ean_att = $this->getEanAtt();
159
+ $name_att = $this->getNameAtt();
160
+ $service_url = $this->getServiceUrl();
161
+
162
+ $return = array('success' => false);
163
+
164
+ if($ean_att && ($ean = $product->getData($ean_att)) && strlen($ean) > 8) {
165
+ if($display_log) {
166
+ //echo " |Request URL: " . $this->getServiceUrl() . self::SERIAL_URL . $this->getSerial() . self::EAN_URL . urlencode($ean) . "| ";
167
+ }
168
+ $xml_request = $this->getXml($ean);
169
+ } elseif($name_att && ($pname = $product->getData($name_att))) {
170
+ if($display_log) {
171
+ //echo " |Request URL: " . $this->getServiceUrl() . self::NAME_TO_EAN_URL . self::SERIAL_URL . $this->getSerial() . self::NAME_URL . urlencode($pname) . "| ";
172
+ }
173
+ $xml_request = $this->getXml(null, $pname);
174
+ } else {
175
+ $xml_request = array();
176
+ $xml_request['success'] = false;
177
+ $xml_request['message'] = $this->__('Service not available') . ' (Error: E003)';
178
+ }
179
+ if(!$xml_request['success']) {
180
+ $return['message'] = $xml_request['message'];
181
+ } else {
182
+
183
+ if($xml_request['xml']->info->name && $xml_request['xml']->info->ean) {
184
+ $return['success'] = true;
185
+ $return['info'] = array('name' => (string)$xml_request['xml']->info->name, 'ean' => (string)$xml_request['xml']->info->ean);
186
+ $return['prices'] = array();
187
+ $highest = 0;
188
+ $lowest = 0;
189
+ $average = 0;
190
+ foreach ($xml_request['xml']->prices->bezorg->item as $price_item) {
191
+ $price = str_replace(",", ".", (string)$price_item->price);
192
+ if($price > $highest) {
193
+ $highest = $price;
194
+ }
195
+ if($price < $lowest || $lowest == 0) {
196
+ $lowest = $price;
197
+ }
198
+ $average += $price;
199
+ if($with_currency_symbol) {
200
+ $return['prices'][] = array(
201
+ 'seller' => (string)$price_item->seller,
202
+ 'price' => Mage::helper('core')->currency($price, true, false),
203
+ 'cleanPrice' => number_format($price, 2, ".", "")
204
+ );
205
+ } elseif($with_seller) {
206
+ $return['prices'][] = array(
207
+ 'seller' => (string)$price_item->seller,
208
+ 'price' => number_format($price, 2, ".", ""),
209
+ 'cleanPrice'=> number_format($price, 2, ".", "")
210
+ );
211
+ } else {
212
+ $return['prices'][] = number_format($price, 2, ".", "");
213
+ }
214
+ }
215
+
216
+ if($with_currency_symbol || $with_seller) {
217
+ usort($return['prices'], array('self', 'cmpByPrice'));
218
+ } else {
219
+ sort($return['prices']);
220
+ }
221
+
222
+ $average = $average / count($xml_request['xml']->prices->bezorg->item);
223
+ if($with_currency_symbol) {
224
+ $return['info']['average'] = Mage::helper('core')->currency($average, true, false);
225
+ $return['info']['lowest'] = Mage::helper('core')->currency($lowest, true, false);
226
+ $return['info']['highest'] = Mage::helper('core')->currency($highest, true, false);
227
+ } else {
228
+ $return['info']['average'] = number_format($average, 2, ".", "");
229
+ $return['info']['lowest'] = number_format($lowest, 2, ".", "");
230
+ $return['info']['highest'] = number_format($highest, 2, ".", "");
231
+ }
232
+
233
+
234
+ } else {
235
+ $return['message'] = $this->__('Service not available') . ' (Error: E004)';
236
+ }
237
+
238
+ }
239
+ return $return;
240
+ }
241
+
242
+
243
+ /**
244
+ * Compare array by price
245
+ * @param array $a
246
+ * @param array $b
247
+ * @return int
248
+ */
249
+ public function cmpByPrice($a, $b) {
250
+ /*
251
+ if(mb_substr($a['price'], 0, 1, 'UTF-8') == Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol()) {
252
+ $price_a = mb_substr($a['price'], 1, 20, 'UTF-8');
253
+ } else {
254
+ $price_a = $a['price'];
255
+ }
256
+ if(mb_substr($b['price'], 0, 1, 'UTF-8') == Mage::app()->getLocale()->currency(Mage::app()->getStore()->getCurrentCurrencyCode())->getSymbol()) {
257
+ $price_b = mb_substr($b['price'], 1, 20, 'UTF-8');
258
+ } else {
259
+ $price_b = $b['price'];
260
+ }
261
+ */
262
+ $price_a=$a['cleanPrice'];
263
+ $price_b=$b['cleanPrice'];
264
+ $diff = $price_a - $price_b;
265
+ if($diff < 0) {
266
+ return -1;
267
+ } elseif($diff > 0) {
268
+ return 1;
269
+ }
270
+ return 0;
271
+ }
272
+
273
+ /**
274
+ * Get pricemotion xml
275
+ * @param string $ean
276
+ * @param string $name
277
+ * @return array
278
+ */
279
+ public function getXml($ean = null, $name = null) {
280
+
281
+ $return = array("success" => false);
282
+
283
+ if($ean !== null) {
284
+
285
+ $ch = curl_init();
286
+ curl_setopt($ch, CURLOPT_URL, $this->getServiceUrl() . self::SERIAL_URL . $this->getSerial() . self::EAN_URL . urlencode($ean));
287
+ curl_setopt($ch, CURLOPT_HEADER, 0);
288
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
289
+ //Timeout after 5 sec to prevent slow loading
290
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
291
+ $response = curl_exec($ch);
292
+
293
+ curl_close($ch);
294
+
295
+ if($response === false) {
296
+ $return['message'] = $this->__('Service not available') . ' (Error: E001a)';
297
+ } else {
298
+ $response_xml = simplexml_load_string($response);
299
+
300
+ if($response_xml === false) {
301
+ $return['message'] = $this->__('Service not available') . ' (Error: E002) Response: ' . $response;
302
+ } elseif($response_xml->getName() == 'error') {
303
+ $return['message'] = $this->__('Service not available') . ": " . (string)$response_xml . ' (Error: E111)';
304
+ } else {
305
+ $return['success'] = true;
306
+ $return['xml'] = $response_xml;
307
+ }
308
+ }
309
+
310
+ } elseif($name !== null) {
311
+ $ch = curl_init();
312
+ curl_setopt($ch, CURLOPT_URL, $this->getServiceUrl() . self::NAME_TO_EAN_URL . self::SERIAL_URL . $this->getSerial() . self::NAME_URL . urlencode($name));
313
+ curl_setopt($ch, CURLOPT_HEADER, 0);
314
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
315
+ //Timeout after 5 sec to prevent slow loading
316
+ curl_setopt($ch, CURLOPT_TIMEOUT, 15);
317
+ $response = curl_exec($ch);
318
+ curl_close($ch);
319
+
320
+ $name_to_ean_xml = simplexml_load_string($response);
321
+
322
+ if($response === false) {
323
+ //print($this->getServiceUrl() . self::NAME_TO_EAN_URL . self::SERIAL_URL . $this->getSerial() . self::NAME_URL . urlencode($name));
324
+ $return['message'] = $this->__('Service not available') . ' (Error: E001b)';
325
+
326
+ } elseif($name_to_ean_xml === false) {
327
+ $return['message'] = $this->__('Service not available') . ' (Error: E002) Response: ' . $response;
328
+ } elseif($name_to_ean_xml->getName() == 'error') {
329
+ $return['message'] = $this->__('Service not available') . ": " . (string)$name_to_ean_xml . ' (Error: E111)';
330
+ } else {
331
+ $ean_array = (string)$name_to_ean_xml->info->ean;
332
+
333
+ $ean_array = explode(",", $ean_array);
334
+ $ean = $ean_array[0];
335
+
336
+ $ch = curl_init();
337
+ curl_setopt($ch, CURLOPT_URL, $this->getServiceUrl() . self::SERIAL_URL . $this->getSerial() . self::EAN_URL . urlencode($ean));
338
+ curl_setopt($ch, CURLOPT_HEADER, 0);
339
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
340
+ //Timeout after 5 sec to prevent slow loading
341
+ curl_setopt($ch, CURLOPT_TIMEOUT, 10);
342
+ $response = curl_exec($ch);
343
+ curl_close($ch);
344
+
345
+ $response_xml = simplexml_load_string($response);
346
+
347
+ if($response === false) {
348
+ $return['message'] = $this->__('Service not available') . ' (Error: E001c)';
349
+ } elseif($response_xml === false) {
350
+ $return['message'] = $this->__('Service not available') . ' (Error: E002) Response: ' . $response;
351
+ } elseif($response_xml->getName() == 'error') {
352
+ $return['message'] = $this->__('Service not available') . ": " . (string)$response_xml . ' (Error: E111)';
353
+ } else {
354
+ $return['success'] = true;
355
+ $return['xml'] = $response_xml;
356
+ }
357
+ }
358
+ } else {
359
+ $return['message'] = $this->__('Service not available') . ' (Error: E003)';
360
+ }
361
+
362
+ return $return;
363
+
364
+ }
365
+
366
+ }
app/code/local/A4s/Pricemotion/Model/Mysql4/Rules.php ADDED
@@ -0,0 +1,16 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion Price rules mysql4
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_Mysql4_Rules extends Mage_Core_Model_Mysql4_Abstract
11
+ {
12
+ public function _construct()
13
+ {
14
+ $this->_init('pricemotion/rules', 'rule_id');
15
+ }
16
+ }
app/code/local/A4s/Pricemotion/Model/Mysql4/Rules/Collection.php ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion Price rules mysql4 collection
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_Mysql4_Rules_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
11
+ {
12
+ public function _construct()
13
+ {
14
+ parent::_construct();
15
+ $this->_init('pricemotion/rules');
16
+
17
+ }
18
+ }
app/code/local/A4s/Pricemotion/Model/Observer.php ADDED
@@ -0,0 +1,753 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion Observer
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_Observer
11
+ {
12
+
13
+ const XML_PATH_EMAIL_TEMPLATE = 'pricemotion_options/emails/template';
14
+
15
+ public static $display_log = false;
16
+ public static $coll_count = 1;
17
+ public static $email_report = false;
18
+
19
+ /**
20
+ * Get pricemotion messages and push them to adminhtml notification
21
+ * @param Mage_Cron_Model_Schedule $schedule
22
+ */
23
+ public function sendMessages(Mage_Cron_Model_Schedule $schedule)
24
+ {
25
+ $ch = curl_init();
26
+ curl_setopt($ch, CURLOPT_URL, Mage::helper('pricemotion')->getMessagesUrl() . Mage::helper('pricemotion')->getSerialUrl() . Mage::helper('pricemotion')->getSerial());
27
+ curl_setopt($ch, CURLOPT_HEADER, 0);
28
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
29
+ //Timeout after 25 sec to prevent slow loading
30
+ curl_setopt($ch, CURLOPT_TIMEOUT, 25);
31
+ $response = curl_exec($ch);
32
+ curl_close($ch);
33
+ $messages_xml = simplexml_load_string($response);
34
+ if ($response !== false && $messages_xml !== false) {
35
+ $feedData = array();
36
+ foreach ($messages_xml->message as $message) {
37
+ $feedData[] = array(
38
+ "title" => "PriceMotion - " . $message->title,
39
+ "description" => $message->safe_body,
40
+ "severity" => 4,
41
+ "date_added" => date("Y-m-d H:i:s")
42
+ );
43
+ }
44
+ if ($feedData) {
45
+ Mage::getModel('adminnotification/inbox')->parse(array_reverse($feedData));
46
+ }
47
+ }
48
+
49
+ }
50
+
51
+ /**
52
+ * Function that is called when catalog_product_collection_load_before is triggered
53
+ * It is used to add new attributes to the product collection
54
+ * @param Varien_Event_Observer $observer
55
+ */
56
+ public function addToProductCollection(Varien_Event_Observer $observer)
57
+ {
58
+ $collection = $observer->getCollection();
59
+ if (Mage::helper("pricemotion")->getLowestPriceAtt()) {
60
+ $collection->addAttributeToSelect(Mage::helper("pricemotion")->getLowestPriceAtt());
61
+ }
62
+ if (Mage::helper("pricemotion")->getPriceDiffAtt()) {
63
+ $collection->addAttributeToSelect(Mage::helper("pricemotion")->getPriceDiffAtt());
64
+ }
65
+
66
+ $collection->addAttributeToSelect('enable_pricemotion');
67
+
68
+ }
69
+
70
+ /**
71
+ *
72
+ * Callback for the product collection iterator
73
+ * @param array $args
74
+ *
75
+ */
76
+ public static function updateAttributesCallback($args)
77
+ {
78
+ self::$coll_count = self::$coll_count + 1;
79
+ $product = $args;
80
+ $log_file = "pricemotion_log" . date("Y-m-d") . ".log";
81
+ Mage::log('Loaded product ' . $product->getId(), null, $log_file);
82
+ if ($product->getStatus() != "1" && $product->getEnablePricemotion() != "1") {
83
+ Mage::log('SKIPPED: product disabled', null, $log_file);
84
+ } else {
85
+ $pricemotion = Mage::helper('pricemotion')->getPricemotion($product, false, false, true);
86
+ $lowestprice_att = Mage::helper("pricemotion")->getLowestPriceAtt();
87
+ $difference_att = Mage::helper("pricemotion")->getPriceDiffAtt();
88
+ echo "Starting productnr : " . self::$coll_count . " : " . "Product: " . $product->getSku() . " : ";
89
+ self::$email_report .= "Starting productnr : " . self::$coll_count . " : " . "Product: " . $product->getSku() . " : ";
90
+ if ($pricemotion['success']) {
91
+ $lowest_price = $pricemotion['info']['lowest'];
92
+ if ($lowest_price) {
93
+ $product->setData($lowestprice_att, $lowest_price);
94
+ if ($product->getSpecialPrice() && $product->getSpecialPrice() > 0) {
95
+ $price = $product->getSpecialPrice();
96
+ } else {
97
+ $price = $product->getPrice();
98
+ }
99
+ $difference = number_format((($price - $lowest_price) * 100) / $lowest_price, 2, ".", "") . "%";
100
+ Mage::log("Price: {$price}; Lowest price: {$lowest_price}; Difference: {$difference}", null, $log_file);
101
+ //if(self::$display_log) {
102
+ echo " Price: {$price}; Lowest price: {$lowest_price}; Difference: {$difference}\r\n";
103
+ self::$email_report .= " Price: {$price}; Lowest price: {$lowest_price}; Difference: {$difference}\r\n";
104
+ //}
105
+ $product->setData($difference_att, $difference);
106
+ $product->save();
107
+ } else {
108
+ Mage::log('No lowest price', null, $log_file);
109
+ }
110
+ } else {
111
+ Mage::log('Pricemotion error', null, $log_file);
112
+ //if(self::$display_log) {
113
+ echo "Pricemotion error: " . str_replace(array("\r\r\n", "\r", "\r\n", "\t"), ' ', strip_tags($pricemotion['message'])) . "\r\n";
114
+ self::$email_report .= "Pricemotion error: " . str_replace(array("\r\r\n", "\r", "\r\n", "\t"), ' ', strip_tags($pricemotion['message'])) . "\r\n";
115
+ //}
116
+ Mage::log($pricemotion, null, $log_file);
117
+ }
118
+ }
119
+
120
+ }
121
+
122
+ /**
123
+ * Update product attributes (lowestprice and price_difference)
124
+ * @param Mage_Cron_Model_Schedule $schedule
125
+ */
126
+ public function updateAttributes($schedule = false, $display_log = false, $start = false, $end = false, $sku = false)
127
+ {
128
+ if ($display_log) {
129
+ self::$display_log = true;
130
+ }
131
+ $log_file = "pricemotion_log" . date("Y-m-d") . ".log";
132
+ Mage::log('Update attributes cron started', null, $log_file);
133
+ $lowestprice_att = Mage::helper("pricemotion")->getLowestPriceAtt();
134
+ $difference_att = Mage::helper("pricemotion")->getPriceDiffAtt();
135
+ $name_att = Mage::helper("pricemotion")->getNameAtt();
136
+
137
+ if ($lowestprice_att && $difference_att) {
138
+
139
+ echo "Started Loading collection\r\n";
140
+ self::$email_report = "Started Loading collection\r\n";
141
+ $collection = Mage::getModel('catalog/product')
142
+ ->getCollection()
143
+ ->addAttributeToSelect('*');
144
+ if ($sku !== false) {
145
+ $collection->addAttributeToFilter('sku', array('eq' => $sku));
146
+ }
147
+ if ($start !== false && $end !== false) {
148
+ $collection->getSelect()->limit($start, $end);
149
+ }
150
+ $collection->walk("A4s_Pricemotion_Model_Observer::updateAttributesCallback");
151
+ echo "Collection walking ended\r\n";
152
+ self::$email_report .= "Collection walking ended\r\n";
153
+ } else {
154
+ Mage::log('Attributes not set', null, $log_file);
155
+ }
156
+ Mage::log("Update attributes cron ended\r\n", null, $log_file);
157
+
158
+ }
159
+
160
+ /**
161
+ * Function that is called when catalog_product_save_after is triggered
162
+ * @param Varien_Event_Observer $observer
163
+ */
164
+ public function saveRulesData(Varien_Event_Observer $observer)
165
+ {
166
+
167
+ if ($post = Mage::app()->getRequest()->getPost()) {
168
+ $product = Mage::registry('product');
169
+ if (isset($product) && $product && isset($post['pricemotion'])) {
170
+ if ($post['pricemotion']['price_rules'] != 0) {
171
+
172
+ $post_data = $post['pricemotion'];
173
+ $cost_margin_status = ($post_data['cost_margin_enabled'] == 'on') ? 1 : 0;
174
+ $only_email = ($post_data['only_email'] == 'on') ? 1 : 0;
175
+
176
+ $rule_model = Mage::getModel('pricemotion/rules')->load($product->getId(), 'product_id');
177
+ $rule_model->setData('product_id', $product->getId());
178
+ $rule_model->setData('cost_margin_percent', $post_data['cost_margin']);
179
+ $rule_model->setData('cost_margin_status', $cost_margin_status);
180
+ $rule_model->setData('below_average_percent', $post_data['below_average']);
181
+ $rule_model->setData('in_top_value', $post_data['top']);
182
+ $rule_model->setData('only_email', $only_email);
183
+ $rule_model->setData('status', $post_data['price_rules']);
184
+ $rule_model->save();
185
+ } elseif ($post['pricemotion']['price_rules'] == 0) {
186
+ $rule_model = Mage::getModel('pricemotion/rules')->load($product->getId(), 'product_id');
187
+ $rule_model->delete();
188
+ }
189
+ }
190
+ }
191
+
192
+ }
193
+
194
+ /**
195
+ * Get pricemotion price rules and adjust the prices
196
+ * @param Mage_Cron_Model_Schedule $schedule
197
+ */
198
+ public function setPrices($schedule)
199
+ {
200
+ error_reporting(E_ALL);
201
+ ini_set("display_errors", "On");
202
+ $log_file = "pricemotion_log" . date("Y-m-d") . ".log";
203
+ echo 'Cron started\r\n';
204
+ Mage::log('Cron started', null, $log_file);
205
+
206
+ $cron_email = "";
207
+ $collection = Mage::getModel('pricemotion/rules')->getCollection();
208
+ $rules_loaded = count($collection);
209
+ echo 'Collection loaded: ' . count($collection) . ' rules\r\n';
210
+ Mage::log('Collection loaded: ' . count($collection) . ' rules', null, $log_file);
211
+ $special_price = Mage::helper("pricemotion")->getSpecialPrice();
212
+ $active_rules = count($collection);
213
+ $report_table_items = array();
214
+
215
+ if (count($collection)) {
216
+ $cron_email .= "<table border='1'>
217
+ <thead>
218
+ <tr>
219
+ <th>Product ID</th>
220
+ <th>" . Mage::helper('pricemotion')->__("Product name") . "</th>
221
+ <th>" . Mage::helper('pricemotion')->__("Rule type") . "</th>
222
+ <th>" . Mage::helper('pricemotion')->__("Old price") . "</th>
223
+ <th>" . Mage::helper('pricemotion')->__("New price") . "</th>
224
+ </tr>
225
+ </thead><tbody>";
226
+ }
227
+
228
+ foreach ($collection as $rule) {
229
+
230
+ if ($rule->getStatus() == A4s_Pricemotion_Model_Rules::RULE_DISABLED) {
231
+ echo 'Rule ' . $rule->getId() . ' disabled\r\n';
232
+ Mage::log('Rule ' . $rule->getId() . ' disabled', null, $log_file);
233
+ $active_rules--;
234
+ continue;
235
+ }
236
+
237
+ $product = Mage::getModel('catalog/product')->load($rule->getProductId());
238
+
239
+ if(!$product->getEnablePricemotion()) {
240
+ echo 'Product with rule id ' . $rule->getId() . ' is disabled\r\n';
241
+ $active_rules--;
242
+ continue;
243
+ }
244
+
245
+ echo 'Loading pricemotion data for product ' . $rule->getProductId() . '\r\n';
246
+ Mage::log('Loading pricemotion data for product ' . $rule->getProductId(), null, $log_file);
247
+ $pricemotion = Mage::helper('pricemotion')->getPricemotion($product, false, false);
248
+
249
+ if ($pricemotion['success']) {
250
+ echo 'Pricemotion data loaded\r\n';
251
+ Mage::log('Pricemotion data loaded', null, $log_file);
252
+ //$cron_email .= "Pricemotion data loaded for product id: ". $product->getId() ."; name: ". $product->getName() ."\r\n";
253
+ if ($special_price && $product->getSpecialPrice() && $product->getSpecialPrice() > 0) {
254
+ $product_price = $product->getSpecialPrice();
255
+ } else {
256
+ $product_price = $product->getPrice();
257
+ }
258
+ $min_price = 0;
259
+ echo 'Checking margin on cost\r\n';
260
+ Mage::log('Checking margin on cost', null, $log_file);
261
+ if ($rule->getCostMarginStatus()) {
262
+ $cost_price_att = Mage::helper("pricemotion")->getCostPriceAtt();
263
+ $cost_price = $product->getData($cost_price_att);
264
+ if (!$cost_price) {
265
+ echo 'Rule skipped: no cost price\r\n';
266
+ Mage::log('Rule skipped: no cost price', null, $log_file);
267
+ $report_table_items[] = array(
268
+ "id" => $product->getId(),
269
+ "name" => $product->getName(),
270
+ "error" => Mage::helper('pricemotion')->__('Cost price not set')
271
+ );
272
+ continue;
273
+ }
274
+ $cost_margin = $rule->getCostMarginPercent();
275
+ $min_price = $cost_price + ($cost_price * ($cost_margin / 100));
276
+ $min_price = number_format($min_price, 4, '.', '');
277
+ }
278
+
279
+ //Appling price rules
280
+ switch ($rule->getStatus()) {
281
+
282
+ case A4s_Pricemotion_Model_Rules::LOWEST_PRICE:
283
+ echo 'Rule lowest price\r\n';
284
+ Mage::log('Rule lowest price', null, $log_file);
285
+ sort($pricemotion['prices']);
286
+ if (count($pricemotion['prices'])) {
287
+ $new_price = $pricemotion['prices'][0];
288
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
289
+ $new_price = round($new_price);
290
+ }
291
+
292
+ $new_price = number_format($new_price, 4, '.', '');
293
+ echo 'New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price . '\r\n';
294
+ Mage::log('New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price, null, $log_file);
295
+
296
+ if ($new_price > $min_price) {
297
+ echo 'New price ' . $new_price . ' set\r\n';
298
+ Mage::log('New price ' . $new_price . ' set', null, $log_file);
299
+ if ($new_price != $product_price) {
300
+ $change_price = true;
301
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
302
+ if ($rule->getOnlyEmail()) {
303
+ $change_price = false;
304
+ $status = Mage::helper('pricemotion')->__("Notificatie");
305
+ }
306
+ $cron_email .= "<tr>
307
+ <td>" . $product->getId() . "</td>
308
+ <td>" . $product->getName() . "</td>
309
+ <td>" . Mage::helper('pricemotion')->__("lowest price") . "</td>
310
+ <td>" . $product_price . "</td>
311
+ <td>" . $new_price . "</td>
312
+ </tr>";
313
+ $report_table_items[] = array(
314
+ "id" => $product->getId(),
315
+ "name" => $product->getName(),
316
+ "type" => "lowest price",
317
+ "price" => $product_price,
318
+ "new_price" => $new_price,
319
+ "min_price" => $min_price,
320
+ "status" => $status
321
+ );
322
+ if ($change_price) {
323
+ if ($special_price) {
324
+ $product->setSpecialPrice($new_price);
325
+ } else {
326
+ $product->setPrice($new_price);
327
+ }
328
+ $product->save();
329
+ }
330
+ } else {
331
+ $report_table_items[] = array(
332
+ "id" => $product->getId(),
333
+ "name" => $product->getName(),
334
+ "type" => "lowest price",
335
+ "price" => $product_price,
336
+ "new_price" => $new_price,
337
+ "min_price" => $min_price,
338
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
339
+ );
340
+ }
341
+
342
+ } elseif ($min_price > 0) {
343
+ echo 'Min price set\r\n';
344
+ Mage::log('Min price set', null, $log_file);
345
+ //$cron_email .= "Min price set\r\n";
346
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
347
+ $min_price = round($min_price);
348
+ }
349
+ if ($min_price != $product_price) {
350
+ $change_price = true;
351
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
352
+ if ($rule->getOnlyEmail()) {
353
+ $change_price = false;
354
+ $status = Mage::helper('pricemotion')->__("Notificatie");
355
+ }
356
+ $cron_email .= "<tr>
357
+ <td>" . $product->getId() . "</td>
358
+ <td>" . $product->getName() . "</td>
359
+ <td>" . Mage::helper('pricemotion')->__("lowest price") . "</td>
360
+ <td>" . $product_price . "</td>
361
+ <td>" . $min_price . "</td>
362
+ </tr>";
363
+
364
+ $report_table_items[] = array(
365
+ "id" => $product->getId(),
366
+ "name" => $product->getName(),
367
+ "type" => "lowest price",
368
+ "price" => $product_price,
369
+ "new_price" => $min_price,
370
+ "min_price" => $min_price,
371
+ "status" => $status
372
+ );
373
+ if ($change_price) {
374
+ if ($special_price) {
375
+ $product->setSpecialPrice($min_price);
376
+ } else {
377
+ $product->setPrice($min_price);
378
+ }
379
+ $product->save();
380
+ }
381
+ } else {
382
+ $report_table_items[] = array(
383
+ "id" => $product->getId(),
384
+ "name" => $product->getName(),
385
+ "type" => "lowest price",
386
+ "price" => $product_price,
387
+ "new_price" => $min_price,
388
+ "min_price" => $min_price,
389
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
390
+ );
391
+ }
392
+ } else {
393
+ echo 'No price set (1)\r\n';
394
+ Mage::log('No price set (1)', null, $log_file);
395
+ $report_table_items[] = array(
396
+ "id" => $product->getId(),
397
+ "name" => $product->getName(),
398
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
399
+ );
400
+ //$cron_email .= "No price was set\r\n";
401
+ }
402
+ } else {
403
+ echo 'No price set (2)\r\n';
404
+ Mage::log('No price set (2)', null, $log_file);
405
+ $report_table_items[] = array(
406
+ "id" => $product->getId(),
407
+ "name" => $product->getName(),
408
+ "error" => Mage::helper('pricemotion')->__('Pricemotion data not available')
409
+ );
410
+ //$cron_email .= "No price was set\r\n";
411
+ }
412
+ break;
413
+
414
+ case A4s_Pricemotion_Model_Rules::RULE_BELOW_AVERAGE:
415
+ echo 'Rule below average\r\n';
416
+ Mage::log('Rule below average', null, $log_file);
417
+ //$cron_email .= "Rule 'below avegare'\r\n";
418
+ if ($pricemotion['info']['average']) {
419
+ $below_average_percent = $rule->getBelowAveragePercent();
420
+ $new_price = $pricemotion['info']['average'] - ($pricemotion['info']['average'] * ($below_average_percent / 100));
421
+ $new_price = number_format($new_price, 4, '.', '');
422
+ echo 'New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price . '\r\n';
423
+ Mage::log('New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price, null, $log_file);
424
+ //$cron_email .= 'New price: ' . $new_price . '; Min price: ' . $min_price . "\r\n";
425
+ if ($new_price > $min_price) {
426
+ echo 'New price set\r\n';
427
+ Mage::log('New price set', null, $log_file);
428
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
429
+ $new_price = round($new_price);
430
+ }
431
+ //$cron_email .= "New price set\r\n";
432
+ if ($new_price != $product_price) {
433
+ $change_price = true;
434
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
435
+ if ($rule->getOnlyEmail()) {
436
+ $change_price = false;
437
+ $status = Mage::helper('pricemotion')->__("Notificatie");
438
+ }
439
+ $cron_email .= "<tr>
440
+ <td>" . $product->getId() . "</td>
441
+ <td>" . $product->getName() . "</td>
442
+ <td>" . Mage::helper('pricemotion')->__("below average") . "</td>
443
+ <td>" . $product_price . "</td>
444
+ <td>" . $new_price . "</td>
445
+ </tr>";
446
+ $report_table_items[] = array(
447
+ "id" => $product->getId(),
448
+ "name" => $product->getName(),
449
+ "type" => "onder de gemiddelde prijs",
450
+ "price" => $product_price,
451
+ "new_price" => $new_price,
452
+ "min_price" => $min_price,
453
+ "status" => $status
454
+ );
455
+ if ($change_price) {
456
+ if ($special_price) {
457
+ $product->setSpecialPrice($new_price);
458
+ } else {
459
+ $product->setPrice($new_price);
460
+ }
461
+ $product->save();
462
+ }
463
+ } else {
464
+ $report_table_items[] = array(
465
+ "id" => $product->getId(),
466
+ "name" => $product->getName(),
467
+ "type" => "onder de gemiddelde prijs",
468
+ "price" => $product_price,
469
+ "new_price" => $new_price,
470
+ "min_price" => $min_price,
471
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
472
+ );
473
+ }
474
+ } elseif ($min_price > 0) {
475
+ echo 'Min price set\r\n';
476
+ Mage::log('Min price set', null, $log_file);
477
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
478
+ $min_price = round($min_price);
479
+ }
480
+ //$cron_email .= "Min price set\r\n";
481
+ if ($min_price != $product_price) {
482
+ $change_price = true;
483
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
484
+ if ($rule->getOnlyEmail()) {
485
+ $change_price = false;
486
+ $status = Mage::helper('pricemotion')->__("Notificatie");
487
+ }
488
+ $cron_email .= "<tr>
489
+ <td>" . $product->getId() . "</td>
490
+ <td>" . $product->getName() . "</td>
491
+ <td>" . Mage::helper('pricemotion')->__("below average") . "</td>
492
+ <td>" . $product_price . "</td>
493
+ <td>" . $min_price . "</td>
494
+ </tr>";
495
+ $report_table_items[] = array(
496
+ "id" => $product->getId(),
497
+ "name" => $product->getName(),
498
+ "type" => "onder de gemiddelde prijs",
499
+ "price" => $product_price,
500
+ "new_price" => $min_price,
501
+ "min_price" => $min_price,
502
+ "status" => $status
503
+ );
504
+ if ($change_price) {
505
+ if ($special_price) {
506
+ $product->setSpecialPrice($min_price);
507
+ } else {
508
+ $product->setPrice($min_price);
509
+ }
510
+ $product->save();
511
+ }
512
+ } else {
513
+ $report_table_items[] = array(
514
+ "id" => $product->getId(),
515
+ "name" => $product->getName(),
516
+ "type" => "onder de gemiddelde prijs",
517
+ "price" => $product_price,
518
+ "new_price" => $new_price,
519
+ "min_price" => $min_price,
520
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
521
+ );
522
+ }
523
+ } else {
524
+ echo 'No price set (1)\r\n';
525
+ Mage::log('No price set (1)', null, $log_file);
526
+ $report_table_items[] = array(
527
+ "id" => $product->getId(),
528
+ "name" => $product->getName(),
529
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
530
+ );
531
+ //$cron_email .= "No price was set\r\n";
532
+ }
533
+
534
+ } else {
535
+ echo 'No price set (2)\r\n';
536
+ Mage::log('No price set (2)', null, $log_file);
537
+ $report_table_items[] = array(
538
+ "id" => $product->getId(),
539
+ "name" => $product->getName(),
540
+ "error" => Mage::helper('pricemotion')->__('Pricemotion data not available')
541
+ );
542
+ //$cron_email .= "No price was set\r\n";
543
+ }
544
+ break;
545
+ case A4s_Pricemotion_Model_Rules::RULE_IN_TOP:
546
+ echo 'Rule in top\r\n';
547
+ Mage::log('Rule in top', null, $log_file);
548
+ //$cron_email .= "Rule 'in top'\r\n";
549
+ sort($pricemotion['prices']);
550
+ if (count($pricemotion['prices'])) {
551
+ $array_position = $rule->getInTopValue() - 1;
552
+ if (isset($pricemotion['prices'][$array_position])) {
553
+ $top_price = $pricemotion['prices'][$array_position];
554
+ $new_price = $top_price - 0.01;
555
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
556
+ $new_price = floor($new_price);
557
+ }
558
+ } else {
559
+ $top_price = end($pricemotion['prices']);
560
+ $new_price = $top_price + 0.01;
561
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
562
+ $new_price = ceil($new_price);
563
+ }
564
+ }
565
+ //$product_price=str_replace(',', '', $product_price);
566
+ $new_price = number_format($new_price, 4, '.', '');
567
+ echo 'New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price . '\r\n';
568
+ Mage::log('New price: ' . $new_price . '; Min price: ' . $min_price . '; Old price: ' . $product_price, null, $log_file);
569
+ //$cron_email .= 'New price: ' . $new_price . '; Min price: ' . $min_price . "\r\n";
570
+ if ($new_price > $min_price) {
571
+ echo 'New price ' . $new_price . ' set\r\n';
572
+ Mage::log('New price ' . $new_price . ' set', null, $log_file);
573
+ if ($new_price != $product_price) {
574
+ $change_price = true;
575
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
576
+ if ($rule->getOnlyEmail()) {
577
+ $change_price = false;
578
+ $status = Mage::helper('pricemotion')->__("Notificatie");
579
+ }
580
+ $cron_email .= "<tr>
581
+ <td>" . $product->getId() . "</td>
582
+ <td>" . $product->getName() . "</td>
583
+ <td>" . Mage::helper('pricemotion')->__("in top") . "</td>
584
+ <td>" . $product_price . "</td>
585
+ <td>" . $new_price . "</td>
586
+ </tr>";
587
+ $report_table_items[] = array(
588
+ "id" => $product->getId(),
589
+ "name" => $product->getName(),
590
+ "type" => "top",
591
+ "price" => $product_price,
592
+ "new_price" => $new_price,
593
+ "min_price" => $min_price,
594
+ "status" => $status
595
+ );
596
+ if ($change_price) {
597
+ if ($special_price) {
598
+ $product->setSpecialPrice($new_price);
599
+ } else {
600
+ $product->setPrice($new_price);
601
+ }
602
+ $product->save();
603
+ }
604
+ } else {
605
+ $report_table_items[] = array(
606
+ "id" => $product->getId(),
607
+ "name" => $product->getName(),
608
+ "type" => "top",
609
+ "price" => $product_price,
610
+ "new_price" => $new_price,
611
+ "min_price" => $min_price,
612
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
613
+ );
614
+ }
615
+
616
+ } elseif ($min_price > 0) {
617
+ echo 'Min price set\r\n';
618
+ Mage::log('Min price set', null, $log_file);
619
+ //$cron_email .= "Min price set\r\n";
620
+ if (Mage::helper('pricemotion')->isRoundedPrice()) {
621
+ $min_price = round($min_price);
622
+ }
623
+ if ($min_price != $product_price) {
624
+ $change_price = true;
625
+ $status = Mage::helper('pricemotion')->__("Prijs gewijzigd");
626
+ if ($rule->getOnlyEmail()) {
627
+ $change_price = false;
628
+ $status = Mage::helper('pricemotion')->__("Notificatie");
629
+ }
630
+ $cron_email .= "<tr>
631
+ <td>" . $product->getId() . "</td>
632
+ <td>" . $product->getName() . "</td>
633
+ <td>" . Mage::helper('pricemotion')->__("in top") . "</td>
634
+ <td>" . $product_price . "</td>
635
+ <td>" . $min_price . "</td>
636
+ </tr>";
637
+
638
+ $report_table_items[] = array(
639
+ "id" => $product->getId(),
640
+ "name" => $product->getName(),
641
+ "type" => "top",
642
+ "price" => $product_price,
643
+ "new_price" => $min_price,
644
+ "min_price" => $min_price,
645
+ "status" => $status
646
+ );
647
+ if ($change_price) {
648
+ if ($special_price) {
649
+ $product->setSpecialPrice($min_price);
650
+ } else {
651
+ $product->setPrice($min_price);
652
+ }
653
+ $product->save();
654
+ }
655
+ } else {
656
+ $report_table_items[] = array(
657
+ "id" => $product->getId(),
658
+ "name" => $product->getName(),
659
+ "type" => "top",
660
+ "price" => $product_price,
661
+ "new_price" => $min_price,
662
+ "min_price" => $min_price,
663
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
664
+ );
665
+ }
666
+ } else {
667
+ echo 'No price set (1)\r\n';
668
+ Mage::log('No price set (1)', null, $log_file);
669
+ $report_table_items[] = array(
670
+ "id" => $product->getId(),
671
+ "name" => $product->getName(),
672
+ "error" => Mage::helper('pricemotion')->__('Geen wijziging')
673
+ );
674
+ //$cron_email .= "No price was set\r\n";
675
+ }
676
+ } else {
677
+ echo 'No price set (2)\r\n';
678
+ Mage::log('No price set (2)', null, $log_file);
679
+ $report_table_items[] = array(
680
+ "id" => $product->getId(),
681
+ "name" => $product->getName(),
682
+ "error" => Mage::helper('pricemotion')->__('Pricemotion data not available')
683
+ );
684
+ //$cron_email .= "No price was set\r\n";
685
+ }
686
+ break;
687
+ default:
688
+ break;
689
+ }
690
+
691
+ } else {
692
+ echo 'Pricemotion data not loaded\r\n';
693
+ Mage::log('Pricemotion data not loaded', null, $log_file);
694
+ //$cron_email .= "Pricemotion data could not be loaded for product ". $rule->getProductId() ."\r\n";
695
+ /*$cron_email .= "<tr>
696
+ <td>".$rule->getProductId()."</td>
697
+ <td colspan='4'>". Mage::helper('pricemotion')->__("Pricemotion data could not be loaded") ."</td>
698
+ </tr>";*/
699
+ $report_table_items[] = array(
700
+ "id" => $product->getId(),
701
+ "name" => $product->getName(),
702
+ "error" => Mage::helper('pricemotion')->__('Pricemotion data could not loaded')
703
+ );
704
+ }
705
+ //$cron_email .= "\r\n";
706
+ }
707
+
708
+ $cron_email = Mage::helper('pricemotion')->__("Cron Started") . "<br/>" . Mage::helper('pricemotion')->__("Loaded %s rules", $active_rules) . "<br/>" . $cron_email;
709
+
710
+ echo "Cron ended\r\n";
711
+ Mage::log("Cron ended\r\n", null, $log_file);
712
+ //$cron_email .= "Cron ended\r\n";
713
+ $cron_email .= "</tbody></table>";
714
+
715
+ if (Mage::helper("pricemotion")->getEmailsEnabled() && Mage::helper("pricemotion")->getEmailTo() && $active_rules > 0) {
716
+ $email = Mage::helper("pricemotion")->getEmailTo();
717
+ $sender = array('name' => Mage::getStoreConfig("trans_email/ident_general/name"),
718
+ 'email' => Mage::getStoreConfig("trans_email/ident_general/email"));
719
+
720
+ $translate = Mage::getSingleton('core/translate');
721
+ /* @var $translate Mage_Core_Model_Translate */
722
+ $translate->setTranslateInline(false);
723
+
724
+ $storeId = Mage::app()->getStore()->getId();
725
+
726
+ try {
727
+ Mage::getModel('core/email_template')
728
+ ->setDesignConfig(array('area' => 'frontend', 'store' => $storeId))
729
+ ->sendTransactional(
730
+ Mage::getStoreConfig(self::XML_PATH_EMAIL_TEMPLATE, $storeId),
731
+ $sender,
732
+ $email,
733
+ "",
734
+ array(
735
+ "date" => date("Y-m-d H:i:s"),
736
+ "rules_loaded" => $active_rules,
737
+ "items" => $report_table_items
738
+ )
739
+ );
740
+
741
+ $translate->setTranslateInline(true);
742
+ echo "Mail Sent!";
743
+ } catch (Exception $e) {
744
+ echo "Mail error: ";
745
+ echo $e->getMessage();
746
+ }
747
+
748
+ }
749
+
750
+ }
751
+
752
+ }
753
+
app/code/local/A4s/Pricemotion/Model/Resource/Eav/Mysql4/Setup.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion Price attributes
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Izabella Papp <izabella@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_Resource_Eav_Mysql4_Setup extends Mage_Eav_Model_Entity_Setup
11
+ {
12
+ }
app/code/local/A4s/Pricemotion/Model/Rules.php ADDED
@@ -0,0 +1,23 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion Rules model
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_Rules extends Mage_Core_Model_Abstract
11
+ {
12
+
13
+ const RULE_DISABLED = 0;
14
+ const RULE_BELOW_AVERAGE = 1;
15
+ const RULE_IN_TOP = 2;
16
+ const LOWEST_PRICE = 3;
17
+
18
+ public function _construct()
19
+ {
20
+ parent::_construct();
21
+ $this->_init('pricemotion/rules');
22
+ }
23
+ }
app/code/local/A4s/Pricemotion/Model/System/Config/Source/Product/Attributes.php ADDED
@@ -0,0 +1,37 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * PriceMotion System config source model to get product attributes
5
+ *
6
+ * @package Pricemotion
7
+ * @copyright Aim4Solutions s.r.l.
8
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
9
+ */
10
+ class A4s_Pricemotion_Model_System_Config_Source_Product_Attributes
11
+ {
12
+
13
+ /**
14
+ * Returns a list of attributes as an array for select options
15
+ *
16
+ * @access public
17
+ * @return array
18
+ */
19
+ public function toOptionArray()
20
+ {
21
+
22
+ $product = Mage::getModel('catalog/product');
23
+ $attributes = $attributes = Mage::getResourceModel('eav/entity_attribute_collection')
24
+ ->setEntityTypeFilter($product->getResource()->getTypeId());
25
+
26
+ $attributes_array = array();
27
+ $attributes_array[] = array("value" => '', 'label' => '--');
28
+ foreach ($attributes as $attr) {
29
+ $attributes_array[] = array("value" => $attr['attribute_code'], 'label' => $attr['frontend_label']);
30
+ }
31
+ return $attributes_array;
32
+
33
+ }
34
+
35
+ }
36
+
37
+ ?>
app/code/local/A4s/Pricemotion/controllers/Adminhtml/ActionController.php ADDED
@@ -0,0 +1,88 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class A4s_Pricemotion_Adminhtml_ActionController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ /**
6
+ * Action controller rules action
7
+ */
8
+ public function rulesAction()
9
+ {
10
+ if (!$this->_validateProducts()) {
11
+ return;
12
+ }
13
+
14
+ $this->_title($this->__('PriceMotion'))
15
+ ->_title($this->__('Mass Update PriceRules'));
16
+ $this->loadLayout()->renderLayout();
17
+ }
18
+
19
+ /**
20
+ * Action controller save action
21
+ */
22
+ public function saveAction()
23
+ {
24
+ if (!$this->_validateProducts()) {
25
+ return;
26
+ }
27
+ $post = $this->getRequest()->getParams();
28
+ $post_data = $post['pricemotion'];
29
+ $productIds = $this->_getHelper()->getProductIds();
30
+ try {
31
+ foreach ($productIds as $product_id) {
32
+ $cost_margin_status = ($post_data['cost_margin_enabled'] == 'on') ? 1 : 0;
33
+ $only_email = ($post_data['only_email'] == 'on') ? 1 : 0;
34
+
35
+ $rule_model = Mage::getModel('pricemotion/rules')->load($product_id, 'product_id');
36
+ $rule_model->setData('product_id', $product_id);
37
+ $rule_model->setData('cost_margin_percent', $post_data['cost_margin']);
38
+ $rule_model->setData('cost_margin_status', $cost_margin_status);
39
+ $rule_model->setData('below_average_percent', $post_data['below_average']);
40
+ $rule_model->setData('in_top_value', $post_data['top']);
41
+ $rule_model->setData('only_email', $only_email);
42
+ $rule_model->setData('status', $post_data['price_rules']);
43
+ $rule_model->save();
44
+ }
45
+ $this->_getSession()->addSuccess(
46
+ $this->__('Total of %d record(s) were updated', count($this->_getHelper()->getProductIds()))
47
+ );
48
+ } catch (Mage_Core_Exception $e) {
49
+ $this->_getSession()->addError($e->getMessage());
50
+ }
51
+ catch (Exception $e) {
52
+ $this->_getSession()->addException($e, $this->__('An error occurred while updating the product(s) price rules.'));
53
+ }
54
+ $this->_redirect('adminhtml/catalog_product', array('_current'=>true));
55
+ }
56
+
57
+ /**
58
+ * Rertive data manipulation helper
59
+ *
60
+ * @return A4s_Pricemotion_Helper_Catalog_Product_Action
61
+ */
62
+ protected function _getHelper()
63
+ {
64
+ return Mage::helper('pricemotion/catalog_product_action');
65
+ }
66
+
67
+ /**
68
+ * Validate selection of products for massupdate
69
+ *
70
+ * @return boolean
71
+ */
72
+ protected function _validateProducts()
73
+ {
74
+ $error = false;
75
+ $productIds = $this->_getHelper()->getProductIds();
76
+ if (!is_array($productIds)) {
77
+ $error = $this->__('Please select products for price rules update');
78
+ }
79
+
80
+ if ($error) {
81
+ $this->_getSession()->addError($error);
82
+ $this->_redirect(Mage::helper('adminhtml')->getUrl('adminhtml/catalog_product'), array('_current'=>true));
83
+ }
84
+
85
+ return !$error;
86
+ }
87
+
88
+ }
app/code/local/A4s/Pricemotion/etc/config.xml ADDED
@@ -0,0 +1,174 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <A4s_Pricemotion>
5
+ <version>0.2.15</version>
6
+ </A4s_Pricemotion>
7
+ </modules>
8
+ <global>
9
+ <blocks>
10
+ <pricemotion>
11
+ <class>A4s_Pricemotion_Block</class>
12
+ </pricemotion>
13
+ <adminhtml>
14
+ <rewrite>
15
+ <catalog_product_grid>A4s_Pricemotion_Block_Adminhtml_Catalog_Product_Grid</catalog_product_grid>
16
+ </rewrite>
17
+ </adminhtml>
18
+ </blocks>
19
+ <models>
20
+ <pricemotion>
21
+ <class>A4s_Pricemotion_Model</class>
22
+ <resourceModel>pricemotion_mysql4</resourceModel>
23
+ </pricemotion>
24
+ <pricemotion_mysql4>
25
+ <class>A4s_Pricemotion_Model_Mysql4</class>
26
+ <entities>
27
+ <rules>
28
+ <table>pricemotion_rules</table>
29
+ </rules>
30
+ </entities>
31
+ </pricemotion_mysql4>
32
+ </models>
33
+ <helpers>
34
+ <pricemotion><class>A4s_Pricemotion_Helper</class></pricemotion>
35
+ </helpers>
36
+ <resources>
37
+ <pricemotion_setup>
38
+ <setup>
39
+ <module>A4s_Pricemotion</module>
40
+ <class>A4s_Pricemotion_Model_Resource_Eav_Mysql4_Setup</class>
41
+ </setup>
42
+ <connection>
43
+ <use>core_setup</use>
44
+ </connection>
45
+ </pricemotion_setup>
46
+ <pricemotion_write>
47
+ <connection>
48
+ <use>core_write</use>
49
+ </connection>
50
+ </pricemotion_write>
51
+ <pricemotion_read>
52
+ <connection>
53
+ <use>core_read</use>
54
+ </connection>
55
+ </pricemotion_read>
56
+ </resources>
57
+ <template>
58
+ <email>
59
+ <pricemotion_options_emails_template translate="label" module="pricemotion">
60
+ <label>PriceMotion Cron Report</label>
61
+ <file>pricemotion.html</file>
62
+ <type>html</type>
63
+ </pricemotion_options_emails_template>
64
+ </email>
65
+ </template>
66
+ </global>
67
+ <admin>
68
+ <routers>
69
+ <pricemotion>
70
+ <use>admin</use>
71
+ <args>
72
+ <module>A4s_Pricemotion</module>
73
+ <frontName>pricemotion</frontName>
74
+ </args>
75
+ </pricemotion>
76
+ </routers>
77
+ </admin>
78
+ <adminhtml>
79
+ <layout>
80
+ <updates>
81
+ <pricemotion>
82
+ <file>pricemotion.xml</file>
83
+ </pricemotion>
84
+ </updates>
85
+ </layout>
86
+ <acl>
87
+ <resources>
88
+ <admin>
89
+ <children>
90
+ <system>
91
+ <children>
92
+ <config>
93
+ <children>
94
+ <pricemotion_options>
95
+ <title>Pricemotion section</title>
96
+ </pricemotion_options>
97
+ </children>
98
+ </config>
99
+ </children>
100
+ </system>
101
+ </children>
102
+ </admin>
103
+ </resources>
104
+ </acl>
105
+ <events>
106
+ <catalog_product_save_after>
107
+ <observers>
108
+ <pricemotion_save_rules_data>
109
+ <type>singleton</type>
110
+ <class>A4s_Pricemotion_Model_Observer</class>
111
+ <method>saveRulesData</method>
112
+ </pricemotion_save_rules_data>
113
+ </observers>
114
+ </catalog_product_save_after>
115
+ <catalog_product_collection_load_before>
116
+ <observers>
117
+ <pricemotion_add_to_product_collection>
118
+ <type>model</type>
119
+ <class>A4s_Pricemotion_Model_Observer</class>
120
+ <method>addToProductCollection</method>
121
+ </pricemotion_add_to_product_collection>
122
+ </observers>
123
+ </catalog_product_collection_load_before>
124
+ </events>
125
+ <translate>
126
+ <modules>
127
+ <pricemotion>
128
+ <files>
129
+ <default>Pricemotion.csv</default>
130
+ </files>
131
+ </pricemotion>
132
+ </modules>
133
+ </translate>
134
+ </adminhtml>
135
+ <crontab>
136
+ <jobs>
137
+ <pricemotion_send_messages>
138
+ <schedule>
139
+ <cron_expr>0 * * * *</cron_expr>
140
+ </schedule>
141
+ <run>
142
+ <model>pricemotion/observer::sendMessages</model>
143
+ </run>
144
+ </pricemotion_send_messages>
145
+ <pricemotion_set_prices>
146
+ <schedule>
147
+ <cron_expr>30 */6 * * *</cron_expr>
148
+ </schedule>
149
+ <run>
150
+ <model>pricemotion/observer::setPrices</model>
151
+ </run>
152
+ </pricemotion_set_prices>
153
+ <pricemotion_update_attributes>
154
+ <schedule>
155
+ <cron_expr>0 */6 * * *</cron_expr>
156
+ </schedule>
157
+ <run>
158
+ <model>pricemotion/observer::updateAttributes</model>
159
+ </run>
160
+ </pricemotion_update_attributes>
161
+ </jobs>
162
+ </crontab>
163
+ <default>
164
+ <pricemotion_options>
165
+ <default>
166
+ <messages_url>http://pricemotion.nl/pm_messaging/</messages_url>
167
+ <url>http://pricemotion.nl/service/</url>
168
+ </default>
169
+ <emails>
170
+ <template>pricemotion_options_emails_template</template>
171
+ </emails>
172
+ </pricemotion_options>
173
+ </default>
174
+ </config>
app/code/local/A4s/Pricemotion/etc/system.xml ADDED
@@ -0,0 +1,169 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+
3
+ <config>
4
+ <tabs>
5
+ <pricemotion_tab translate="label" module="pricemotion">
6
+ <label>PriceMotion</label>
7
+ <sort_order>210</sort_order>
8
+ </pricemotion_tab>
9
+ </tabs>
10
+ <sections>
11
+ <pricemotion_options translate="label" module="pricemotion">
12
+ <class>separator-top</class>
13
+ <label>PriceMotion</label>
14
+ <tab>pricemotion_tab</tab>
15
+ <sort_order>130</sort_order>
16
+ <show_in_default>1</show_in_default>
17
+ <show_in_website>1</show_in_website>
18
+ <show_in_store>1</show_in_store>
19
+ <groups>
20
+ <default translate="label comment" module="pricemotion">
21
+ <label>Defaults</label>
22
+ <frontend_type>text</frontend_type>
23
+ <sort_order>10</sort_order>
24
+ <show_in_default>1</show_in_default>
25
+ <show_in_website>1</show_in_website>
26
+ <show_in_store>1</show_in_store>
27
+ <fields>
28
+ <url translate="label">
29
+ <label>Pricemotion URL</label>
30
+ <frontend_type>text</frontend_type>
31
+ <sort_order>1</sort_order>
32
+ <show_in_default>1</show_in_default>
33
+ <show_in_website>1</show_in_website>
34
+ <show_in_store>1</show_in_store>
35
+ <validate>validate-url</validate>
36
+ </url>
37
+ <messages_url translate="label">
38
+ <label>Pricemotion Messages URL</label>
39
+ <frontend_type>text</frontend_type>
40
+ <sort_order>5</sort_order>
41
+ <show_in_default>1</show_in_default>
42
+ <show_in_website>1</show_in_website>
43
+ <show_in_store>1</show_in_store>
44
+ <validate>validate-url</validate>
45
+ </messages_url>
46
+ <serial translate="label">
47
+ <label>Serial</label>
48
+ <frontend_type>text</frontend_type>
49
+ <sort_order>10</sort_order>
50
+ <show_in_default>1</show_in_default>
51
+ <show_in_website>1</show_in_website>
52
+ <show_in_store>1</show_in_store>
53
+ <validate>validate-alphanum</validate>
54
+ </serial>
55
+ <ean_att translate="label">
56
+ <label>EAN Attribute</label>
57
+ <frontend_type>select</frontend_type>
58
+ <source_model>A4s_Pricemotion_Model_System_Config_Source_Product_Attributes</source_model>
59
+ <sort_order>20</sort_order>
60
+ <show_in_default>1</show_in_default>
61
+ <show_in_website>1</show_in_website>
62
+ <show_in_store>1</show_in_store>
63
+ <validate>validate-select</validate>
64
+ </ean_att>
65
+ <name_att translate="label">
66
+ <label>Name Attribute</label>
67
+ <frontend_type>select</frontend_type>
68
+ <source_model>A4s_Pricemotion_Model_System_Config_Source_Product_Attributes</source_model>
69
+ <sort_order>25</sort_order>
70
+ <show_in_default>1</show_in_default>
71
+ <show_in_website>1</show_in_website>
72
+ <show_in_store>1</show_in_store>
73
+ <validate>validate-select</validate>
74
+ </name_att>
75
+ <cost_price_att translate="label">
76
+ <label>Cost Price Attribute</label>
77
+ <frontend_type>select</frontend_type>
78
+ <source_model>A4s_Pricemotion_Model_System_Config_Source_Product_Attributes</source_model>
79
+ <sort_order>30</sort_order>
80
+ <show_in_default>1</show_in_default>
81
+ <show_in_website>1</show_in_website>
82
+ <show_in_store>1</show_in_store>
83
+ <validate>validate-select</validate>
84
+ </cost_price_att>
85
+ <lowestprice_att translate="label">
86
+ <label>Lowest Price Attribute</label>
87
+ <frontend_type>select</frontend_type>
88
+ <source_model>A4s_Pricemotion_Model_System_Config_Source_Product_Attributes</source_model>
89
+ <sort_order>40</sort_order>
90
+ <show_in_default>1</show_in_default>
91
+ <show_in_website>1</show_in_website>
92
+ <show_in_store>1</show_in_store>
93
+ <validate>validate-select</validate>
94
+ </lowestprice_att>
95
+ <pricediff_att translate="label">
96
+ <label>Price Difference Attribute</label>
97
+ <frontend_type>select</frontend_type>
98
+ <source_model>A4s_Pricemotion_Model_System_Config_Source_Product_Attributes</source_model>
99
+ <sort_order>50</sort_order>
100
+ <show_in_default>1</show_in_default>
101
+ <show_in_website>1</show_in_website>
102
+ <show_in_store>1</show_in_store>
103
+ <validate>validate-select</validate>
104
+ </pricediff_att>
105
+ <rounded_prices translate="label">
106
+ <label>Rounded Prices</label>
107
+ <frontend_type>select</frontend_type>
108
+ <source_model>adminhtml/system_config_source_yesno</source_model>
109
+ <sort_order>60</sort_order>
110
+ <show_in_default>1</show_in_default>
111
+ <show_in_website>1</show_in_website>
112
+ <show_in_store>1</show_in_store>
113
+ </rounded_prices>
114
+ <special_price translate="label">
115
+ <label>Use 'Special Price'</label>
116
+ <frontend_type>select</frontend_type>
117
+ <source_model>adminhtml/system_config_source_yesno</source_model>
118
+ <sort_order>70</sort_order>
119
+ <show_in_default>1</show_in_default>
120
+ <show_in_website>1</show_in_website>
121
+ <show_in_store>1</show_in_store>
122
+ <comment>Instead of changing the actual product price set this to Yes and PriceMotion will change the 'Special Price'.</comment>
123
+ </special_price>
124
+ </fields>
125
+ </default>
126
+ <emails translate="label comment" module="pricemotion">
127
+ <label>Email Options</label>
128
+ <frontend_type>text</frontend_type>
129
+ <sort_order>20</sort_order>
130
+ <show_in_default>1</show_in_default>
131
+ <show_in_website>1</show_in_website>
132
+ <show_in_store>1</show_in_store>
133
+ <fields>
134
+ <enabled translate="label">
135
+ <label>Cron Reports</label>
136
+ <frontend_type>select</frontend_type>
137
+ <source_model>adminhtml/system_config_source_yesno</source_model>
138
+ <sort_order>0</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
+ <comment>Send emails with reports after cron is finished.</comment>
143
+ </enabled>
144
+ <recipient_email translate="label">
145
+ <label>Send Emails To</label>
146
+ <frontend_type>text</frontend_type>
147
+ <validate>validate-email</validate>
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
+ </recipient_email>
153
+ <template translate="label">
154
+ <label>Email Template</label>
155
+ <frontend_type>select</frontend_type>
156
+ <source_model>adminhtml/system_config_source_email_template</source_model>
157
+ <sort_order>20</sort_order>
158
+ <show_in_default>1</show_in_default>
159
+ <show_in_website>1</show_in_website>
160
+ <show_in_store>1</show_in_store>
161
+ </template>
162
+ </fields>
163
+ </emails>
164
+ </groups>
165
+ </pricemotion_options>
166
+ </sections>
167
+
168
+
169
+ </config>
app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-install-0.1.0.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * PriceMotion mysql installer
6
+ *
7
+ * @package Pricemotion
8
+ * @copyright Aim4Solutions s.r.l.
9
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
10
+ */
11
+
12
+
13
+ $installer = $this;
14
+
15
+ $installer->startSetup();
16
+
17
+ $installer->run("
18
+
19
+ -- DROP TABLE IF EXISTS {$this->getTable('pricemotion_rules')};
20
+ CREATE TABLE {$this->getTable('pricemotion_rules')} (
21
+ `rule_id` int(10) NOT NULL AUTO_INCREMENT,
22
+ `product_id` bigint(20) NOT NULL,
23
+ `cost_margin_percent` float(5,2) DEFAULT NULL,
24
+ `cost_margin_status` tinyint(1) NOT NULL COMMENT '0=Disabled; 1=Enabled',
25
+ `below_average_percent` float(5,2) NOT NULL,
26
+ `in_top_value` int(4) NOT NULL,
27
+ `status` int(11) NOT NULL COMMENT '0=Disabled; 1=Below average; 2=In top',
28
+ PRIMARY KEY (`rule_id`),
29
+ KEY `product_id` (`product_id`)
30
+ ) ENGINE=InnoDB DEFAULT CHARSET=latin1;
31
+
32
+ ");
33
+
34
+ $installer->addAttribute('catalog_product', 'pricemotion_lowest_price', array(
35
+ 'backend' => '',
36
+ 'frontend' => '',
37
+ 'label' => 'Lowest Price',
38
+ 'input' => 'price',
39
+ 'class' => '',
40
+ 'global' => true,
41
+ 'visible' => true,
42
+ 'required' => false,
43
+ 'user_defined' => true,
44
+ 'searchable' => false,
45
+ 'filterable' => false,
46
+ 'comparable' => false,
47
+ 'apply_to' => '',
48
+ 'position' => 1,
49
+ 'visible_on_front' => false,
50
+ 'visible_in_advanced_search' => 1
51
+ ));
52
+
53
+ $installer->addAttribute('catalog_product', 'pricemotion_price_difference', array(
54
+ 'backend' => '',
55
+ 'frontend' => '',
56
+ 'label' => 'Price Difference',
57
+ 'input' => 'text',
58
+ 'class' => '',
59
+ 'global' => true,
60
+ 'visible' => true,
61
+ 'required' => false,
62
+ 'user_defined' => true,
63
+ 'searchable' => false,
64
+ 'filterable' => false,
65
+ 'comparable' => false,
66
+ 'apply_to' => '',
67
+ 'position' => 1,
68
+ 'visible_on_front' => false,
69
+ 'visible_in_advanced_search' => 1
70
+ ));
71
+
72
+ $installer->endSetup();
app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.10-0.2.11.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * PriceMotion mysql installer
6
+ *
7
+ * @package Pricemotion
8
+ * @copyright Aim4Solutions s.r.l.
9
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
10
+ */
11
+
12
+
13
+ $installer = $this;
14
+
15
+ $installer->startSetup();
16
+
17
+ $installer->addAttribute(Mage_Catalog_Model_Product::ENTITY, 'enable_pricemotion', array(
18
+ 'group' => 'General',
19
+ 'type' => 'int',
20
+ 'backend' => '',
21
+ 'frontend' => '',
22
+ 'label' => 'Show PriceMotion Prices',
23
+ 'input' => 'select',
24
+ 'class' => '',
25
+ 'source' => 'eav/entity_attribute_source_boolean',
26
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_GLOBAL,
27
+ 'visible' => true,
28
+ 'required' => false,
29
+ 'user_defined' => false,
30
+ 'default' => '0',
31
+ 'searchable' => false,
32
+ 'filterable' => false,
33
+ 'comparable' => false,
34
+ 'visible_on_front' => false,
35
+ 'unique' => false,
36
+ 'apply_to' => '',
37
+ 'is_configurable' => false
38
+ ));
39
+
40
+
41
+ $installer->endSetup();
app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.12-0.2.13.php ADDED
@@ -0,0 +1,12 @@
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ $installer = $this;
4
+
5
+ $installer->startSetup();
6
+
7
+ $installer->run("
8
+ ALTER TABLE {$this->getTable('pricemotion_rules')} CHANGE `status` `status` INT( 11 ) NOT NULL COMMENT '0=Disabled; 1=Below average; 2=In top; 3=Lowest price';
9
+ ");
10
+
11
+
12
+ $installer->endSetup();
app/code/local/A4s/Pricemotion/sql/pricemotion_setup/mysql4-upgrade-0.2.8-0.2.9.php ADDED
@@ -0,0 +1,22 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+
4
+ /**
5
+ * PriceMotion mysql installer
6
+ *
7
+ * @package Pricemotion
8
+ * @copyright Aim4Solutions s.r.l.
9
+ * @author Sebastian Pruteanu <sebastian@aim4solutions.com>
10
+ */
11
+
12
+
13
+ $installer = $this;
14
+
15
+ $installer->startSetup();
16
+
17
+ $installer->run("
18
+ ALTER TABLE {$this->getTable('pricemotion_rules')} ADD `only_email` BOOLEAN NOT NULL DEFAULT FALSE AFTER `in_top_value` ;
19
+ ");
20
+
21
+
22
+ $installer->endSetup();
app/design/adminhtml/default/default/layout/pricemotion.xml ADDED
@@ -0,0 +1,26 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <layout>
3
+ <adminhtml_catalog_product_edit>
4
+ <reference name="product_tabs">
5
+ <action method="addTab">
6
+ <name>pricemotion_tab</name>
7
+ <block>pricemotion/adminhtml_catalog_product_tab</block>
8
+ </action>
9
+ <action method="addTab">
10
+ <name>pricemotion_pricerules</name>
11
+ <block>pricemotion/adminhtml_catalog_product_pricerules</block>
12
+ </action>
13
+ </reference>
14
+ <reference name="head">
15
+ <action method="addCss"><stylesheet>pricemotion/pricemotion.css</stylesheet></action>
16
+ </reference>
17
+ </adminhtml_catalog_product_edit>
18
+ <pricemotion_adminhtml_action_rules>
19
+ <reference name="head">
20
+ <action method="addCss"><stylesheet>pricemotion/pricemotion.css</stylesheet></action>
21
+ </reference>
22
+ <reference name="content">
23
+ <block type="pricemotion/adminhtml_catalog_product_action_rules" name="pricemotion_pricerules" template="pricemotion/mass_price_rules.phtml"></block>
24
+ </reference>
25
+ </pricemotion_adminhtml_action_rules>
26
+ </layout>
app/design/adminhtml/default/default/template/pricemotion/mass_price_rules.phtml ADDED
@@ -0,0 +1,47 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PriceMotion tab template
4
+ */
5
+ ?>
6
+ <?php echo $this->getFormInitScripts() ?>
7
+ <div class="content-header">
8
+ <?php echo $this->getHeaderHtml() ?>
9
+ <p class="content-buttons form-buttons"><?php echo $this->getButtonsHtml('header') ?></p>
10
+ </div>
11
+ <form action="<?php echo $this->getSaveUrl() ?>" method="post" id="pricemotion_pricerules">
12
+ <input name="form_key" type="hidden" value="<?php echo Mage::getSingleton('core/session')->getFormKey() ?>" />
13
+ <div class="price-rule-box">
14
+ <input type="radio" name="pricemotion[price_rules]" id="pm_rules_disable" checked="checked" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_DISABLED ?>" />
15
+ <label for="pm_rules_disable"><?php echo $this->__('Disable all price rules') ?></label>
16
+ </div>
17
+ <div class="price-rule-box">
18
+ <input type="radio" name="pricemotion[price_rules]" id="pm_lowest_price" value="<?php echo A4s_Pricemotion_Model_Rules::LOWEST_PRICE ?>" />
19
+ <label for="pm_lowest_price"><?php echo $this->__('Equal to lowest price') ?></label>
20
+ </div>
21
+ <div class="price-rule-box">
22
+ <input type="radio" name="pricemotion[price_rules]" id="pm_below_average_enabled" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_BELOW_AVERAGE ?>" />
23
+ <label for="pm_below_average_enabled"><?php echo $this->__('The price is always') ?></label>
24
+ <input type="text" class="input-text" name="pricemotion[below_average]" id="pm_below_average" />&#37;&nbsp;
25
+ <label for="pm_below_average"><?php echo $this->__('below average.') ?></label>
26
+ </div>
27
+ <div class="price-rule-box">
28
+ <input type="radio" name="pricemotion[price_rules]" id="pm_top_enabled" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_IN_TOP ?>" />
29
+ <label for="pm_top_enabled"><?php echo $this->__('The price is always in top') ?></label>
30
+ <input type="text" class="input-text" name="pricemotion[top]" id="pm_top" />&nbsp;
31
+ <label for="pm_top"><?php echo $this->__('of lowest prices.') ?></label>
32
+ </div>
33
+ <div class="price-rule-box">
34
+ <label for="pm_cost_margin_enabled"><?php echo $this->__('Enable') ?></label>
35
+ <input type="checkbox" name="pricemotion[cost_margin_enabled]" id="pm_cost_margin_enabled"/>
36
+ <label for="pm_cost_margin"><?php echo $this->__('Minimum margin of') ?></label>
37
+ <input type="text" class="input-text" name="pricemotion[cost_margin]" id="pm_cost_margin" />&#37;&nbsp;
38
+ <label for="pm_cost_margin"><?php echo $this->__('from the cost price.') ?></label>
39
+ </div>
40
+ <div class="price-rule-box">
41
+ <input type="checkbox" name="pricemotion[only_email]" id="pm_only_email" />
42
+ <label for="pm_only_email"><?php echo $this->__("Don't change prices but still send email notification") ?></label>
43
+ </div>
44
+ </form>
45
+ <script type="text/javascript">
46
+ var editForm = new varienForm('pricemotion_pricerules', '<?php echo $this->getValidationUrl() ?>');
47
+ </script>
app/design/adminhtml/default/default/template/pricemotion/price_rules.phtml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * PriceMotion tab template
4
+ */
5
+ ?>
6
+ <?php
7
+
8
+ $rules = $this->getProductRules();
9
+
10
+ ?>
11
+ <div class="price-rule-box">
12
+ <input type="radio" name="pricemotion[price_rules]" id="pm_rules_disable" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_DISABLED ?>" <?php if($rules->getStatus() == A4s_Pricemotion_Model_Rules::RULE_DISABLED): ?>checked="checked"<?php endif; ?> />
13
+ <label for="pm_rules_disable"><?php echo $this->__('Disable all price rules') ?></label>
14
+ </div>
15
+ <div class="price-rule-box">
16
+ <input type="radio" name="pricemotion[price_rules]" id="pm_lowest_price" value="<?php echo A4s_Pricemotion_Model_Rules::LOWEST_PRICE ?>" <?php if($rules->getStatus() == A4s_Pricemotion_Model_Rules::LOWEST_PRICE): ?>checked="checked"<?php endif; ?>/>
17
+ <label for="pm_lowest_price"><?php echo $this->__('Equal to lowest price') ?></label>
18
+ </div>
19
+ <div class="price-rule-box">
20
+ <input type="radio" name="pricemotion[price_rules]" id="pm_below_average_enabled" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_BELOW_AVERAGE ?>" <?php if($rules->getStatus() == A4s_Pricemotion_Model_Rules::RULE_BELOW_AVERAGE): ?>checked="checked"<?php endif; ?>/>
21
+ <label for="pm_below_average_enabled"><?php echo $this->__('The price is always') ?></label>
22
+ <input type="text" value="<?php echo $rules->getBelowAveragePercent() ?>" class="input-text" name="pricemotion[below_average]" id="pm_below_average" />&#37;&nbsp;
23
+ <label for="pm_below_average"><?php echo $this->__('below average.') ?></label>
24
+ </div>
25
+ <div class="price-rule-box">
26
+ <input type="radio" name="pricemotion[price_rules]" id="pm_top_enabled" value="<?php echo A4s_Pricemotion_Model_Rules::RULE_IN_TOP ?>" <?php if($rules->getStatus() == A4s_Pricemotion_Model_Rules::RULE_IN_TOP): ?>checked="checked"<?php endif; ?>/>
27
+ <label for="pm_top_enabled"><?php echo $this->__('The price is always in top') ?></label>
28
+ <input type="text" value="<?php echo $rules->getInTopValue() ?>" class="input-text" name="pricemotion[top]" id="pm_top" />&nbsp;
29
+ <label for="pm_top"><?php echo $this->__('of lowest prices.') ?></label>
30
+ </div>
31
+ <div class="price-rule-box">
32
+ <label for="pm_cost_margin_enabled"><?php echo $this->__('Enable') ?></label>
33
+ <input type="checkbox" name="pricemotion[cost_margin_enabled]" id="pm_cost_margin_enabled" <?php if($rules->getCostMarginStatus()): ?>checked="checked"<?php endif; ?>/>
34
+ <label for="pm_cost_margin"><?php echo $this->__('Minimum margin of') ?></label>
35
+ <input type="text" value="<?php echo $rules->getCostMarginPercent() ?>" class="input-text" name="pricemotion[cost_margin]" id="pm_cost_margin" />&#37;&nbsp;
36
+ <label for="pm_cost_margin"><?php echo $this->__('from the cost price.') ?></label>
37
+ </div>
38
+ <div class="price-rule-box">
39
+ <input type="checkbox" name="pricemotion[only_email]" id="pm_only_email" <?php if($rules->getOnlyEmail()): ?>checked="checked"<?php endif; ?>/>
40
+ <label for="pm_only_email"><?php echo $this->__("Don't change prices but still send email notification") ?></label>
41
+ </div>
app/etc/modules/A4s_Pricemotion.xml ADDED
@@ -0,0 +1,9 @@
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <A4s_Pricemotion>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ </A4s_Pricemotion>
8
+ </modules>
9
+ </config>
app/locale/en_US/Pricemotion.csv ADDED
@@ -0,0 +1,33 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Average Price","Average Price"
2
+ "below average.","below average."
3
+ "below average","below average"
4
+ "Disable all price rule","Disable all price rule"
5
+ "Enable","Enable"
6
+ "Error","Error"
7
+ "from the cost price.","from the cost price."
8
+ "Highest Price","Highest Price"
9
+ "Lowest Price","Lowest Price"
10
+ "Minimum margin of","Minimum margin of"
11
+ "of lowest prices.","of lowest prices."
12
+ "Price","Price"
13
+ "Price Difference","Price Difference"
14
+ "Price Information","Price Information"
15
+ "Pricemotion EAN","Pricemotion EAN"
16
+ "Pricemotion name","Pricemotion name"
17
+ "PriceMotion Price Rules","PriceMotion Price Rules"
18
+ "PriceMotion Prices","PriceMotion Prices"
19
+ "Prices","Prices"
20
+ "Service not available","Service not available"
21
+ "The price is always","The price is always"
22
+ "The price is always in top","The price is always in top"
23
+ "Vendor","Vendor"
24
+ "Cron Started","Cron Started"
25
+ "Loaded %s rules","Loaded %s rules"
26
+ "Product ID","Product ID"
27
+ "Product name","Product name"
28
+ "Rule type","Rule type"
29
+ "Old price","Old price"
30
+ "New price","New price"
31
+ "in top","in top"
32
+ "Pricemotion data could not be loaded","Pricemotion data could not be loaded"
33
+ "PriceMotion Cron Report:","PriceMotion Cron Report:"
app/locale/en_US/template/email/pricemotion.html ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--@subject PriceMotion Cron Report: {{var date}} @-->
2
+ <!--@vars
3
+ {"store url=\"\"":"Store Url",
4
+ "var date":"Date of cron",
5
+ "var rules_loaded":"Number of rules loaded",
6
+ "var items":"Rules",
7
+ "var logo_url":"Email Logo Image Url",
8
+ "var logo_alt":"Email Logo Image Alt"}
9
+ @-->
10
+ <!--@styles
11
+ body,td { color:#2f2f2f; font:11px/1.35em Verdana, Arial, Helvetica, sans-serif; }
12
+ @-->
13
+
14
+ <body style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
15
+ <div style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
16
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
17
+ <tr>
18
+ <td align="center" valign="top" style="padding:20px 0 20px 0">
19
+ <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="10" border="0" width="650" style="border:1px solid #E0E0E0;">
20
+ <!-- [ header starts here] -->
21
+ <tr>
22
+ <td valign="top"><a href="{{store url=""}}"><img src="{{var logo_url}}" alt="{{var logo_alt}}" style="margin-bottom:10px;" border="0"/></a></td>
23
+ </tr>
24
+ <!-- [ middle starts here] -->
25
+ <tr>
26
+ <td valign="top">
27
+ <p style="font-size:12px; line-height:16px; margin:0;">
28
+ PriceMotion Cron Started
29
+ </p>
30
+ <p style="font-size:12px; line-height:16px; margin:0;">Loaded {{var rules_loaded}} rules</p>
31
+ </td>
32
+ </tr>
33
+ <tr>
34
+ <td>
35
+ <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="10" border="0" width="550" style="border:1px solid #E0E0E0;">
36
+ <tr>
37
+ <td><b>Product ID</b></td>
38
+ <td><b>Product name</b></td>
39
+ <td><b>Rule type</b></td>
40
+ <td><b>Old price</b></td>
41
+ <td><b>New price</b></td>
42
+ <td><b>Margin monitor</b></td>
43
+ <td><b>Status</b></td>
44
+ </tr>
45
+ {{block type='core/template' area='frontend' template='pricemotion/report_items.phtml' items=$items}}
46
+ </table>
47
+ </td>
48
+ </tr>
49
+ </table>
50
+ </td>
51
+ </tr>
52
+ </table>
53
+ </div>
54
+ </body>
app/locale/nl_NL/Pricemotion.csv ADDED
@@ -0,0 +1,38 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ "Average Price","Gemiddelde prijs"
2
+ "below average.","onder de gemiddelde prijs."
3
+ "below average","onder de gemiddelde prijs"
4
+ "Disable all price rules","Alle prijsregels uitschakelen"
5
+ "Enable","Activeer"
6
+ "Error","Fout"
7
+ "from the cost price.","gebasseerd op de kostprijs."
8
+ "Highest Price","Hoogste prijs"
9
+ "Lowest Price","Laagste prijs"
10
+ "Minimum margin of","Minimale marge van"
11
+ "of lowest prices.","van laagste prijzen."
12
+ "Price","Prijs"
13
+ "Price Difference","Prijs verschil"
14
+ "Price Information","Prijs informatie"
15
+ "Pricemotion EAN","Pricemotion EAN"
16
+ "Pricemotion name","Pricemotion naam"
17
+ "PriceMotion Price Rules","PriceMotion Prijs Regels"
18
+ "PriceMotion Prices","PriceMotion Prijzen"
19
+ "Prices","Prijzen"
20
+ "Service not available","Service of product is niet beschikbaar"
21
+ "The price is always","De prijs is altijd"
22
+ "The price is always in top","De prijs staat altijd in de top"
23
+ "Vendor","Winkel"
24
+ "Cron Started","NL-Cron Started"
25
+ "Loaded %s rules","NL-Loaded %s rules"
26
+ "Product ID","NL-Product ID"
27
+ "Product name","NL-Product name"
28
+ "Rule type","NL-Rule type"
29
+ "Old price","NL-Old price"
30
+ "New price","NL-New price"
31
+ "in top","NL-in top"
32
+ "Pricemotion data could not be loaded","NL-Pricemotion data could not be loaded"
33
+ "PriceMotion Cron Report:","NL-PriceMotion Cron Report:"
34
+ "Don't change prices but still send email notification","Notificatie per email, wijzig prijs niet"
35
+ "Show PriceMotion Prices","Gebruik Pricemotion"
36
+ "Equal to lowest price","Gelijk aan laagste prijs"
37
+ "lowest price","laagste prijs"
38
+ "Update PriceMotion Price Rules","Update Pricemotion prijs regels"
app/locale/nl_NL/template/email/pricemotion.html ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--@subject Pricemotion cron rapport: {{var date}} @-->
2
+ <!--@vars
3
+ {"store url=\"\"":"Store Url",
4
+ "var date":"Date of cron",
5
+ "var rules_loaded":"Number of rules loaded",
6
+ "var items":"Rules",
7
+ "var logo_url":"Email Logo Image Url",
8
+ "var logo_alt":"Email Logo Image Alt"}
9
+ @-->
10
+ <!--@styles
11
+ body,td { color:#2f2f2f; font:11px/1.35em Verdana, Arial, Helvetica, sans-serif; }
12
+ @-->
13
+
14
+ <body style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
15
+ <div style="background:#F6F6F6; font-family:Verdana, Arial, Helvetica, sans-serif; font-size:12px; margin:0; padding:0;">
16
+ <table cellspacing="0" cellpadding="0" border="0" width="100%">
17
+ <tr>
18
+ <td align="center" valign="top" style="padding:20px 0 20px 0">
19
+ <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="10" border="0" width="650" style="border:1px solid #E0E0E0;">
20
+ <!-- [ header starts here] -->
21
+ <tr>
22
+ <td valign="top"><a href="{{store url=""}}"><img src="{{var logo_url}}" alt="{{var logo_alt}}" style="margin-bottom:10px;" border="0"/></a></td>
23
+ </tr>
24
+ <!-- [ middle starts here] -->
25
+ <tr>
26
+ <td valign="top">
27
+ <p style="font-size:12px; line-height:16px; margin:0;">
28
+ PriceMotion Cron gestart
29
+ </p>
30
+ <p style="font-size:12px; line-height:16px; margin:0;">{{var rules_loaded}} regels geladen</p>
31
+ </td>
32
+ </tr>
33
+ <tr>
34
+ <td>
35
+ <table bgcolor="#FFFFFF" cellspacing="0" cellpadding="10" border="0" width="550" style="border:1px solid #E0E0E0;">
36
+ <tr>
37
+ <td><b>Product ID</b></td>
38
+ <td><b>Product naam</b></td>
39
+ <td><b>Regel type</b></td>
40
+ <td><b>Oude prijs</b></td>
41
+ <td><b>Nieuwe prijs</b></td>
42
+ <td><b>Margebewaking</b></td>
43
+ <td><b>Status</b></td>
44
+ </tr>
45
+ {{block type='core/template' area='frontend' template='pricemotion/report_items.phtml' items=$items}}
46
+ </table>
47
+ </td>
48
+ </tr>
49
+ </table>
50
+ </td>
51
+ </tr>
52
+ </table>
53
+ </div>
54
+ </body>
package.xml ADDED
@@ -0,0 +1,18 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>A4s_Pricemotion</name>
4
+ <version>0.2.15</version>
5
+ <stability>stable</stability>
6
+ <license uri="https://www.gnu.org/copyleft/gpl.html">GNU GPL v3.0</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Pricemotion is een prijsvergelijker voor webwinkeliers</summary>
10
+ <description>Pricemotion is een prijsvergelijker voor webwinkeliers. Je kunt de prijzen van je concurrenten opvragen in Magento en je hebt prijsregels om prijzen (automatisch) aan te passen.</description>
11
+ <notes>Pricemotion is een prijsvergelijker voor webwinkeliers. Je kunt de prijzen van je concurrenten opvragen in Magento en je hebt prijsregels om prijzen (automatisch) aan te passen</notes>
12
+ <authors><author><name>Sebastian Pruteanu</name><user>sebastian</user><email>sebi.pruteanu@gmail.com</email></author></authors>
13
+ <date>2014-04-30</date>
14
+ <time>13:28:07</time>
15
+ <contents><target name="magelocal"><dir name="A4s"><dir name="Pricemotion"><dir name="Block"><dir name="Adminhtml"><dir name="Catalog"><dir name="Product"><dir name="Action"><file name="Rules.php" hash="2ab2d7b2aec730e4180c214e4111c6d6"/></dir><file name="Grid.php" hash="efa1e9b5133e2f173bc478c29168fc80"/><file name="Pricerules.php" hash="cb8685c1f0de60337d52b86307f16dae"/><file name="Tab.php" hash="af00da1a6dff03d99390a48086572df4"/></dir></dir><dir name="Form"><dir name="Element"><file name="Errormsg.php" hash="67a6e14c48db851da3ce29dc636066ab"/><file name="Prices.php" hash="0a3b56aeee92427b954b3642b419b336"/></dir></dir></dir></dir><dir name="Helper"><dir name="Catalog"><dir name="Product"><file name="Action.php" hash="8126e50cf75eb79d8e2c8d2f077b6e7f"/></dir></dir><file name="Data.php" hash="f4794720f868796f489032ffd502e915"/></dir><dir name="Model"><dir name="Mysql4"><dir name="Rules"><file name="Collection.php" hash="422047623e90aeeaf3056aa735e5cf51"/></dir><file name="Rules.php" hash="de43a9a3bf018ff3dc88289b400cd959"/></dir><file name="Observer.php" hash="72d7d2089c0e4d1a277d4d9a00ec3231"/><dir name="Resource"><dir name="Eav"><dir name="Mysql4"><file name="Setup.php" hash="db37feaae0b61a2f1af2bf2f3bd0f620"/></dir></dir></dir><file name="Rules.php" hash="39c0ae3ab9c1989b66a36d708722301a"/><dir name="System"><dir name="Config"><dir name="Source"><dir name="Product"><file name="Attributes.php" hash="d2e820f8b5888e1394e34b640738f1d9"/></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><file name="ActionController.php" hash="436f4b1f3f0f4c87313a5aaabf963f3a"/></dir></dir><dir name="etc"><file name="config.xml" hash="a09a98e11ff5a62624b51e17f7315777"/><file name="system.xml" hash="8639b7edd7fd7a33fb293716c9cfac9e"/></dir><dir name="sql"><dir name="pricemotion_setup"><file name="mysql4-install-0.1.0.php" hash="c33e0086a9b77f31642eb1a921623166"/><file name="mysql4-upgrade-0.2.10-0.2.11.php" hash="8c89afb7b2c3f5ba56ac39c8d0b72e67"/><file name="mysql4-upgrade-0.2.12-0.2.13.php" hash="579437094cfe6c059aa3c16a9d43bf3a"/><file name="mysql4-upgrade-0.2.8-0.2.9.php" hash="0d320ad04bd30316daa8b1994211af9a"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="pricemotion.xml" hash="b0b4f5f55155551c4523bfad0ac4dd28"/></dir><dir name="template"><dir name="pricemotion"><file name="mass_price_rules.phtml" hash="de5d9e786403fa0dcf5807648330d2c4"/><file name="price_rules.phtml" hash="e80a8705a931b73b862113b82be3a1be"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="A4s_Pricemotion.xml" hash="8579f9f81887bdb95098fa360a783553"/></dir></target><target name="magelocale"><dir name="nl_NL"><file name="Pricemotion.csv" hash="6daaa231e3a0657a1e196553d6c78c76"/><dir name="template"><dir name="email"><file name="pricemotion.html" hash="d36760ec1dd2d8503430f934a9b778e8"/></dir></dir></dir><dir name="en_US"><file name="Pricemotion.csv" hash="0ab8bfb05c1e3f7bdd26b84596432ac5"/><dir name="template"><dir name="email"><file name="pricemotion.html" hash="b1910a27cd87ee07612ed4cb89deca3b"/></dir></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="pricemotion"><file name="pricemotion.css" hash="118e574df3f4dce6f8bcc8d750bb4b43"/></dir></dir></dir></dir></target></contents>
16
+ <compatible/>
17
+ <dependencies><required><php><min>5.2.0</min><max>5.5.0</max></php></required></dependencies>
18
+ </package>
skin/adminhtml/default/default/pricemotion/pricemotion.css ADDED
@@ -0,0 +1,6 @@
 
 
 
 
 
 
1
+ .price-rule-box {
2
+ background: none repeat scroll 0 0 #E7EFEF;
3
+ border: 1px solid #CDDDDD;
4
+ margin: 0.7em 0;
5
+ padding: 0.4em;
6
+ }