SweOptipricer - Version 0.1.0

Version Notes

Testing candidate

Download this release

Release Info

Developer Rui Mendes
Extension SweOptipricer
Version 0.1.0
Comparing to
See all releases


Version 0.1.0

app/code/local/SWE/Optipricer/Block/Button.php ADDED
@@ -0,0 +1,63 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget to share the product in Facebook and get a personalized discount
4
+ *
5
+ * @package SWE_Optipricer
6
+ * @author Ubiprism Lda. / be.ubi <contact@beubi.com>
7
+ * @copyright 2014 be.ubi
8
+ * @license GNU Lesser General Public License (LGPL)
9
+ * @version v.0.2
10
+ */
11
+ class SWE_Optipricer_Block_Button extends Mage_Adminhtml_Block_System_Config_Form_Field
12
+ {
13
+ const URL_ENDPOINT_CONTACT = 'contact/email';
14
+
15
+ /**
16
+ * Set template
17
+ */
18
+ protected function _construct()
19
+ {
20
+ parent::_construct();
21
+ $this->setTemplate('swe/optipricer/system/config/button.phtml');
22
+ }
23
+
24
+ /**
25
+ * Return element html
26
+ *
27
+ * @param Varien_Data_Form_Element_Abstract $element
28
+ * @return string
29
+ */
30
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element)
31
+ {
32
+ return $this->_toHtml();
33
+ }
34
+
35
+ /**
36
+ * Return ajax url for button
37
+ *
38
+ * @return string
39
+ */
40
+ public function getAjaxCheckUrl()
41
+ {
42
+ $endPoint = Mage::getStoreConfig('swe/swe_group_activation/swe_endpoint', Mage::app()->getStore());
43
+ $uriPageView = $endPoint.self::URL_ENDPOINT_CONTACT;
44
+ return $uriPageView;
45
+ }
46
+
47
+ /**
48
+ * Generate button html
49
+ *
50
+ * @return string
51
+ */
52
+ public function getButtonHtml()
53
+ {
54
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button')
55
+ ->setData(array(
56
+ 'id' => 'swe_optipricer_button',
57
+ 'label' => $this->helper('adminhtml')->__('Send Contact'),
58
+ 'onclick' => 'javascript:check(); return false;'
59
+ ));
60
+
61
+ return $button->toHtml();
62
+ }
63
+ }
app/code/local/SWE/Optipricer/Block/Discount.php ADDED
@@ -0,0 +1,320 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Widget to share the product in Facebook and get a personalized discount
4
+ *
5
+ * @package SWE_Optipricer
6
+ * @author Ubiprism Lda. / be.ubi <contact@beubi.com>
7
+ * @copyright 2014 be.ubi
8
+ * @license GNU Lesser General Public License (LGPL)
9
+ * @version v.0.2
10
+ */
11
+ class SWE_Optipricer_Block_Discount extends Mage_Core_Block_Template implements Mage_Widget_Block_Interface
12
+ {
13
+ /**
14
+ * A model to serialize attributes
15
+ * @var Varien_Object
16
+ */
17
+ protected $_serializer = null;
18
+
19
+ private $token;
20
+ private $key;
21
+ private $enabledGlobal;
22
+ private $enabledLocal;
23
+ private $minDiscount;
24
+ private $maxDiscount;
25
+ private $text;
26
+ private $endPoint;
27
+ private $pageView;
28
+ private $renderView;
29
+ private $locale;
30
+ private $expiryOffset;
31
+ private $backgroundColor;
32
+ private $colorFont;
33
+
34
+ const HTTP_OK = 200;
35
+ const URL_ENDPOINT_COUPON = 'coupon';
36
+ const URL_ENDPOINT_PAGEVIEW = 'pageview';
37
+
38
+ /**
39
+ * Initialization
40
+ */
41
+ protected function _construct()
42
+ {
43
+ $this->token = Mage::getStoreConfig('swe/swe_group_activation/swe_token', Mage::app()->getStore());
44
+ $this->key = Mage::getStoreConfig('swe/swe_group_activation/swe_key', Mage::app()->getStore());
45
+ $this->endPoint = Mage::getStoreConfig('swe/swe_group_activation/swe_endpoint', Mage::app()->getStore());
46
+ $this->enabledGlobal = Mage::getStoreConfig('swe/swe_group_activation/swe_enable', Mage::app()->getStore());
47
+ $this->minDiscount = Mage::getStoreConfig('swe/swe_group_parameters/swe_min', Mage::app()->getStore());
48
+ $this->maxDiscount = Mage::getStoreConfig('swe/swe_group_parameters/swe_max', Mage::app()->getStore());
49
+ $this->text = '';
50
+ $this->pageView = Mage::getStoreConfig('swe/swe_group_parameters/swe_pageview', Mage::app()->getStore());
51
+ $this->renderView = Mage::getStoreConfig('swe/swe_group_parameters/swe_renderview', Mage::app()->getStore());
52
+ $this->expiryOffset = Mage::getStoreConfig('swe/swe_group_parameters/swe_expiryoffset', Mage::app()->getStore());
53
+ $this->backgroundColor = Mage::getStoreConfig('swe/swe_group_parameters/swe_background_color', Mage::app()->getStore());
54
+ $this->colorFont = Mage::getStoreConfig('swe/swe_group_parameters/swe_font_color', Mage::app()->getStore());
55
+ $this->locale = Mage::app()->getLocale()->getLocaleCode();
56
+ $this->_serializer = new Varien_Object();
57
+ parent::_construct();
58
+ }
59
+
60
+ protected function _prepareLayout() {
61
+ $this->getLayout()->getBlock('head')->addJs('swe/optipricer.min.js');
62
+ $this->getLayout()->getBlock('head')->addJs('swe/optispin.min.js');
63
+ $this->getLayout()->getBlock('head')->addJs('swe/optialert.min.js');
64
+ }
65
+
66
+ /**
67
+ * Produces links list html
68
+ *
69
+ * @return string
70
+ */
71
+ protected function _toHtml()
72
+ {
73
+ $this->loadLocalParameters();
74
+
75
+ //ToDo: remove Debug
76
+ $this->printDebug(false);
77
+
78
+ $result = $html = '';
79
+ //Global parameter of the service ($enabled)
80
+ if (!$this->enabledGlobal || !$this->enabledLocal || !$this->token || !$this->key) {
81
+ return $html;
82
+ }
83
+
84
+ //get ProductDetails and other relevant data to the requests
85
+ $data = $this->getProductDetails();
86
+ $data['min'] = $this->minDiscount;
87
+ $data['max'] = $this->maxDiscount;
88
+ $data['text'] = $this->text;
89
+ $data['discount_render'] = $this->renderView;
90
+ $data['expiry_offset'] = $this->expiryOffset;
91
+ //ToDo: get FacebookId if exists any info about it
92
+ $data['social_credentials'] = array('facebookId' => '', 'facebookToken' => '');
93
+
94
+ $securedData['data'] = $this->secureContent(json_encode($data));
95
+ $securedData['social_credentials'] = $data['social_credentials'];
96
+
97
+ //Check if pageView parameter is enabled
98
+ if ($this->pageView) {
99
+ $result = $this->updatePageView($securedData, $this->renderView);
100
+ }
101
+
102
+ $securedData['store_token'] = $this->token;
103
+ $securedData['product_id'] = $data['product_id'];
104
+ $securedData['name'] = json_encode($data['name']);
105
+ $securedData['url_api'] = $this->endPoint;
106
+ $securedData['o_price'] = $data['price'];
107
+ $securedData['locale'] = $this->locale;
108
+ $securedData['currency'] = $data['currency'];
109
+ $securedData['formatted_price'] = $data['formatted_price'];
110
+
111
+ //Generate the Optipricer Button
112
+ if ($result && $this->renderView) {
113
+ if ($result['http_code'] == self::HTTP_OK && $result['content']) {
114
+ return $result['content'];
115
+ }
116
+ }
117
+ //Get text variables
118
+ $transButton = $this->__('Share and get a discount!');
119
+ $transCommentInit = $this->__('Hey! Check this');
120
+ $transCommentMid = $this->__('I found on');
121
+ $transCommentEnd = $this->__('I loved it!');
122
+ $name = Mage::app()->getStore()->getFrontendName();
123
+ $transComment = $transCommentInit.' '.$data['name'].' '.$transCommentMid.' '.$name.'. '.$transCommentEnd;
124
+
125
+ //Assign variables to be rendered in the template
126
+ $this->assign('buttoncolor', '#'.$this->backgroundColor);
127
+ $this->assign('fontcolor', '#'.$this->colorFont);
128
+ $this->assign('transButton', $transButton);
129
+ $this->assign('transComment', $transComment);
130
+ $this->assign('offer', $securedData);
131
+
132
+ return parent::_toHtml();
133
+ }
134
+
135
+ private function updatePageView($data, $renderView = false)
136
+ {
137
+ $uriPageView = $this->endPoint.self::URL_ENDPOINT_PAGEVIEW;
138
+ $headers = array();
139
+ $headers[] = 'Authorization: Token '.$this->token;
140
+ $headers[] = 'Accept-Language: '.$this->locale;
141
+ if ($renderView) {
142
+ $headers[] = 'Accept: text/html';
143
+ }
144
+ // Get cURL resource
145
+ $response = $this->executeApiRequest($uriPageView, 'PUT', $headers, $data);
146
+
147
+ return $response;
148
+ }
149
+
150
+ private function executeApiRequest($uri, $method, $headers = array(), $rawData = '')
151
+ {
152
+ $curl = curl_init();
153
+ curl_setopt($curl, CURLOPT_RETURNTRANSFER, 1);
154
+ curl_setopt($curl, CURLOPT_URL, $uri);
155
+ curl_setopt($curl, CURLOPT_CUSTOMREQUEST, $method);
156
+ curl_setopt($curl, CURLOPT_FOLLOWLOCATION, 1);
157
+ //FixMe: delete ssl options
158
+ curl_setopt($curl, CURLOPT_SSL_VERIFYPEER, false);
159
+ curl_setopt($curl, CURLOPT_SSL_VERIFYHOST, false);
160
+ if ($headers) {
161
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
162
+ }
163
+ if ($rawData) {
164
+ $data = json_encode($rawData);
165
+ $headers[] = 'Content-Type: application/json';
166
+ $headers[] = 'Content-Length: ' . strlen($data);
167
+ curl_setopt($curl, CURLOPT_HTTPHEADER, $headers);
168
+ curl_setopt($curl, CURLOPT_POSTFIELDS, $data);
169
+ }
170
+ // Send the request & save response to $content
171
+ $content = curl_exec($curl);
172
+ if(curl_errno($curl)) {
173
+ curl_close($curl);
174
+ //ToDo: send an email to alert the error
175
+ return false;
176
+ }
177
+ $info = curl_getinfo($curl);
178
+ $result['http_code'] = $info['http_code'];
179
+ $result['content'] = $content;
180
+ // Close request to clear up some resources
181
+ curl_close($curl);
182
+ return $result;
183
+ }
184
+
185
+ private function getProductDetails()
186
+ {
187
+ $product = Mage::registry('current_product');
188
+ $productDetails = array();
189
+ $productDetails['product_id'] = $product->getId();
190
+ $productDetails['name'] = $product->getName();
191
+ $productDetails['description'] = $product->description;
192
+ $productDetails['price'] = $product->getPrice();
193
+ $productDetails['product_barcode'] = $product->getBarcode();
194
+ $productDetails['image_url'] = $product->getImageUrl();
195
+ $productDetails['link'] = $product->getProductUrl();
196
+ $brand = $product->getAttributeText('manufacturer');
197
+ $productDetails['product_brand'] = $brand ? $brand : '';
198
+ $categories = $product->getCategoryIds();
199
+ $categoriesAux = array();
200
+ foreach ($categories as $category_id) {
201
+ $_cat = Mage::getModel('catalog/category')->load($category_id);
202
+ if ($_cat->getName() && !in_array($_cat->getName(), $categoriesAux)) {
203
+ $categoriesAux[] = $_cat->getName();
204
+ }
205
+ }
206
+ $productDetails['categories'] = $categoriesAux;
207
+ $currentCurrencyCode = Mage::app()->getStore()->getCurrentCurrencyCode();
208
+ $currentCurrencySymbol = Mage::app()->getLocale()->currency($currentCurrencyCode)->getSymbol();
209
+ $productDetails['currency'] = $currentCurrencySymbol;
210
+ $productDetails['formatted_price'] = Mage::helper('core')->formatPrice($product->getPrice(), false);
211
+
212
+ return $productDetails;
213
+ }
214
+
215
+ private function loadLocalParameters()
216
+ {
217
+ $this->enabledLocal = $this->getData('enable_service');
218
+ $colorFont = $this->getData('swe_font_color');
219
+ $backgroundColor = $this->getData('swe_background_color');
220
+ $expiryOffsetLocal = $this->getData('swe_expiryoffset');
221
+
222
+ if($colorFont) {
223
+ $this->colorFont = $colorFont;
224
+ }
225
+ if($backgroundColor){
226
+ $this->backgroundColor = $backgroundColor;
227
+ }
228
+ if ($expiryOffsetLocal) {
229
+ $this->expiryOffset = $expiryOffsetLocal;
230
+ }
231
+ $minimumLocal = $this->getData('swe_min');
232
+ if ($minimumLocal) {
233
+ $this->minDiscount = $minimumLocal;
234
+ }
235
+ $maximumLocal = $this->getData('swe_max');
236
+ if ($maximumLocal && !($maximumLocal < $this->minDiscount)) {
237
+ $this->maxDiscount = $maximumLocal;
238
+ }
239
+ if($this->maxDiscount < $this->minDiscount) {
240
+ $this->maxDiscount = $this->minDiscount;
241
+ }
242
+ }
243
+
244
+ private function secureContent($content, $task = 'encrypt')
245
+ {
246
+ if ($task == 'decrypt') {
247
+ $contentSecured = $this->decryptContent($this->key, $content);
248
+ } else {
249
+ $contentSecured = $this->encryptContent($this->key, $content);
250
+ }
251
+
252
+ return $contentSecured;
253
+ }
254
+
255
+ /**
256
+ * Encrypt content
257
+ *
258
+ * @param String $key Key
259
+ * @param String $content Content
260
+ *
261
+ * @return string
262
+ */
263
+ private function encryptContent($key, $content)
264
+ {
265
+ $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
266
+ $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_RANDOM);
267
+ $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $content, MCRYPT_MODE_CBC, $iv);
268
+ $ciphertextArr = array('cipher' => base64_encode($ciphertext), 'iv' => base64_encode($iv));
269
+ $ciphertextArr = json_encode($ciphertextArr);
270
+ $ciphertextBase64 = base64_encode($ciphertextArr);
271
+
272
+ return $ciphertextBase64;
273
+ }
274
+
275
+ /**
276
+ * Decrypt content
277
+ *
278
+ * @param String $key Key
279
+ * @param String $cipher Cipher
280
+ *
281
+ * @return string
282
+ */
283
+ private function decryptContent($key, $cipher)
284
+ {
285
+ $ciphertextDec = base64_decode($cipher);
286
+ $ciphertextDec = json_decode($ciphertextDec);
287
+ $content = trim(mcrypt_decrypt(
288
+ MCRYPT_RIJNDAEL_128,
289
+ $key,
290
+ base64_decode($ciphertextDec->cipher),
291
+ MCRYPT_MODE_CBC,
292
+ base64_decode($ciphertextDec->iv)
293
+ ));
294
+
295
+ return $content;
296
+ }
297
+
298
+ //ToDo: remove
299
+ private function printDebug($debug) {
300
+ /*************** ToDo: remove *************/
301
+ if ($debug) {
302
+ echo "<br />--------- DEBUG -------<br/>";
303
+ echo "<b>Enabled Global</b>: ".$this->enabledGlobal;
304
+ echo "<br /><b>Enabled Local</b>: ".$this->enabledLocal;
305
+ echo "<br /><b>EndPoint</b>: ".$this->endPoint;
306
+ echo "<br /><b>Token</b>: ".$this->token;
307
+ echo "<br /><b>Key</b>: ".$this->key;
308
+ echo "<br /><b>Min</b>: ".$this->minDiscount;
309
+ echo "<br /><b>Max</b>: ".$this->maxDiscount;
310
+ echo "<br /><b>PageView</b>: ".$this->pageView;
311
+ echo "<br /><b>renderView</b>: ".$this->renderView;
312
+ echo "<br /><b>ExpiryOffset</b>: ".$this->expiryOffset;
313
+ echo "<br /><b>Locale</b>: ".$this->locale;
314
+ echo "<br /><b>ColorFont</b>: ".$this->colorFont;
315
+ echo "<br /><b>Background Color</b>: ".$this->backgroundColor;
316
+ echo "<br />-------- END DEBUG -----<br /><br />";
317
+ }
318
+ /*************** ToDo: remove *************/
319
+ }
320
+ }
app/code/local/SWE/Optipricer/Helper/Data.php ADDED
@@ -0,0 +1,14 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Default helper of the module
4
+ *
5
+ * @package SWE_Optipricer
6
+ * @author Ubiprism Lda. / be.ubi <contact@beubi.com>
7
+ * @copyright 2014 be.ubi
8
+ * @license GNU Lesser General Public License (LGPL)
9
+ * @version v.0.2
10
+ */
11
+ class SWE_Optipricer_Helper_Data extends Mage_Core_Helper_Abstract
12
+ {
13
+
14
+ }
app/code/local/SWE/Optipricer/Model/Config.php ADDED
@@ -0,0 +1,21 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Class SWE_Optipricer_Model_Observer
4
+ *
5
+ * @package SWE_Optipricer
6
+ * @author Ubiprism Lda. / be.ubi <contact@beubi.com>
7
+ * @copyright 2014 be.ubi
8
+ * @license GNU Lesser General Public License (LGPL)
9
+ * @version v.0.2
10
+ */
11
+ class SWE_Optipricer_Model_Config
12
+ {
13
+ public function toOptionArray()
14
+ {
15
+ $result = array();
16
+ $result[] = array('value' => '0', 'label'=>' Local');
17
+ $result[] = array('value' => '1', 'label'=>' Remote');
18
+
19
+ return $result;
20
+ }
21
+ }
app/code/local/SWE/Optipricer/Model/Observer.php ADDED
@@ -0,0 +1,408 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /**
4
+ * Class SWE_Optipricer_Model_Observer
5
+ *
6
+ * @package SWE_Optipricer
7
+ * @author Ubiprism Lda. / be.ubi <contact@beubi.com>
8
+ * @copyright 2014 be.ubi
9
+ * @license GNU Lesser General Public License (LGPL)
10
+ * @version v.0.2
11
+ */
12
+ class SWE_Optipricer_Model_Observer extends Varien_Event_Observer
13
+ {
14
+ const STATE_CANCELED = 'canceled';
15
+ const SCENARIO_ONE_PAGE_CHECKOUT = 'one_page';
16
+ const SCENARIO_MULTIPLE_ADDRESSES_CHECKOUT = 'multiple_addresses';
17
+ const URL_ENDPOINT_COUPON = 'coupon';
18
+ const URL_ENDPOINT_REDEEM = 'redeem';
19
+ const URL_SEPARATOR = '/';
20
+
21
+ protected $_serializer = null;
22
+ private $token;
23
+ private $key;
24
+ private $enabledGlobal;
25
+ private $minDiscount;
26
+ private $maxDiscount;
27
+ private $text;
28
+ private $endPoint;
29
+ private $pageView;
30
+ private $renderView;
31
+ private $locale;
32
+ private $expiryOffset;
33
+
34
+ /**
35
+ * Initialization
36
+ */
37
+ protected function _construct()
38
+ {
39
+ $this->token = Mage::getStoreConfig('swe/swe_group_activation/swe_token',Mage::app()->getStore());
40
+ $this->key = Mage::getStoreConfig('swe/swe_group_activation/swe_key', Mage::app()->getStore());
41
+ $this->enabledGlobal = Mage::getStoreConfig('swe/swe_group_activation/swe_enable',Mage::app()->getStore());
42
+ $this->endPoint = Mage::getStoreConfig('swe/swe_group_activation/swe_endpoint',Mage::app()->getStore());
43
+ $this->minDiscount = Mage::getStoreConfig('swe/swe_group_parameters/swe_min',Mage::app()->getStore());
44
+ $this->maxDiscount = Mage::getStoreConfig('swe/swe_group_parameters/swe_max',Mage::app()->getStore());
45
+ $this->text = '';
46
+ $this->pageView = Mage::getStoreConfig('swe/swe_group_parameters/swe_pageview',Mage::app()->getStore());
47
+ $this->renderView = Mage::getStoreConfig('swe/swe_group_parameters/swe_renderview',Mage::app()->getStore());
48
+ $this->expiryOffset = Mage::getStoreConfig('swe/swe_group_parameters/swe_expiryoffset',Mage::app()->getStore());
49
+ $this->locale = Mage::app()->getLocale()->getLocaleCode();
50
+ $this->_serializer = new Varien_Object();
51
+ }
52
+
53
+ /**
54
+ * Verify each price for each discount given
55
+ *
56
+ * @param Varien_Event_Observer $observer Observer
57
+ *
58
+ * @return void
59
+ */
60
+ public function validateCart(Varien_Event_Observer $observer)
61
+ {
62
+ $session = Mage::getSingleton('checkout/session');
63
+ /** @var Mage_Sales_Model_Quote $quote */
64
+ $quote = $session->getQuote();
65
+ $quote->setIsMultiShipping(false);
66
+ $scenario = $this->getCurrentScenario($quote);
67
+ $this->_construct();
68
+ if (!$this->token) {
69
+ return;
70
+ }
71
+ try {
72
+ $errors = array();
73
+ foreach($quote->getAllItems() as $item) {
74
+ $error = $this->validateItem($item, $scenario);
75
+ if ($error) {
76
+ $errors[] = $error;
77
+ }
78
+ }
79
+ $quote->setTotalsCollectedFlag(false);
80
+
81
+ } catch (Exception $e) {
82
+ //ToDo: send email with the error
83
+ return;
84
+ }
85
+ }
86
+
87
+ /**
88
+ * Send Order status to Optipricer System
89
+ *
90
+ * @param Varien_Event_Observer $observer Observer
91
+ *
92
+ * @return void
93
+ */
94
+ public function sendOrderStatus(Varien_Event_Observer $observer)
95
+ {
96
+ $this->_construct();
97
+ if (!$this->token) {
98
+ return;
99
+ }
100
+ $cookiesToRemove = array();
101
+ $session = Mage::getSingleton('checkout/session');
102
+ /** @var Mage_Sales_Model_Quote $quote */
103
+ $quote = $session->getQuote();
104
+ $scenario = $this->getCurrentScenario($quote);
105
+ $errors = array();
106
+ try {
107
+ //Validate each product (that has a coupon assigned to it)
108
+ foreach($quote->getAllItems() as $item)
109
+ {
110
+ $error = $this->validateItem($item, $scenario);
111
+ if ($error) {
112
+ $errors[] = $item->getName();
113
+ } else {
114
+ $productId = $item->getProductId();
115
+ $oldProduct = Mage::getModel('catalog/product')->load($productId);
116
+ $originalPrice = round($oldProduct->getData('price'), 2);
117
+ list($discountToken, $priceWithDiscount) = $this->getDiscountTokenAndValueCookie($this->token, $productId);
118
+ // Price has changed and a Cookie exists
119
+ if ($discountToken) {
120
+ $products = $this->getAllQuoteProducts($scenario, $quote);
121
+ //Try to Redeem coupon
122
+ if (!$this->redeemCoupon($discountToken, $products)) {
123
+ $errors[] = $item->getName();
124
+ //Remove invalid cookie
125
+ setcookie('discount_'.$this->token.'_'.$productId, null, -1, '/');
126
+ $this->changeItemPrice($item, $originalPrice, $scenario);
127
+ } else {
128
+ $cookiesToRemove[] = 'discount_'.$this->token.'_'.$productId;
129
+ $this->changeItemPrice($item, $priceWithDiscount, $scenario);
130
+ }
131
+ }
132
+ }
133
+ }
134
+ } catch (Exception $e){
135
+ //ToDo: send email with the error
136
+ return;
137
+ }
138
+
139
+ //Process the error regarding the scenario
140
+ if (count($errors)) {
141
+ $result['success'] = false;
142
+ $result['error'] = true;
143
+ if (count($errors) > 1) {
144
+ $message = 'Products '.implode(', ', $errors).' are invalid!';
145
+ } elseif (count($errors) == 1) {
146
+ $message = 'Product '.$errors[0].' is invalid!';
147
+ }
148
+ $result['error_messages'] = $message;
149
+ $response = Mage::app()->getResponse();
150
+ $response->setBody(Mage::helper('core')->jsonEncode($result));
151
+ $response->sendResponse();
152
+ exit();
153
+ } else {
154
+ //Remove cookies of used coupons
155
+ foreach ($cookiesToRemove as $cookie) {
156
+ setcookie($cookie, null, -1, '/');
157
+ }
158
+ }
159
+ }
160
+
161
+ /************************* AUXILIARY METHODS ***************************/
162
+
163
+ /**
164
+ * Method to manage secure content
165
+ *
166
+ * @param string $content Content
167
+ * @param string $task Task
168
+ *
169
+ * @return string
170
+ */
171
+ private function secureContent($content, $task = 'encrypt')
172
+ {
173
+ if ($task == 'decrypt') {
174
+ $contentSecured = $this->decryptContent($this->key, $content);
175
+ } else {
176
+ $contentSecured = $this->encryptContent($this->key, $content);
177
+ }
178
+
179
+ return $contentSecured;
180
+ }
181
+
182
+ /**
183
+ * Encrypt content
184
+ *
185
+ * @param String $key Key
186
+ * @param String $content Content
187
+ *
188
+ * @return string
189
+ */
190
+ private function encryptContent($key, $content)
191
+ {
192
+ $ivSize = mcrypt_get_iv_size(MCRYPT_RIJNDAEL_128, MCRYPT_MODE_CBC);
193
+ $iv = mcrypt_create_iv($ivSize, MCRYPT_DEV_RANDOM);
194
+ $ciphertext = mcrypt_encrypt(MCRYPT_RIJNDAEL_128, $key, $content, MCRYPT_MODE_CBC, $iv);
195
+ $ciphertextArr = array('cipher' => base64_encode($ciphertext), 'iv' => base64_encode($iv));
196
+ $ciphertextArr = json_encode($ciphertextArr);
197
+ $ciphertextBase64 = base64_encode($ciphertextArr);
198
+
199
+ return $ciphertextBase64;
200
+ }
201
+
202
+ /**
203
+ * Decrypt content
204
+ *
205
+ * @param String $key Key
206
+ * @param String $cipher Cipher
207
+ *
208
+ * @return string
209
+ */
210
+ private function decryptContent($key, $cipher)
211
+ {
212
+ $ciphertextDec = base64_decode($cipher);
213
+ $ciphertextDec = json_decode($ciphertextDec);
214
+ $content = trim(mcrypt_decrypt(
215
+ MCRYPT_RIJNDAEL_128,
216
+ $key,
217
+ base64_decode($ciphertextDec->cipher),
218
+ MCRYPT_MODE_CBC,
219
+ base64_decode($ciphertextDec->iv)
220
+ ));
221
+ return $content;
222
+ }
223
+
224
+ /**
225
+ * Method to get the DiscountToken and the Value from the cookie
226
+ *
227
+ * @param string $token Token Store
228
+ * @param int $productId Product Id
229
+ *
230
+ * @return array
231
+ */
232
+ private function getDiscountTokenAndValueCookie($token, $productId)
233
+ {
234
+ $discountToken = '';
235
+ $finalPrice = 0;
236
+ if (isset($_COOKIE['discount_'.$token.'_'.$productId])) {
237
+ $cookie = $_COOKIE['discount_'.$token.'_'.$productId];
238
+ $dataAux = explode(':', $cookie);
239
+ $data = $this->secureContent(json_encode($dataAux[0]), 'decrypt');
240
+ $coupon = json_decode($data, true);
241
+ if (is_array($coupon)) {
242
+ if (array_key_exists('token', $coupon)) {
243
+ $discountToken = $coupon['token'];
244
+ }
245
+ } else {
246
+ //ToDo: alert that a cookie was violated
247
+ setcookie($cookie, null, -1, '/');
248
+ }
249
+ if (is_array($coupon)) {
250
+ if (array_key_exists('value', $coupon)) {
251
+ $finalPrice = $coupon['value'];
252
+ }
253
+ }
254
+ }
255
+ return array($discountToken, $finalPrice);
256
+ }
257
+
258
+ /**
259
+ * Method to redeem a given coupon
260
+ *
261
+ * @param string $discountToken Discount token
262
+ * @param array $products Products
263
+ * @param string $discountTokens
264
+ *
265
+ * @return bool
266
+ */
267
+ private function redeemCoupon($discountToken, $products, $discountTokens = '')
268
+ {
269
+ $info = array();
270
+ if ($products) {
271
+ $info['products'] = $products;
272
+ }
273
+ $url = $this->endPoint.self::URL_ENDPOINT_COUPON.
274
+ self::URL_SEPARATOR.$discountToken.self::URL_SEPARATOR.self::URL_ENDPOINT_REDEEM;
275
+
276
+ $client = new Zend_Http_Client($url);
277
+ $client->setHeaders(Zend_Http_Client::CONTENT_TYPE, 'application/json');
278
+ $client->setHeaders('Authorization', 'Token '.$this->token);
279
+ if (!$discountTokens) {
280
+ $discountTokens = array($discountToken);
281
+ }
282
+ $data = array(
283
+ 'tokens' => $discountTokens,
284
+ 'notes' => $info,
285
+ 'location' => ''
286
+ );
287
+ $securedData['data'] = $this->secureContent(json_encode($data));
288
+ $client->setRawData(json_encode($securedData));
289
+ try {
290
+ $response = $client->request('PUT');
291
+ if ($response->isSuccessful()) {
292
+ //$resp = $response->getBody();
293
+ $result = true;
294
+ } else {
295
+ $result = false;
296
+ }
297
+ } catch (Exception $e) {
298
+ //ToDo: send an email
299
+ $result = false;
300
+ }
301
+ return $result;
302
+ }
303
+
304
+ /**
305
+ * Method to change the price of the item/product
306
+ *
307
+ * @param Mage_Sales_Model_Quote_Item $item
308
+ * @param double $finalValue Final Price
309
+ * @param string $scenario Scenario
310
+ *
311
+ * @throws Exception
312
+ */
313
+ private function changeItemPrice($item, $finalValue, $scenario='other')
314
+ {
315
+ try {
316
+ if ($finalValue > 0) {
317
+ $product = $item->getProduct();
318
+ $oldProduct = Mage::getModel('catalog/product')->load($product->getId());
319
+ $originalPrice = $oldProduct->getData('price');
320
+ //ToDo: discount field (amount)
321
+ $item->setOriginalPrice($product->getPrice());
322
+ $item->setCustomPrice($finalValue);
323
+ $item->setOriginalCustomPrice($finalValue);
324
+ $price = $product->getPrice();
325
+ $discount = $price - $finalValue;
326
+ $item->setBaseDiscountAmount($discount);
327
+ $perc = $discount / $price * 100;
328
+ $item->save();
329
+ }
330
+ } catch (Exception $e) {
331
+ throw $e;
332
+ }
333
+ }
334
+
335
+ /**
336
+ * Method to collect all products from the quote
337
+ *
338
+ * @param string $scenario Current Scenario
339
+ * @param Mage_Sales_Model_Service_Quote $quote Quote
340
+ *
341
+ * @throws Exception
342
+ *
343
+ * @return array
344
+ */
345
+ private function getAllQuoteProducts($scenario, $quote)
346
+ {
347
+ $products = array();
348
+ foreach($quote->getAllItems() as $item)
349
+ {
350
+ $productId = $item->getProductId();
351
+ list($discountToken, $finalValue) = $this->getDiscountTokenAndValueCookie($this->token, $productId);
352
+ $productAux = array();
353
+ $productAux['productId'] = $productId;
354
+ $productAux['discountToken'] = $discountToken;
355
+ $productAux['finalValue'] = $finalValue;
356
+ $products[] = $productAux;
357
+ }
358
+ return $products;
359
+ }
360
+
361
+ /**
362
+ * Method to return current Scenario
363
+ *
364
+ * @return string
365
+ */
366
+ private function getCurrentScenario($quote)
367
+ {
368
+ if ($quote->getIsMultiShipping()) {
369
+ $scenario = self::SCENARIO_MULTIPLE_ADDRESSES_CHECKOUT;
370
+ } else {
371
+ $scenario = self::SCENARIO_ONE_PAGE_CHECKOUT;
372
+ }
373
+ return $scenario;
374
+ }
375
+
376
+ /**
377
+ * Method to validate an item
378
+ *
379
+ * @param Mage_Sales_Model_Quote_Item $item Item
380
+ * @param string $scenario Current Scenario
381
+ *
382
+ * @throws Exception
383
+ *
384
+ * @return string
385
+ */
386
+ private function validateItem($item, $scenario='other')
387
+ {
388
+ $error = '';
389
+ $productId = $item->getProductId();
390
+ $newProduct = $item->getProduct();
391
+ $oldProduct = Mage::getModel('catalog/product')->load($newProduct->getId());
392
+ list($discountToken, $priceWithDiscount) = $this->getDiscountTokenAndValueCookie($this->token, $productId);
393
+ $originalPrice = round($oldProduct->getData('price'), 2);
394
+ $currentProductPrice = round($newProduct->getData('price'), 2);
395
+ $currentItemPrice = round($item->getCustomPrice(), 2);
396
+ if ($originalPrice != $currentProductPrice || $originalPrice != $currentItemPrice || $discountToken) {
397
+ // Price has changed and cookie was deleted/violated
398
+ if (!$discountToken) {
399
+ $error = $item->getName();
400
+ $this->changeItemPrice($item, $originalPrice, $scenario);
401
+ setcookie('discount_'.$this->token.'_'.$productId, null, -1, '/');
402
+ } else {
403
+ $this->changeItemPrice($item, $priceWithDiscount, $scenario);
404
+ }
405
+ }
406
+ return $error;
407
+ }
408
+ }
app/code/local/SWE/Optipricer/controllers/Adminhtml/SweoptipricerController.php ADDED
@@ -0,0 +1,15 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ class SWE_Optipricer_Adminhtml_SweoptipricerController extends Mage_Adminhtml_Controller_Action
4
+ {
5
+ /**
6
+ * Return some checking result
7
+ *
8
+ * @return void
9
+ */
10
+ public function checkAction()
11
+ {
12
+ $result = 1;
13
+ Mage::app()->getResponse()->setBody($result);
14
+ }
15
+ }
app/code/local/SWE/Optipricer/etc/.gitignore ADDED
@@ -0,0 +1 @@
 
1
+ config.xml
app/code/local/SWE/Optipricer/etc/system.xml ADDED
@@ -0,0 +1,179 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <config>
3
+ <tabs>
4
+ <swe translate="label" module="optipricer">
5
+ <label>SWE - Optipricer</label>
6
+ <sort_order>100</sort_order>
7
+ </swe>
8
+ </tabs>
9
+ <sections>
10
+ <swe translate="label" module="optipricer">
11
+ <label>Configuration</label>
12
+ <tab>swe</tab>
13
+ <sort_order>1000</sort_order>
14
+ <show_in_default>1</show_in_default>
15
+ <show_in_website>1</show_in_website>
16
+ <show_in_store>1</show_in_store>
17
+
18
+ <groups>
19
+ <swe_group_activation translate="label" module="optipricer">
20
+ <label>Optipricer - Activation</label>
21
+ <sort_order>10</sort_order>
22
+ <show_in_default>1</show_in_default>
23
+ <show_in_website>1</show_in_website>
24
+ <show_in_store>1</show_in_store>
25
+ <expanded>0</expanded>
26
+ <fields>
27
+ <swe_name translate="label">
28
+ <label>Name</label>
29
+ <frontend_type>text</frontend_type>
30
+ <validate>required-entry</validate>
31
+ <sort_order>5</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
+ </swe_name>
36
+ <swe_email translate="label">
37
+ <label>Email</label>
38
+ <frontend_type>text</frontend_type>
39
+ <validate>validate-email required-entry</validate>
40
+ <sort_order>10</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
+ </swe_email>
45
+ <swe_message translate="label">
46
+ <label>Message</label>
47
+ <frontend_type>textarea</frontend_type>
48
+ <sort_order>15</sort_order>
49
+ <show_in_default>1</show_in_default>
50
+ <show_in_website>1</show_in_website>
51
+ <show_in_store>1</show_in_store>
52
+ </swe_message>
53
+ <swe_contact translate="label">
54
+ <label>Activate service</label>
55
+ <frontend_type>button</frontend_type>
56
+ <frontend_model>optipricer/button</frontend_model>
57
+ <sort_order>20</sort_order>
58
+ <show_in_default>1</show_in_default>
59
+ <show_in_website>1</show_in_website>
60
+ <show_in_store>1</show_in_store>
61
+ </swe_contact>
62
+ <swe_token translate="label">
63
+ <label>Store Token </label>
64
+ <comment>Store Token (given by be.ubi)</comment>
65
+ <frontend_type>text</frontend_type>
66
+ <sort_order>24</sort_order>
67
+ <show_in_default>1</show_in_default>
68
+ <show_in_website>1</show_in_website>
69
+ <show_in_store>1</show_in_store>
70
+ </swe_token>
71
+ <swe_key translate="label">
72
+ <label>Store Key </label>
73
+ <comment>Key for encrypt/decrypt data (given by be.ubi)</comment>
74
+ <frontend_type>text</frontend_type>
75
+ <sort_order>30</sort_order>
76
+ <show_in_default>1</show_in_default>
77
+ <show_in_website>1</show_in_website>
78
+ <show_in_store>1</show_in_store>
79
+ </swe_key>
80
+ <swe_enable translate="label">
81
+ <label>Enable Service </label>
82
+ <comment>Enable or Disable the service.</comment>
83
+ <frontend_type>select</frontend_type>
84
+ <sort_order>40</sort_order>
85
+ <show_in_default>1</show_in_default>
86
+ <show_in_website>1</show_in_website>
87
+ <show_in_store>1</show_in_store>
88
+ <source_model>adminhtml/system_config_source_yesno</source_model>
89
+ </swe_enable>
90
+ <swe_endpoint translate="label">
91
+ <label>Swe Endpoint </label>
92
+ <comment>Don't change this endpoint! Unless it was requested by the widget develop team.</comment>
93
+ <frontend_type>text</frontend_type>
94
+ <sort_order>90</sort_order>
95
+ <show_in_default>1</show_in_default>
96
+ <show_in_website>1</show_in_website>
97
+ <show_in_store>1</show_in_store>
98
+ </swe_endpoint>
99
+ </fields>
100
+ </swe_group_activation>
101
+ <swe_group_parameters translate="label" module="optipricer">
102
+ <label>Optipricer - Parameters</label>
103
+ <sort_order>20</sort_order>
104
+ <show_in_default>1</show_in_default>
105
+ <show_in_website>1</show_in_website>
106
+ <show_in_store>1</show_in_store>
107
+ <expanded>1</expanded>
108
+ <fields>
109
+ <swe_expiryoffset translate="label">
110
+ <label>Expiry Offset (in minutes)</label>
111
+ <comment>Time limit for the Coupon. Example: 2880=2 days</comment>
112
+ <frontend_type>text</frontend_type>
113
+ <sort_order>50</sort_order>
114
+ <show_in_default>1</show_in_default>
115
+ <show_in_website>1</show_in_website>
116
+ <show_in_store>1</show_in_store>
117
+ </swe_expiryoffset>
118
+ <swe_min translate="label">
119
+ <label>Minimum Discount </label>
120
+ <comment>Minimum value of the discount range.</comment>
121
+ <frontend_type>text</frontend_type>
122
+ <sort_order>60</sort_order>
123
+ <show_in_default>1</show_in_default>
124
+ <show_in_website>1</show_in_website>
125
+ <show_in_store>1</show_in_store>
126
+ </swe_min>
127
+ <swe_max translate="label">
128
+ <label>Maximum Discount </label>
129
+ <comment>Maximum value of the discount range.</comment>
130
+ <frontend_type>text</frontend_type>
131
+ <sort_order>70</sort_order>
132
+ <show_in_default>1</show_in_default>
133
+ <show_in_website>1</show_in_website>
134
+ <show_in_store>1</show_in_store>
135
+ </swe_max>
136
+ <swe_pageview translate="label">
137
+ <label>Enable Page Views </label>
138
+ <comment>Enable or Disable the feature "Page Views".</comment>
139
+ <frontend_type>select</frontend_type>
140
+ <sort_order>80</sort_order>
141
+ <show_in_default>1</show_in_default>
142
+ <show_in_website>1</show_in_website>
143
+ <show_in_store>1</show_in_store>
144
+ <source_model>adminhtml/system_config_source_yesno</source_model>
145
+ </swe_pageview>
146
+ <swe_renderview translate="label">
147
+ <label>Render Template </label>
148
+ <comment>Render templates from local or remote sources.</comment>
149
+ <frontend_type>radios</frontend_type>
150
+ <source_model>optipricer/config</source_model>
151
+ <sort_order>90</sort_order>
152
+ <show_in_default>1</show_in_default>
153
+ <show_in_website>1</show_in_website>
154
+ <show_in_store>1</show_in_store>
155
+ </swe_renderview>
156
+ <swe_background_color translate="label">
157
+ <label>Background color (Button)</label>
158
+ <comment>If empty, the color 660066 (purple) will be used</comment>
159
+ <frontend_type>text</frontend_type>
160
+ <sort_order>100</sort_order>
161
+ <show_in_default>1</show_in_default>
162
+ <show_in_website>1</show_in_website>
163
+ <show_in_store>1</show_in_store>
164
+ </swe_background_color>
165
+ <swe_font_color translate="label">
166
+ <label>Font color (Button)</label>
167
+ <comment>If empty, the color FFFFFF (white) will be used</comment>
168
+ <frontend_type>text</frontend_type>
169
+ <sort_order>110</sort_order>
170
+ <show_in_default>1</show_in_default>
171
+ <show_in_website>1</show_in_website>
172
+ <show_in_store>1</show_in_store>
173
+ </swe_font_color>
174
+ </fields>
175
+ </swe_group_parameters>
176
+ </groups>
177
+ </swe>
178
+ </sections>
179
+ </config>
app/code/local/SWE/Optipricer/etc/widget.xml ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <widgets>
3
+ <optipricer_discount type="optipricer/discount" translate="Optipricer Discount" module="optipricer">
4
+ <name>Optipricer Discount</name>
5
+
6
+ <description>Get a personalized discount</description>
7
+
8
+ <!-- Additional javascript files to be loaded
9
+ on the widget configuration edit form if needed. -->
10
+ <!--<js>mage/adminhtml/first.js,mage/adminhtml/second.js</js>-->
11
+
12
+ <!--
13
+ It should contain comma separated list
14
+ of javascript files paths under the /js directory.
15
+ This tag is optional.
16
+ -->
17
+
18
+ <parameters>
19
+ <enable_service translate="label">
20
+ <label>Enable Service</label>
21
+ <visible>1</visible>
22
+ <required>1</required>
23
+ <type>select</type>
24
+ <value>1</value>
25
+ <source_model>adminhtml/system_config_source_yesno</source_model>
26
+ </enable_service>
27
+ <swe_font_color translate="label">
28
+ <label>Font color (Button)</label>
29
+ <visible>1</visible>
30
+ <type>text</type>
31
+ <description>If empty, the color FFFFFF (white) will be used</description>
32
+ </swe_font_color>
33
+ <swe_background_color translate="label">
34
+ <label>Background color (Button)</label>
35
+ <visible>1</visible>
36
+ <type>text</type>
37
+ <!-- <value>5D2D87</value> -->
38
+ <description>If empty, the color 660066 (purple) will be used</description>
39
+ </swe_background_color>
40
+ <swe_expiryoffset translate="label">
41
+ <label>Expiry Offset (in minutes)</label>
42
+ <visible>1</visible>
43
+ <type>text</type>
44
+ <description>If empty, it uses the default value defined in the configuration.</description>
45
+ </swe_expiryoffset>
46
+ <swe_min translate="label">
47
+ <label>Minimum Discount </label>
48
+ <description>If empty, it uses the default value defined in the configuration.</description>
49
+ <type>text</type>
50
+ <visible>1</visible>
51
+ </swe_min>
52
+ <swe_max translate="label">
53
+ <label>Maximum Discount </label>
54
+ <description>If empty, it uses the default value defined in the configuration.</description>
55
+ <visible>1</visible>
56
+ <type>text</type>
57
+ </swe_max>
58
+ <template translate="label">
59
+ <label>Frontend Template</label>
60
+ <visible>1</visible>
61
+ <required>1</required>
62
+ <type>select</type>
63
+ <values>
64
+ <button translate="label">
65
+ <value>swe/optipricer/widget.phtml</value>
66
+ <label>Share Button (Optipricer)</label>
67
+ </button>
68
+ </values>
69
+ </template>
70
+ </parameters>
71
+ </optipricer_discount>
72
+ </widgets>
app/design/frontend/base/default/template/swe/optipricer/widget.phtml ADDED
@@ -0,0 +1,371 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <style>
2
+
3
+ /** =====================
4
+ * Default Look and Feel
5
+ ====================== **/
6
+
7
+ .alertify-logs {
8
+ position: fixed;
9
+ z-index: 5000;
10
+ top: 10px;
11
+ right: 10px;
12
+ width: 300px;
13
+ }
14
+ .alertify,
15
+ .alertify-log {
16
+ font-family: sans-serif;
17
+ }
18
+ .alertify {
19
+ background: #FFF;
20
+ border: 10px solid #333; /* browsers that don't support rgba */
21
+ border: 10px solid rgba(0,0,0,.7);
22
+ border-radius: 8px;
23
+ box-shadow: 0 3px 3px rgba(0,0,0,.3);
24
+ -webkit-background-clip: padding; /* Safari 4? Chrome 6? */
25
+ -moz-background-clip: padding; /* Firefox 3.6 */
26
+ background-clip: padding-box; /* Firefox 4, Safari 5, Opera 10, IE 9 */
27
+ }
28
+ .alertify-text {
29
+ border: 1px solid #CCC;
30
+ padding: 10px;
31
+ border-radius: 4px;
32
+ }
33
+ .alertify-button {
34
+ border-radius: 4px;
35
+ color: #FFF;
36
+ font-weight: bold;
37
+ padding: 6px 15px;
38
+ text-decoration: none;
39
+ text-shadow: 1px 1px 0 rgba(0,0,0,.5);
40
+ box-shadow: inset 0 1px 0 0 rgba(255,255,255,.5);
41
+ background-image: -webkit-linear-gradient(top, rgba(255,255,255,.3), rgba(255,255,255,0));
42
+ background-image: -moz-linear-gradient(top, rgba(255,255,255,.3), rgba(255,255,255,0));
43
+ background-image: -ms-linear-gradient(top, rgba(255,255,255,.3), rgba(255,255,255,0));
44
+ background-image: -o-linear-gradient(top, rgba(255,255,255,.3), rgba(255,255,255,0));
45
+ background-image: linear-gradient(top, rgba(255,255,255,.3), rgba(255,255,255,0));
46
+ }
47
+ .alertify-button:hover,
48
+ .alertify-button:focus {
49
+ outline: none;
50
+ background-image: -webkit-linear-gradient(top, rgba(0,0,0,.1), rgba(0,0,0,0));
51
+ background-image: -moz-linear-gradient(top, rgba(0,0,0,.1), rgba(0,0,0,0));
52
+ background-image: -ms-linear-gradient(top, rgba(0,0,0,.1), rgba(0,0,0,0));
53
+ background-image: -o-linear-gradient(top, rgba(0,0,0,.1), rgba(0,0,0,0));
54
+ background-image: linear-gradient(top, rgba(0,0,0,.1), rgba(0,0,0,0));
55
+ }
56
+ .alertify-button:focus {
57
+ box-shadow: 0 0 15px #2B72D5;
58
+ }
59
+ .alertify-button:active {
60
+ position: relative;
61
+ box-shadow: inset 0 2px 4px rgba(0,0,0,.15), 0 1px 2px rgba(0,0,0,.05);
62
+ }
63
+ .alertify-button-cancel,
64
+ .alertify-button-cancel:hover,
65
+ .alertify-button-cancel:focus {
66
+ background-color: #FE1A00;
67
+ border: 1px solid #D83526;
68
+ }
69
+ .alertify-button-ok,
70
+ .alertify-button-ok:hover,
71
+ .alertify-button-ok:focus {
72
+ background-color: #5CB811;
73
+ border: 1px solid #3B7808;
74
+ }
75
+
76
+ .alertify-log {
77
+ background: #1F1F1F;
78
+ background: rgba(0,0,0,.9);
79
+ padding: 15px;
80
+ border-radius: 4px;
81
+ color: #FFF;
82
+ text-shadow: -1px -1px 0 rgba(0,0,0,.5);
83
+ }
84
+ .alertify-log-error {
85
+ background: #FE1A00;
86
+ background: rgba(254,26,0,.9);
87
+ }
88
+ .alertify-log-success {
89
+ background: #5CB811;
90
+ background: rgba(92,184,17,.9);
91
+ }
92
+
93
+ .alertify,
94
+ .alertify-show,
95
+ .alertify-log {
96
+ -webkit-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
97
+ -moz-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
98
+ -ms-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
99
+ -o-transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275);
100
+ transition: all 500ms cubic-bezier(0.175, 0.885, 0.320, 1.275); /* easeOutBack */
101
+ }
102
+ .alertify-hide {
103
+ -webkit-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
104
+ -moz-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
105
+ -ms-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
106
+ -o-transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
107
+ transition: all 250ms cubic-bezier(0.600, -0.280, 0.735, 0.045); /* easeInBack */
108
+ }
109
+ .alertify-log-hide {
110
+ -webkit-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
111
+ -moz-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
112
+ -ms-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
113
+ -o-transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045);
114
+ transition: all 500ms cubic-bezier(0.600, -0.280, 0.735, 0.045); /* easeInBack */
115
+ }
116
+ .alertify-cover {
117
+ position: fixed; z-index: 99999;
118
+ top: 0; right: 0; bottom: 0; left: 0;
119
+ background-color:white;
120
+ filter:alpha(opacity=0);
121
+ opacity:0;
122
+ }
123
+ .alertify-cover-hidden {
124
+ display: none;
125
+ }
126
+ .alertify {
127
+ position: fixed; z-index: 99999;
128
+ top: 50px; left: 50%;
129
+ width: 550px;
130
+ margin-left: -275px;
131
+ opacity: 1;
132
+ }
133
+ .alertify-hidden {
134
+ -webkit-transform: translate(0,-150px);
135
+ -moz-transform: translate(0,-150px);
136
+ -ms-transform: translate(0,-150px);
137
+ -o-transform: translate(0,-150px);
138
+ transform: translate(0,-150px);
139
+ opacity: 0;
140
+ display: none;
141
+ }
142
+ /* overwrite display: none; for everything except IE6-8 */
143
+ :root *> .alertify-hidden {
144
+ display: block;
145
+ visibility: hidden;
146
+ }
147
+ .alertify-logs {
148
+ position: fixed;
149
+ z-index: 5000;
150
+ bottom: 10px;
151
+ right: 10px;
152
+ width: 300px;
153
+ }
154
+ .alertify-logs-hidden {
155
+ display: none;
156
+ }
157
+ .alertify-log {
158
+ display: block;
159
+ margin-top: 10px;
160
+ position: relative;
161
+ right: -300px;
162
+ opacity: 0;
163
+ }
164
+ .alertify-log-show {
165
+ right: 0;
166
+ opacity: 1;
167
+ }
168
+ .alertify-log-hide {
169
+ -webkit-transform: translate(300px, 0);
170
+ -moz-transform: translate(300px, 0);
171
+ -ms-transform: translate(300px, 0);
172
+ -o-transform: translate(300px, 0);
173
+ transform: translate(300px, 0);
174
+ opacity: 0;
175
+ }
176
+ .alertify-dialog {
177
+ padding: 25px;
178
+ }
179
+ .alertify-resetFocus {
180
+ border: 0;
181
+ clip: rect(0 0 0 0);
182
+ height: 1px;
183
+ margin: -1px;
184
+ overflow: hidden;
185
+ padding: 0;
186
+ position: absolute;
187
+ width: 1px;
188
+ }
189
+ .alertify-inner {
190
+ text-align: center;
191
+ }
192
+ .alertify-text {
193
+ margin-bottom: 15px;
194
+ width: 100%;
195
+ -webkit-box-sizing: border-box;
196
+ -moz-box-sizing: border-box;
197
+ box-sizing: border-box;
198
+ font-size: 100%;
199
+ }
200
+ .alertify-buttons {
201
+ }
202
+ .alertify-button,
203
+ .alertify-button:hover,
204
+ .alertify-button:active,
205
+ .alertify-button:visited {
206
+ background: none;
207
+ text-decoration: none;
208
+ border: none;
209
+ /* line-height and font-size for input button */
210
+ line-height: 1.5;
211
+ font-size: 100%;
212
+ display: inline-block;
213
+ cursor: pointer;
214
+ margin-left: 5px;
215
+ }
216
+
217
+ @media only screen and (max-width: 680px) {
218
+ .alertify,
219
+ .alertify-logs {
220
+ width: 90%;
221
+ -webkit-box-sizing: border-box;
222
+ -moz-box-sizing: border-box;
223
+ box-sizing: border-box;
224
+ }
225
+ .alertify {
226
+ left: 5%;
227
+ margin: 0;
228
+ }
229
+ }
230
+
231
+
232
+ textarea {
233
+ resize: none;
234
+ display: block;
235
+ width: 100%;
236
+ max-width:none;
237
+ }
238
+
239
+ .fade{
240
+ position: absolute;
241
+ display: none;
242
+ background-color:#FFF;
243
+ opacity: 0.7;
244
+ filter: alpha(opacity=70);
245
+ }
246
+
247
+ .form-control {
248
+ display: block;
249
+ width: 100%;
250
+ height: 34px;
251
+ padding: 6px;
252
+ font-size: 14px;
253
+ line-height: 1.42857143;
254
+ color: #555555;
255
+ background-color: #ffffff;
256
+ background-image: none;
257
+ border: 1px solid #cccccc;
258
+ border-radius: 4px;
259
+ -webkit-box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
260
+ box-shadow: inset 0 1px 1px rgba(0, 0, 0, 0.075);
261
+ -webkit-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
262
+ -o-transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
263
+ transition: border-color ease-in-out .15s, box-shadow ease-in-out .15s;
264
+ }
265
+ .form-control:focus {
266
+ border-color: #66afe9;
267
+ background-color: #fff;
268
+ outline: 0;
269
+ -webkit-box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
270
+ box-shadow: inset 0 1px 1px rgba(0,0,0,.075), 0 0 8px rgba(102, 175, 233, 0.6);
271
+ }
272
+ .form-control::-moz-placeholder {
273
+ color: #999999;
274
+ opacity: 1;
275
+ }
276
+ .form-control:-ms-input-placeholder {
277
+ color: #999999;
278
+ }
279
+ .form-control::-webkit-input-placeholder {
280
+ color: #999999;
281
+ }
282
+ .form-control[disabled],
283
+ .form-control[readonly],
284
+ fieldset[disabled] .form-control {
285
+ cursor: not-allowed;
286
+ background-color: #eeeeee;
287
+ opacity: 1;
288
+ }
289
+ textarea.form-control {
290
+ height: auto;
291
+ }
292
+
293
+ .buttons-opti,
294
+ .buttons-opti:hover{
295
+ height: auto;
296
+ width: 100%;
297
+ color: <?php echo $fontcolor; ?> ;
298
+ padding: 12px 30px;
299
+ font-size: 14px;
300
+ font-weight: bold;
301
+ text-transform: uppercase;
302
+ border: 0;
303
+ border-radius: 10px;
304
+ text-decoration: none;
305
+ -moz-border-radius: 10px;
306
+ -webkit-border-radius: 10px;
307
+ cursor: pointer;
308
+ }
309
+
310
+ .discount-opti{
311
+ color:green;
312
+ font-weight: bold;
313
+ }
314
+
315
+ .buttons-purple{
316
+ background-color: <?php echo $buttoncolor; ?> ;
317
+ }
318
+
319
+ .form-group{
320
+ margin-bottom:20px;
321
+ }
322
+
323
+ </style>
324
+
325
+ <div id="main-optipricer">
326
+ <div class="fade"></div>
327
+ <div id="background1">
328
+ <form name="widget-form" action="#" method="post">
329
+ <textarea id="form_comment" rows="5" class="form-group form-control"><?php echo $transComment;?></textarea>
330
+ <button id="optibutton" type="button" class="buttons-opti buttons-purple form-group"><?php echo $transButton;?></button>
331
+ </form>
332
+ </div>
333
+ </div>
334
+ <hr>
335
+ <script>
336
+ var cp = new Coupon(<?php echo $offer['name'];?>, "<?php echo $offer['data'];?>", "<?php echo $offer['store_token'];?>", "<?php echo $offer['product_id']; ?>", <?php echo $offer['o_price']; ?>, "<?php echo $offer['formatted_price']?>", "<?php echo $offer['url_api'];?>", "<?php echo $offer['currency'];?>");
337
+
338
+ function statusChangeCallback(response) {
339
+ cp.readCookie();
340
+ var logged = cp.getLoginStatus(response);
341
+ if (cp.cookie && logged) {
342
+ cp.handleRequest(null);
343
+ } else {
344
+ cp.removeSpin();
345
+ }
346
+ }
347
+ window.fbAsyncInit = function () {
348
+ FB.init({
349
+ appId: '263200773711733',
350
+ xfbml: true,
351
+ version: 'v2.2'
352
+ });
353
+
354
+ FB.getLoginStatus(function (response) {
355
+ statusChangeCallback(response);
356
+ });
357
+ };
358
+
359
+ (function (d, s, id) {
360
+ var js, fjs = d.getElementsByTagName(s)[0];
361
+ if (d.getElementById(id)) {
362
+ return;
363
+ }
364
+ js = d.createElement(s);
365
+ js.id = id;
366
+ js.src = "//connect.facebook.net/<?php echo $offer['locale'];?>/all.js";
367
+ fjs.parentNode.insertBefore(js, fjs);
368
+ }(document, 'script', 'facebook-jssdk'));
369
+ </script>
370
+
371
+
app/etc/modules/SWE_Optipricer.xml ADDED
@@ -0,0 +1,13 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <config>
3
+ <modules>
4
+ <SWE_Optipricer>
5
+ <active>true</active>
6
+ <codePool>local</codePool>
7
+ <depends>
8
+ <Mage_Cms />
9
+ </depends>
10
+ <version>1.0.0</version>
11
+ </SWE_Optipricer>
12
+ </modules>
13
+ </config>
app/locale/en_US/SWE_Optipricer.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ "Share and get a discount!"
2
+ "Hey! Check this"
3
+ "I found on"
4
+ "I loved it!"
5
+ "cennasssss"
app/locale/pt_PT/SWE_Optipricer.csv ADDED
@@ -0,0 +1,5 @@
 
 
 
 
 
1
+ "Share and get a discount!", "Partilhe e ganhe um desconto!"
2
+ "Hey! Check this", "Hey! Vê este produto"
3
+ "I found on", "que encontrei na loja"
4
+ "I loved it!", "Eu achei o máximo!"
5
+ "cennasssss", "coisasss"
js/swe/optialert.min.js ADDED
@@ -0,0 +1 @@
 
1
+ !function(a,b){"use strict";var c,d=a.document;c=function(){var c,e,f,g,h,i,j,k,l,m,n,o,p,q={},r={},s=!1,t={ENTER:13,ESC:27,SPACE:32},u=[];return r={buttons:{holder:'<nav class="alertify-buttons">{{buttons}}</nav>',submit:'<button type="submit" class="alertify-button alertify-button-ok" id="alertify-ok">{{ok}}</button>',ok:'<button class="alertify-button alertify-button-ok" id="alertify-ok">{{ok}}</button>',cancel:'<button class="alertify-button alertify-button-cancel" id="alertify-cancel">{{cancel}}</button>'},input:'<div class="alertify-text-wrapper"><input type="text" class="alertify-text" id="alertify-text"></div>',message:'<p class="alertify-message">{{message}}</p>',log:'<article class="alertify-log{{class}}">{{message}}</article>'},p=function(){var a,c,e=!1,f=d.createElement("fakeelement"),g={WebkitTransition:"webkitTransitionEnd",MozTransition:"transitionend",OTransition:"otransitionend",transition:"transitionend"};for(a in g)if(f.style[a]!==b){c=g[a],e=!0;break}return{type:c,supported:e}},c=function(a){return d.getElementById(a)},q={labels:{ok:"OK",cancel:"Cancel"},delay:5e3,buttonReverse:!1,buttonFocus:"ok",transition:b,addListeners:function(a){var b,c,i,j,k,l="undefined"!=typeof f,m="undefined"!=typeof e,n="undefined"!=typeof o,p="",q=this;b=function(b){return"undefined"!=typeof b.preventDefault&&b.preventDefault(),i(b),"undefined"!=typeof o&&(p=o.value),"function"==typeof a&&("undefined"!=typeof o?a(!0,p):a(!0)),!1},c=function(b){return"undefined"!=typeof b.preventDefault&&b.preventDefault(),i(b),"function"==typeof a&&a(!1),!1},i=function(){q.hide(),q.unbind(d.body,"keyup",j),q.unbind(g,"focus",k),l&&q.unbind(f,"click",b),m&&q.unbind(e,"click",c)},j=function(a){var d=a.keyCode;(d===t.SPACE&&!n||n&&d===t.ENTER)&&b(a),d===t.ESC&&m&&c(a)},k=function(){n?o.focus():!m||q.buttonReverse?f.focus():e.focus()},this.bind(g,"focus",k),this.bind(h,"focus",k),l&&this.bind(f,"click",b),m&&this.bind(e,"click",c),this.bind(d.body,"keyup",j),this.transition.supported||this.setFocus()},bind:function(a,b,c){"function"==typeof a.addEventListener?a.addEventListener(b,c,!1):a.attachEvent&&a.attachEvent("on"+b,c)},handleErrors:function(){if("undefined"!=typeof a.onerror){var b=this;return a.onerror=function(a,c,d){b.error("["+a+" on line "+d+" of "+c+"]",0)},!0}return!1},appendButtons:function(a,b){return this.buttonReverse?b+a:a+b},build:function(a){var b="",c=a.type,d=a.message,e=a.cssClass||"";switch(b+='<div class="alertify-dialog">',b+='<a id="alertify-resetFocusBack" class="alertify-resetFocus" href="#">Reset Focus</a>',"none"===q.buttonFocus&&(b+='<a href="#" id="alertify-noneFocus" class="alertify-hidden"></a>'),"prompt"===c&&(b+='<div id="alertify-form">'),b+='<article class="alertify-inner">',b+=r.message.replace("{{message}}",d),"prompt"===c&&(b+=r.input),b+=r.buttons.holder,b+="</article>","prompt"===c&&(b+="</div>"),b+='<a id="alertify-resetFocus" class="alertify-resetFocus" href="#">Reset Focus</a>',b+="</div>",c){case"confirm":b=b.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.ok)),b=b.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"prompt":b=b.replace("{{buttons}}",this.appendButtons(r.buttons.cancel,r.buttons.submit)),b=b.replace("{{ok}}",this.labels.ok).replace("{{cancel}}",this.labels.cancel);break;case"alert":b=b.replace("{{buttons}}",r.buttons.ok),b=b.replace("{{ok}}",this.labels.ok)}return l.className="alertify alertify-"+c+" "+e,k.className="alertify-cover",b},close:function(a,b){var c,d,e=b&&!isNaN(b)?+b:this.delay,f=this;this.bind(a,"click",function(){c(a)}),d=function(a){a.stopPropagation(),f.unbind(this,f.transition.type,d),m.removeChild(this),m.hasChildNodes()||(m.className+=" alertify-logs-hidden")},c=function(a){"undefined"!=typeof a&&a.parentNode===m&&(f.transition.supported?(f.bind(a,f.transition.type,d),a.className+=" alertify-log-hide"):(m.removeChild(a),m.hasChildNodes()||(m.className+=" alertify-logs-hidden")))},0!==b&&setTimeout(function(){c(a)},e)},dialog:function(a,b,c,e,f){j=d.activeElement;var g=function(){m&&null!==m.scrollTop&&k&&null!==k.scrollTop||g()};if("string"!=typeof a)throw new Error("message must be a string");if("string"!=typeof b)throw new Error("type must be a string");if("undefined"!=typeof c&&"function"!=typeof c)throw new Error("fn must be a function");return this.init(),g(),u.push({type:b,message:a,callback:c,placeholder:e,cssClass:f}),s||this.setup(),this},extend:function(a){if("string"!=typeof a)throw new Error("extend method must have exactly one paramter");return function(b,c){return this.log(b,a,c),this}},hide:function(){var a,b=this;u.splice(0,1),u.length>0?this.setup(!0):(s=!1,a=function(c){c.stopPropagation(),b.unbind(l,b.transition.type,a)},this.transition.supported?(this.bind(l,this.transition.type,a),l.className="alertify alertify-hide alertify-hidden"):l.className="alertify alertify-hide alertify-hidden alertify-isHidden",k.className="alertify-cover alertify-cover-hidden",j.focus())},init:function(){d.createElement("nav"),d.createElement("article"),d.createElement("section"),null==c("alertify-cover")&&(k=d.createElement("div"),k.setAttribute("id","alertify-cover"),k.className="alertify-cover alertify-cover-hidden",d.body.appendChild(k)),null==c("alertify")&&(s=!1,u=[],l=d.createElement("section"),l.setAttribute("id","alertify"),l.className="alertify alertify-hidden",d.body.appendChild(l)),null==c("alertify-logs")&&(m=d.createElement("section"),m.setAttribute("id","alertify-logs"),m.className="alertify-logs alertify-logs-hidden",d.body.appendChild(m)),d.body.setAttribute("tabindex","0"),this.transition=p()},log:function(a,b,c){var d=function(){m&&null!==m.scrollTop||d()};return this.init(),d(),m.className="alertify-logs",this.notify(a,b,c),this},notify:function(a,b,c){var e=d.createElement("article");e.className="alertify-log"+("string"==typeof b&&""!==b?" alertify-log-"+b:""),e.innerHTML=a,m.appendChild(e),setTimeout(function(){e.className=e.className+" alertify-log-show"},50),this.close(e,c)},set:function(a){var b;if("object"!=typeof a&&a instanceof Array)throw new Error("args must be an object");for(b in a)a.hasOwnProperty(b)&&(this[b]=a[b])},setFocus:function(){o?(o.focus(),o.select()):i.focus()},setup:function(a){var d,j=u[0],k=this;s=!0,d=function(a){a.stopPropagation(),k.setFocus(),k.unbind(l,k.transition.type,d)},this.transition.supported&&!a&&this.bind(l,this.transition.type,d),l.innerHTML=this.build(j),g=c("alertify-resetFocus"),h=c("alertify-resetFocusBack"),f=c("alertify-ok")||b,e=c("alertify-cancel")||b,i="cancel"===q.buttonFocus?e:"none"===q.buttonFocus?c("alertify-noneFocus"):f,o=c("alertify-text")||b,n=c("alertify-form")||b,"string"==typeof j.placeholder&&""!==j.placeholder&&(o.value=j.placeholder),a&&this.setFocus(),this.addListeners(j.callback)},unbind:function(a,b,c){"function"==typeof a.removeEventListener?a.removeEventListener(b,c,!1):a.detachEvent&&a.detachEvent("on"+b,c)}},{alert:function(a,b,c){return q.dialog(a,"alert",b,"",c),this},confirm:function(a,b,c){return q.dialog(a,"confirm",b,"",c),this},extend:q.extend,init:q.init,log:function(a,b,c){return q.log(a,b,c),this},prompt:function(a,b,c,d){return q.dialog(a,"prompt",b,c,d),this},success:function(a,b){return q.log(a,"success",b),this},error:function(a,b){return q.log(a,"error",b),this},set:function(a){q.set(a)},labels:q.labels,debug:q.handleErrors}},"function"==typeof define?define([],function(){return new c}):"undefined"==typeof a.alertify&&(a.alertify=new c)}(this);
js/swe/optipricer.min.js ADDED
@@ -0,0 +1 @@
 
1
+ function Coupon(e,t,i,s,n,o,r,a){var c={n:e,d:t,st:i,p:s,o_p:n,o_pf:o,url:r,ps:a};this._initialize(c),this.setSpin();var h=this;document.getElementById("optibutton").addEventListener("click",function(e){e.preventDefault(),e.stopPropagation(),h.socialCredentials&&h.socialCredentials.facebookToken?(h.sendForm(),h.lockPermissions=!0):(h.checkLogin(h.perms,!0),h.lockPermissions=!1)})}function treatError(e,t,i){var s='{"msg":"'+e+'", "url":"'+t+'", "line":'+i+"}";sendRequest("logs/create","post",s,500,1,function(){})}function sendRequest(e,t,i,s,n,o){var r=cp.url+""+e,a="Token "+cp.st,c=null,h=new XMLHttpRequest;h.open(t.toUpperCase(),encodeURI(r),!0),h.setRequestHeader("Authorization",a),h.onreadystatechange=function l(){200!=h.status&&201!=h.status&&204!=h.status&&304!=h.status?(n++,s=4*s,6>n&&(c=window.setTimeout(function(){h.open(t.toUpperCase(),encodeURI(r),!0),h.onreadystatechange=l(),h.send(i)},s))):(c&&clearTimeout(c),o(h))},null!==i&&h.send(i)}var coupon={_initialize:function(e){this.d=e.d,this.n=e.n,this.st=e.st,this.p=e.p,this.ck_n="discount_"+this.st+"_"+this.p,this.url=e.url,this.o_p=e.o_p,this.o_pf=e.o_pf,this.p_s=e.ps,this.v=null,this.html=null,this.opts={lines:13,length:10,width:5,radius:10,corners:1,rotate:0,direction:1,color:"#010046",speed:1,trail:60,shadow:!0,hwaccel:!1,className:"spinner",zIndex:2e9,top:"43%",left:"54%"},this.spinner=new Spinner(this.opts),this.perms=["email","read_stream","user_interests","user_relationships","user_birthday","user_likes","user_work_history","user_education_history","publish_actions"]},_findRiskPrice:function(e){var t=this._htmlTree(document.getElementById("main-optipricer"),this.n);t&&this._riskPrice(t,e)},_htmlTree:function(e,t){var i=null;if(e.parentNode){var s=e.parentNode;s.childNodes.length>1&&(i=this._searchParent(s,t)),null===i&&this._htmlTree(s.parentNode,t)}return i},_replaceDiv:function(e,t,i){var s=document.getElementById(e);if(i)s.innerHTML="",s.innerHTML=t;else{var n=document.getElementById("opti-fbmessage");n?n.innerText=t:(n=document.createElement("h4"),n.id="opti-fbmessage",n.innerText=t,s.appendChild(n))}},_riskPrice:function(e,t){var i,s,n,o,r=e.childNodes,a=this.o_p.toString().replace(".",",");for(i=0;i<r.length;i++)r[i].hasChildNodes()&&r[i].innerHTML?this._riskPrice(r[i],t):(o=void 0!==r[i].innerHTML?r[i].innerHTML:r[i].data,n=e.parentNode,-1===o.indexOf(this.p_s)||-1===o.indexOf(this.o_pf)&&-1===o.indexOf(a)||-1!==n.className.indexOf("opti-discount")||(this.p_symbol=o.indexOf(this.p_s)>3?!0:!1,s=e.cloneNode(!0),s.innerHTML=this.getPriceToPrint(-1!==o.indexOf(".")?!0:!1),s.style.display="block",n.className=n.className+" opti-discount",n.appendChild(s),e.style.textDecoration="line-through"))},_searchParent:function(e,t){var i,s=e.childNodes;for(i=0;i<s.length;i++)if(void 0!==s[i].tagName&&"main-optipricer"!==s[i].id){if(-1!==s[i].innerHTML.indexOf(t))return e;s[i].hasChildNodes()&&this._searchParent(s[i],t)}return null},_toHtml:function(){var e=document.createElement("h2"),t=document.createElement("div");return t.id="optipricerdiscount"," "+e.outerHTML+" "+t.outerHTML},_missingPermissions:function(e){var t,i,s=[];if(e){for(i=0;i<this.perms.length;i++){var n=!1;for(t=0;t<e.length;t++)e[t].permission===this.perms[i]&&"granted"===e[t].status&&(n=!0,t=e.length);n||s.push(this.perms[i])}return s}return void 0},checkLogin:function(e,t){var i=this;FB.login(function(e){i.getLoginStatus(e)&&(i.cookie?i.handleRequest(null):FB.api("/v2.2/"+i.socialCredentials.facebookId+"/permissions","GET",function(e){var s=i._missingPermissions(e.data);0===s.length?i.sendForm():t&&i.sendForm()}))},{scope:e.join(",")})},checkPermissions:function(e){if(this.lockPermissions){var t=this,i=[];FB.api("/v2.2/"+t.socialCredentials.facebookId+"/permissions","GET",function(s){i=t._missingPermissions(s.data),void 0===i?t.checkLogin(t.perms,!0):i.length>0&&(t._replaceDiv("background1",e,!1),t.checkLogin(i,!1))}),this.removeSpin()}else this._replaceDiv("background1",e,!1),this.removeSpin()},createCookie:function(){document.cookie=this.ck_n+"="+this.c+":"+this.n+":"+this.v+":"+this.socialCredentials.facebookId+"; expires="+this.expires+"; path=/"},getLoginStatus:function(e){if("connected"===e.status){var t={facebookId:e.authResponse.userID,facebookToken:e.authResponse.accessToken};return this.setSocialCredentials(t),!0}return!1},getPriceToPrint:function(e){var t=e?this.v.toString():this.v.toString().replace(".",",");return this.p_symbol?t+" "+this.p_s:this.p_s+" "+t},handleErrors:function(e){var t=JSON.parse(e.responseText);switch(t.errorCode){case 1:case 2:case 3:case 4:case 6:this.removeSpin(),this._replaceDiv("main-optipricer",t.html,!0);break;case 5:this.checkPermissions(t.message)}},handleRequest:function(e){var t;e&&(t=JSON.parse(e.response),this.c=t.coupon,this.v=t.value,this.expires=new Date(1e3*t.expiryTime).toString(),this.createCookie()),this._findRiskPrice(this.v),this.removeSpin(),this.html=t&&t.html?t.html:this.html?this.html:this._toHtml(),this._replaceDiv("background1",this.html,!0);var i=(this.o_p-this.v)/this.o_p*100;document.getElementById("optipricerdiscount").innerHTML="<h5>You got a <span class='discount-opti'>"+i.toFixed(0)+"%</span> discount</h5>"},readCookie:function(){this.setSpin();var e="; "+document.cookie,t=e.split("; "+this.ck_n+"=");if(2===t.length){var i=t[1].split(":");this.cookie=!0,this.c=i[0],this.n=i[1],this.v=i[2],this.socialCredentials={},this.socialCredentials.facebookId=i[3].split(";")[0]}else this.cookie=!1},removeSpin:function(){var e=document.getElementsByClassName("fade")[0];e.style.display="none",this.spinner.stop()},sendForm:function(){this.setComment(document.getElementById("form_comment").value);var e=this.toJson();if(this.comment.length>2){document.getElementById("form_comment").setCustomValidity("");var t=this.url+"coupon/",i=[["Authorization","Token "+this.st]];i.push(["Accept","application/json"]),this.setSpin(),this.sendRequest(t,"POST",i,e,this)}else alertify.custom=alertify.extend("custom"),alertify.custom("You must comment something about the product..")},sendRequest:function(e,t,i,s,n){var o,r=new XMLHttpRequest,a=!0;for(r.open(t.toUpperCase(),encodeURI(e),!0),o=0;o<i.length;o++)2===i[o].length?r.setRequestHeader(i[o][0],i[o][1]):a=!1;if(a){var c=0;r.onreadystatechange=function(){if(200!=r.status&&201!=r.status&&204!=r.status&&304!=r.status)try{JSON.parse(r.responseText),""!==r.responseText&&0===c&&(c++,n.handleErrors(r))}catch(t){n.removeSpin(),treatError("[widget-magento]"+t.message,e,0)}else n.handleRequest(r)},null!==s&&r.send(new Blob([s],{type:"application/json"}))}else console.log("The input headers are defined wrong, must be a bi dimensional array, header[x][2]")},setComment:function(e){this.comment=e},setSocialCredentials:function(e){this.socialCredentials?this.socialCredentials.facebookId===e.facebookId?this.socialCredentials.facebookToken=e.facebookToken:(this.cookie=!1,this.socialCredentials.facebookId=e.facebookId,this.socialCredentials.facebookToken=e.facebookToken):(this.socialCredentials={},this.socialCredentials.facebookId=e.facebookId,this.socialCredentials.facebookToken=e.facebookToken)},setSpin:function(){var e=document.getElementsByClassName("fade")[0],t=document.getElementById("main-optipricer");e.style.display="block",e.style.width=t.offsetWidth+"px",e.style.height=t.offsetHeight+"px",this.spinner.spin(e)},toJson:function(){var e={data:this.d,social_credentials:this.socialCredentials,comment:this.comment};return JSON.stringify(e)}};Coupon.prototype=coupon,window.onerror=function(e,t,i){treatError(e,t,i)};
js/swe/optispin.min.js ADDED
@@ -0,0 +1,2 @@
 
 
1
+ //fgnass.github.com/spin.js#v2.0.1
2
+ !function(a,b){"object"==typeof exports?module.exports=b():"function"==typeof define&&define.amd?define(b):a.Spinner=b()}(this,function(){"use strict";function a(a,b){var c,d=document.createElement(a||"div");for(c in b)d[c]=b[c];return d}function b(a){for(var b=1,c=arguments.length;c>b;b++)a.appendChild(arguments[b]);return a}function c(a,b,c,d){var e=["opacity",b,~~(100*a),c,d].join("-"),f=.01+c/d*100,g=Math.max(1-(1-a)/b*(100-f),a),h=j.substring(0,j.indexOf("Animation")).toLowerCase(),i=h&&"-"+h+"-"||"";return l[e]||(m.insertRule("@"+i+"keyframes "+e+"{0%{opacity:"+g+"}"+f+"%{opacity:"+a+"}"+(f+.01)+"%{opacity:1}"+(f+b)%100+"%{opacity:"+a+"}100%{opacity:"+g+"}}",m.cssRules.length),l[e]=1),e}function d(a,b){var c,d,e=a.style;for(b=b.charAt(0).toUpperCase()+b.slice(1),d=0;d<k.length;d++)if(c=k[d]+b,void 0!==e[c])return c;return void 0!==e[b]?b:void 0}function e(a,b){for(var c in b)a.style[d(a,c)||c]=b[c];return a}function f(a){for(var b=1;b<arguments.length;b++){var c=arguments[b];for(var d in c)void 0===a[d]&&(a[d]=c[d])}return a}function g(a,b){return"string"==typeof a?a:a[b%a.length]}function h(a){this.opts=f(a||{},h.defaults,n)}function i(){function c(b,c){return a("<"+b+' xmlns="urn:schemas-microsoft.com:vml" class="spin-vml">',c)}m.addRule(".spin-vml","behavior:url(#default#VML)"),h.prototype.lines=function(a,d){function f(){return e(c("group",{coordsize:k+" "+k,coordorigin:-j+" "+-j}),{width:k,height:k})}function h(a,h,i){b(m,b(e(f(),{rotation:360/d.lines*a+"deg",left:~~h}),b(e(c("roundrect",{arcsize:d.corners}),{width:j,height:d.width,left:d.radius,top:-d.width>>1,filter:i}),c("fill",{color:g(d.color,a),opacity:d.opacity}),c("stroke",{opacity:0}))))}var i,j=d.length+d.width,k=2*j,l=2*-(d.width+d.length)+"px",m=e(f(),{position:"absolute",top:l,left:l});if(d.shadow)for(i=1;i<=d.lines;i++)h(i,-2,"progid:DXImageTransform.Microsoft.Blur(pixelradius=2,makeshadow=1,shadowopacity=.3)");for(i=1;i<=d.lines;i++)h(i);return b(a,m)},h.prototype.opacity=function(a,b,c,d){var e=a.firstChild;d=d.shadow&&d.lines||0,e&&b+d<e.childNodes.length&&(e=e.childNodes[b+d],e=e&&e.firstChild,e=e&&e.firstChild,e&&(e.opacity=c))}}var j,k=["webkit","Moz","ms","O"],l={},m=function(){var c=a("style",{type:"text/css"});return b(document.getElementsByTagName("head")[0],c),c.sheet||c.styleSheet}(),n={lines:12,length:7,width:5,radius:10,rotate:0,corners:1,color:"#000",direction:1,speed:1,trail:100,opacity:.25,fps:20,zIndex:2e9,className:"spinner",top:"50%",left:"50%",position:"absolute"};h.defaults={},f(h.prototype,{spin:function(b){this.stop();{var c=this,d=c.opts,f=c.el=e(a(0,{className:d.className}),{position:d.position,width:0,zIndex:d.zIndex});d.radius+d.length+d.width}if(e(f,{left:d.left,top:d.top}),b&&b.insertBefore(f,b.firstChild||null),f.setAttribute("role","progressbar"),c.lines(f,c.opts),!j){var g,h=0,i=(d.lines-1)*(1-d.direction)/2,k=d.fps,l=k/d.speed,m=(1-d.opacity)/(l*d.trail/100),n=l/d.lines;!function o(){h++;for(var a=0;a<d.lines;a++)g=Math.max(1-(h+(d.lines-a)*n)%l*m,d.opacity),c.opacity(f,a*d.direction+i,g,d);c.timeout=c.el&&setTimeout(o,~~(1e3/k))}()}return c},stop:function(){var a=this.el;return a&&(clearTimeout(this.timeout),a.parentNode&&a.parentNode.removeChild(a),this.el=void 0),this},lines:function(d,f){function h(b,c){return e(a(),{position:"absolute",width:f.length+f.width+"px",height:f.width+"px",background:b,boxShadow:c,transformOrigin:"left",transform:"rotate("+~~(360/f.lines*k+f.rotate)+"deg) translate("+f.radius+"px,0)",borderRadius:(f.corners*f.width>>1)+"px"})}for(var i,k=0,l=(f.lines-1)*(1-f.direction)/2;k<f.lines;k++)i=e(a(),{position:"absolute",top:1+~(f.width/2)+"px",transform:f.hwaccel?"translate3d(0,0,0)":"",opacity:f.opacity,animation:j&&c(f.opacity,f.trail,l+k*f.direction,f.lines)+" "+1/f.speed+"s linear infinite"}),f.shadow&&b(i,e(h("#000","0 0 4px #000"),{top:"2px"})),b(d,b(i,h(g(f.color,k),"0 0 1px rgba(0,0,0,.1)")));return d},opacity:function(a,b,c){b<a.childNodes.length&&(a.childNodes[b].style.opacity=c)}});var o=e(a("group"),{behavior:"url(#default#VML)"});return!d(o,"transform")&&o.adj?i():j=d(o,"animation"),h});
package.xml ADDED
@@ -0,0 +1,20 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>SweOptipricer</name>
4
+ <version>0.1.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://opensource.org/licenses/LGPL-3.0">GNU Lesser General Public License (LGPL)</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>Calculate best price for each customer</summary>
10
+ <description>The extension provides a widget that uses the Optipricer API to create promotions for your products.&#xD;
11
+ Customers will receive a discount after a successful product share on Facebook.&#xD;
12
+ For more information www.optipricer.com</description>
13
+ <notes>Testing candidate</notes>
14
+ <authors><author><name>Rui Mendes</name><user>ruidamendes</user><email>rui.mendes@beubi.com</email></author><author><name>beubi</name><user>beubi</user><email>swe@beubi.com</email></author></authors>
15
+ <date>2015-02-13</date>
16
+ <time>18:58:31</time>
17
+ <contents><target name="magelocal"><dir name="SWE"><dir name="Optipricer"><dir name="Block"><file name="Button.php" hash="8ed206abaf5cb543c1ecdee14edffeb8"/><file name="Discount.php" hash="94eeb6ed1d031ce824b7979ac684e882"/></dir><dir name="Helper"><file name="Data.php" hash="d0fe8d14d8322200cd61852652572f2c"/></dir><dir name="Model"><file name="Config.php" hash="b3b4dbb1fcae77bf0b06cbb51b688269"/><file name="Observer.php" hash="0d822491b36a5a11770232bc688ba1b8"/></dir><dir name="controllers"><dir name="Adminhtml"><file name="SweoptipricerController.php" hash="a8298c06a29de784667fab43874d7bfa"/></dir></dir><dir name="etc"><file name="config.xml" hash="ac94752d4f796ccd3b9646503d15b25c"/><file name="system.xml" hash="e3c6666a5bea0b84720648ff0f8a0930"/><file name="widget.xml" hash="fbc9c4137471aaffb1d6a39d6bbaca56"/><file name=".gitignore" hash="8bbba098c1565b7ecf097c21a8df20c7"/></dir></dir></dir></target><target name="magedesign"><dir name="frontend"><dir name="base"><dir name="default"><dir name="template"><dir name="swe"><dir name="optipricer"><file name="widget.phtml" hash="d0b4396cdfc3ac7ec21cd88626935315"/></dir></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="SWE_Optipricer.xml" hash="225863b467db416b4db8b754cf73efa1"/></dir></target><target name="magelocale"><dir name="en_US"><file name="SWE_Optipricer.csv" hash="2c27e6a50f20ae1318274d6fa8b17bfd"/></dir><dir name="pt_PT"><file name="SWE_Optipricer.csv" hash="7ac9dd9cf8e434d982a003789a0cd826"/></dir></target><target name="mage"><dir name="js"><dir name="swe"><file name="optialert.min.js" hash="d819c38f0c3c8ef8a084154da96667eb"/><file name="optipricer.min.js" hash="5fad2fc014c5d54956a4ade5c05c7681"/><file name="optispin.min.js" hash="f2b0a61b3a739d03e88401e2a1163588"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="template"><dir name="swe"><dir name="optipricer"><dir name="system"><dir name="config"><file name="button.phtml" hash=""/></dir></dir></dir></dir></dir></dir></dir></dir></target></contents>
18
+ <compatible/>
19
+ <dependencies><required><php><min>5.3.10</min><max>6.0.0</max></php></required></dependencies>
20
+ </package>