nypwidget - Version 2.0.0

Version Notes

Features:
- New, more powerful, button configuration controls:
- Easier setup with a new assisted PriceWaiter signup process:
- Support for Automated Acceptance

Download this release

Release Info

Developer PriceWaiter
Extension nypwidget
Version 2.0.0
Comparing to
See all releases


Code changes from version 1.2.7 to 2.0.0

Files changed (46) hide show
  1. app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Link.php +30 -0
  2. app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Signup.php +55 -0
  3. app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Widget.php +6 -3
  4. app/code/community/PriceWaiter/NYPWidget/Block/Category.php +49 -35
  5. app/code/community/PriceWaiter/NYPWidget/Block/Widget.php +3 -1
  6. app/code/community/PriceWaiter/NYPWidget/Helper/Data.php +345 -223
  7. app/code/community/PriceWaiter/NYPWidget/Model/Callback.php +305 -314
  8. app/code/community/PriceWaiter/NYPWidget/Model/Carrier/ShippingMethod.php +15 -13
  9. app/code/community/PriceWaiter/NYPWidget/Model/Category.php +107 -73
  10. app/code/community/PriceWaiter/NYPWidget/Model/Display/Phrase.php +4 -2
  11. app/code/community/PriceWaiter/NYPWidget/Model/Display/Size.php +4 -2
  12. app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Category.php +7 -5
  13. app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Category/Collection.php +8 -6
  14. app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Order.php +7 -5
  15. app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Order/Collection.php +7 -5
  16. app/code/community/PriceWaiter/NYPWidget/Model/Observer.php +28 -24
  17. app/code/community/PriceWaiter/NYPWidget/Model/Order.php +20 -18
  18. app/code/community/PriceWaiter/NYPWidget/Model/PaymentMethod.php +17 -16
  19. app/code/community/PriceWaiter/NYPWidget/Model/Resource/Eav/Mysql4/Setup.php +4 -2
  20. app/code/community/PriceWaiter/NYPWidget/controllers/Adminhtml/PricewaiterController.php +98 -0
  21. app/code/community/PriceWaiter/NYPWidget/controllers/CallbackController.php +3 -1
  22. app/code/community/PriceWaiter/NYPWidget/controllers/ProductinfoController.php +164 -0
  23. app/code/community/PriceWaiter/NYPWidget/etc/adminhtml.xml +1 -1
  24. app/code/community/PriceWaiter/NYPWidget/etc/config.xml +49 -28
  25. app/code/community/PriceWaiter/NYPWidget/etc/system.xml +102 -63
  26. app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-install-1.0.0.php +1 -1
  27. app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.1.2-1.1.3.php +21 -21
  28. app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.1.7-1.1.8.php +1 -1
  29. app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.2.4-1.2.5.php +1 -1
  30. app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.3.0-1.3.1.php +54 -0
  31. app/design/adminhtml/default/default/layout/pricewaiter.xml +8 -8
  32. app/design/adminhtml/default/default/template/pricewaiter/admin_widget.phtml +0 -32
  33. app/design/adminhtml/default/default/template/pricewaiter/categorytab.phtml +41 -27
  34. app/design/adminhtml/default/default/template/pricewaiter/signup.phtml +4 -0
  35. app/design/frontend/base/default/layout/pricewaiter.xml +7 -5
  36. app/design/frontend/base/default/template/pricewaiter/widget.phtml +71 -18
  37. app/etc/modules/PriceWaiter_NYPWidget.xml +3 -3
  38. js/jscolor-pw/arrow.gif +0 -0
  39. js/jscolor-pw/cross.gif +0 -0
  40. js/jscolor-pw/hs.png +0 -0
  41. js/jscolor-pw/hv.png +0 -0
  42. js/jscolor-pw/jscolor.js +0 -935
  43. js/pricewaiter/product-pages.js +261 -285
  44. js/pricewaiter/token.js +44 -0
  45. package.xml +149 -11
  46. skin/adminhtml/default/default/pricewaiter.css +17 -17
app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Link.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ class PriceWaiter_NYPWidget_Block_Adminhtml_Link extends Varien_Data_Form_Element_Link implements Varien_Data_Form_Element_Renderer_Interface
21
+ {
22
+ public function render(Varien_Data_Form_Element_Abstract $element)
23
+ {
24
+ $helper = Mage::helper('nypwidget');
25
+ $this->setData('href', $helper->getButtonSettingsUrl());
26
+ $this->setData('target', '_blank');
27
+ $this->setData('value', 'Customize the appearance of your widget on PriceWaiter.com');
28
+ return $this->toHtml();
29
+ }
30
+ }
app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Signup.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ class PriceWaiter_NYPWidget_Block_Adminhtml_Signup extends Mage_Adminhtml_Block_System_Config_Form_Field
21
+ {
22
+ protected function _construct()
23
+ {
24
+ parent::_construct();
25
+ $this->setTemplate('pricewaiter/signup.phtml');
26
+ }
27
+
28
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $el)
29
+ {
30
+ return $this->_toHtml();
31
+ }
32
+
33
+ public function getButtonHtml()
34
+ {
35
+ // If they have already set their API key, don't show the button.
36
+ if (Mage::getStoreConfig('pricewaiter/configuration/api_key')) {
37
+ return;
38
+ }
39
+
40
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button')->setData(
41
+ array(
42
+ 'id' => 'nypwidget_signup',
43
+ 'label' => $this->helper('adminhtml')->__('Sign Up for PriceWaiter'),
44
+ 'disabled' => true
45
+ )
46
+ );
47
+
48
+ return $button->toHtml();
49
+ }
50
+
51
+ public function getTokenUrl()
52
+ {
53
+ return Mage::helper('adminhtml')->getUrl('adminhtml/adminhtml_pricewaiter/token');
54
+ }
55
+ }
app/code/community/PriceWaiter/NYPWidget/Block/Adminhtml/Widget.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,9 +16,11 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Block_Adminhtml_Widget extends Mage_Adminhtml_Block_Abstract
19
  {
20
- public function _getHelper() {
 
21
  $helper = Mage::helper('nypwidget');
22
  return $helper;
23
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Block_Adminhtml_Widget extends Mage_Adminhtml_Block_Abstract
21
  {
22
+ public function _getHelper()
23
+ {
24
  $helper = Mage::helper('nypwidget');
25
  return $helper;
26
  }
app/code/community/PriceWaiter/NYPWidget/Block/Category.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,40 +16,53 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Block_Category extends Mage_Adminhtml_Block_Template
19
- implements Mage_Adminhtml_Block_Widget_Tab_Interface
20
  {
21
- public function __construct()
22
- {
23
- $this->setTemplate('pricewaiter/categorytab.phtml');
24
- }
25
-
26
- public function getIsEnabled()
27
- {
28
- $category = Mage::registry('category');
29
- $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category, $category->getStore()->getId());
30
-
31
- return $nypcategory->isActive(true);
32
- }
33
-
34
- public function getTabLabel()
35
- {
36
- return $this->__('PriceWaiter Widget');
37
- }
38
-
39
- public function getTabTitle()
40
- {
41
- return $this->__('PriceWaiter');
42
- }
43
-
44
- public function canShowTab()
45
- {
46
- return true;
47
- }
48
-
49
- public function isHidden()
50
- {
51
- return false;
52
- }
 
 
 
 
 
 
 
 
 
 
 
 
53
 
54
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Block_Category extends Mage_Adminhtml_Block_Template
21
+ implements Mage_Adminhtml_Block_Widget_Tab_Interface
22
  {
23
+ public function __construct()
24
+ {
25
+ $this->setTemplate('pricewaiter/categorytab.phtml');
26
+ }
27
+
28
+ private function _getCategory()
29
+ {
30
+ $category = Mage::registry('category');
31
+ $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category, $category->getStore()->getId());
32
+
33
+ return $nypcategory;
34
+ }
35
+
36
+ public function getIsEnabled()
37
+ {
38
+ $category = $this->_getCategory();
39
+ return $category->isActive(true);
40
+ }
41
+
42
+ public function getIsConversionToolsEnabled()
43
+ {
44
+ $category = $this->_getCategory();
45
+ return $category->isConversionToolsEnabled(true);
46
+ }
47
+
48
+ public function getTabLabel()
49
+ {
50
+ return $this->__('PriceWaiter Widget');
51
+ }
52
+
53
+ public function getTabTitle()
54
+ {
55
+ return $this->__('PriceWaiter');
56
+ }
57
+
58
+ public function canShowTab()
59
+ {
60
+ return true;
61
+ }
62
+
63
+ public function isHidden()
64
+ {
65
+ return false;
66
+ }
67
 
68
  }
app/code/community/PriceWaiter/NYPWidget/Block/Widget.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,6 +16,7 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Block_Widget extends Mage_Core_Block_Template
19
  {
20
  public function _getHelper()
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Block_Widget extends Mage_Core_Block_Template
21
  {
22
  public function _getHelper()
app/code/community/PriceWaiter/NYPWidget/Helper/Data.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
 
3
  /*
4
- * Copyright 2013 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
@@ -19,226 +19,348 @@
19
 
20
  class PriceWaiter_NYPWidget_Helper_Data extends Mage_Core_Helper_Abstract
21
  {
22
- private $_product = false;
23
- private $_testing = false;
24
-
25
- public function isTesting()
26
- {
27
- return $this->_testing;
28
- }
29
-
30
- public function isEnabled()
31
- {
32
- // Is the pricewaiter widget enabled for this store
33
- if (Mage::getStoreConfig('pricewaiter/configuration/enabled')) {
34
-
35
- // Is the pricewaiter widget enabled for this product
36
- $product = $this->_getProduct();
37
- if (!is_object($product) or ($product->getId() and $product->getData('nypwidget_disabled'))) {
38
- return false;
39
- }
40
-
41
- // Is the PriceWaiter widget enabled for this category
42
- $category = Mage::registry('current_category');
43
- if (is_object($category)) {
44
- $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category);
45
- if (!$nypcategory->isActive()) {
46
- return false;
47
- }
48
- } else {
49
- // We end up here if we are visiting the product page without being
50
- // "in a category". Basically, we arrived via a search page.
51
- // The logic here checks to see if there are any categories that this
52
- // product belongs to that enable the PriceWaiter widget. If not, return false.
53
- $categories = $product->getCategoryIds();
54
- $categoryActive = false;
55
- foreach ($categories as $categoryId) {
56
- unset($currentCategory);
57
- unset($nypcategory);
58
- $currentCategory = Mage::getModel('catalog/category')->load($categoryId);
59
- $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($currentCategory);
60
- if ($nypcategory->isActive()) {
61
- $categoryActive = true;
62
- break;
63
- }
64
- }
65
- if (!$categoryActive) {
66
- return false;
67
- }
68
- }
69
-
70
- } else {
71
- // We end up here if PriceWaiter is disabled for this store
72
- return false;
73
- }
74
-
75
- return true;
76
- }
77
-
78
- public function getPriceWaiterOptions()
79
- {
80
- $apiKey = Mage::getStoreConfig('pricewaiter/configuration/api_key');
81
-
82
- $displayPhrase = Mage::getStoreConfig('pricewaiter/appearance/display_phrase') ? 'button_mo' : 'button_nyp';
83
- $displaySize = Mage::getStoreConfig('pricewaiter/appearance/display_size') ? 'sm' : 'lg';
84
- $displayColor = Mage::getStoreConfig('pricewaiter/appearance/display_color');
85
- $displayHoverColor = Mage::getStoreConfig('pricewaiter/appearance/display_hover_color');
86
-
87
- $pwOptions = "
88
- var PriceWaiterOptions = {
89
- apiKey: '" . $apiKey . "',
90
- button: {
91
- type: " . json_encode($displayPhrase) . ",
92
- size: " . json_encode($displaySize) . ",";
93
-
94
- if ($displayColor) {
95
- $pwOptions .= "
96
- color: " . json_encode($displayColor) . ",";
97
- }
98
-
99
- if ($displayHoverColor) {
100
- $pwOptions .= "
101
- hoverColor: " . json_encode($displayHoverColor) . ",";
102
- }
103
-
104
- $pwOptions .= "
105
- },
106
- };\n";
107
-
108
- return $pwOptions;
109
- }
110
-
111
- public function getProductOptions($admin = false)
112
- {
113
- if ($admin) {
114
- return "PriceWaiterOptions.product = {
115
- sku: 'TEST-SKU',
116
- name: 'Test Name',
117
- price: 19.99,
118
- image: 'http://placekitten.com/220/220'
119
- };
120
- var PriceWaiterProductType = 'simple';
121
- var PriceWaiterRegularPrice = 19.99";
122
- }
123
-
124
- $product = $this->_getProduct();
125
-
126
- if ($product->getId()) {
127
-
128
- switch ($product->getTypeId()) {
129
- case "simple":
130
- return $this->_pwBoilerPlate($product) . "
131
- var PriceWaiterProductType = 'simple';
132
- ";
133
- break;
134
- case "configurable":
135
- return $this->_pwBoilerPlate($product) . "
136
- var PriceWaiterProductType = 'configurable';
137
- ";
138
- break;
139
- case "grouped":
140
- return $this->_pwBoilerPlate($product) . "
141
- var PriceWaiterProductType = 'grouped';\n"
142
- . $this->_getGroupedProductInfo() ."\n";
143
- break;
144
- case "virtual":
145
- // Virtual products are not yet supported
146
- return false;
147
- break;
148
- case "bundle":
149
- return $this->_pwBoilerPlate($product) . "
150
- var PriceWaiterProductType = 'bundle';
151
- ";
152
- break;
153
- case "downloadable":
154
- // Downloadable products are not yet supported
155
- return false;
156
- break;
157
- default:
158
- return false;
159
- break;
160
- }
161
- } else {
162
- return false;
163
- }
164
- }
165
-
166
- public function getWidgetUrl()
167
- {
168
- if ($this->_testing) {
169
- return "https://testing.pricewaiter.com/nyp/script/widget.js";
170
- } else {
171
- return "https://widget.pricewaiter.com/nyp/script/widget.js";
172
- }
173
- }
174
-
175
- public function getApiUrl()
176
- {
177
- if ($this->_testing) {
178
- return "https://api-testing.pricewaiter.com/1/order/verify?"
179
- . "api_key="
180
- . Mage::getStoreConfig('pricewaiter/configuration/api_key');
181
- } else {
182
- return "https://api.pricewaiter.com/1/order/verify?api_key="
183
- . Mage::getStoreConfig('pricewaiter/configuration/api_key');
184
- }
185
- }
186
-
187
- private function _pwBoilerPlate($product)
188
- {
189
- if ($product->getTypeId() == 'grouped') {
190
- $productPrice = 0;
191
- } else {
192
- $productPrice = $product->getFinalPrice();
193
- }
194
-
195
- return "
196
- PriceWaiterOptions.product = {
197
- sku: " . json_encode($product->getSku()) . ",
198
- name: " . json_encode($product->getName()) . ",
199
- price: " . json_encode($productPrice) . ",
200
- image: " . json_encode($product->getImageUrl()) . "
201
- };
202
- var PriceWaiterRegularPrice = '" . (float)$product->getPrice() . "';
203
- ";
204
- }
205
-
206
- private function _getProduct()
207
- {
208
- if (!$this->_product) {
209
- $this->_product = Mage::registry('current_product');
210
- }
211
-
212
- return $this->_product;
213
- }
214
-
215
- private function _getGroupedProductInfo()
216
- {
217
- $product = $this->_getProduct();
218
- $javascript = "var PriceWaiterGroupedProductInfo = new Array();\n";
219
-
220
- $associatedProducts = $product->getTypeInstance(true)->getAssociatedProducts($product);
221
- foreach ($associatedProducts as $simpleProduct) {
222
- $javascript .= "PriceWaiterGroupedProductInfo[" . $simpleProduct->getId() . "] = ";
223
- $javascript .= "new Array('" . htmlentities($simpleProduct->getName()) . "', '"
224
- . number_format($simpleProduct->getPrice(), 2) . "')\n";
225
- }
226
-
227
- return $javascript;
228
- }
229
-
230
- public function getStoreByApiKey($apiKey)
231
- {
232
- $stores = Mage::app()->getStores();
233
-
234
- // Find the store with the matching API key by checking the key for each store
235
- // in Magento
236
- foreach ($stores as $store) {
237
- if ($apiKey == Mage::getStoreConfig('pricewaiter/configuration/api_key', $store->getId())) {
238
- return $store;
239
- }
240
- }
241
-
242
- return Mage::app()->getStore();
243
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
244
  }
1
  <?php
2
 
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
19
 
20
  class PriceWaiter_NYPWidget_Helper_Data extends Mage_Core_Helper_Abstract
21
  {
22
+ private $_product = false;
23
+ private $_testing = false;
24
+ private $_buttonEnabled = null;
25
+ private $_conversionToolsEnabled = null;
26
+
27
+ public function isTesting()
28
+ {
29
+ return $this->_testing;
30
+ }
31
+
32
+ public function isEnabledForStore()
33
+ {
34
+ // Is the pricewaiter widget enabled for this store and an API Key has been set.
35
+ if (Mage::getStoreConfig('pricewaiter/configuration/enabled')
36
+ && Mage::getStoreConfig('pricewaiter/configuration/api_key')
37
+ ) {
38
+ return true;
39
+ }
40
+
41
+ return false;
42
+ }
43
+
44
+ // Set the values of $_buttonEnabled and $_conversionToolsEnabled
45
+ private function _setEnabledStatus()
46
+ {
47
+ if ($this->_buttonEnabled != null && $this->_conversionToolsEnabled != null) {
48
+ return true;
49
+ }
50
+
51
+ if (Mage::getStoreConfig('pricewaiter/configuration/enabled')) {
52
+ $this->_buttonEnabled = true;
53
+ }
54
+
55
+ if (Mage::getStoreConfig('pricewaiter/conversion_tools/enabled')) {
56
+ $this->_conversionToolsEnabled = true;
57
+ }
58
+
59
+ // Is the pricewaiter widget enabled for this product
60
+ $product = $this->_getProduct();
61
+ if (!is_object($product) or ($product->getId() and $product->getData('nypwidget_disabled'))) {
62
+ $this->_buttonEnabled = false;
63
+ }
64
+
65
+ if (!is_object($product) or ($product->getId() and $product->getData('nypwidget_ct_disabled'))) {
66
+ $this->_conversionToolsEnabled = false;
67
+ }
68
+
69
+ // Is the PriceWaiter widget enabled for this category
70
+ $category = Mage::registry('current_category');
71
+ if (is_object($category)) {
72
+ $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category);
73
+ if (!$nypcategory->isActive()) {
74
+ $this->_buttonEnabled = false;
75
+ }
76
+ if (!$nypcategory->isConversionToolsEnabled()) {
77
+ $this->_conversionToolsEnabled = false;
78
+ }
79
+ } else {
80
+ // We end up here if we are visiting the product page without being
81
+ // "in a category". Basically, we arrived via a search page.
82
+ // The logic here checks to see if there are any categories that this
83
+ // product belongs to that enable the PriceWaiter widget. If not, return false.
84
+ $categories = $product->getCategoryIds();
85
+ $categoryActive = false;
86
+ $categoryCTActive = false;
87
+ foreach ($categories as $categoryId) {
88
+ unset($currentCategory);
89
+ unset($nypcategory);
90
+ $currentCategory = Mage::getModel('catalog/category')->load($categoryId);
91
+ $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($currentCategory);
92
+ if ($nypcategory->isActive()) {
93
+ if ($nypcategory->isConversionToolsEnabled()) {
94
+ $categoryCTActive = true;
95
+ }
96
+ $categoryActive = true;
97
+ break;
98
+ }
99
+ }
100
+ if (!$categoryActive) {
101
+ $this->_buttonEnabled = false;
102
+ }
103
+
104
+ if (!$categoryCTActive) {
105
+ $this->_conversionToolsEnabled = false;
106
+ }
107
+
108
+ }
109
+
110
+ // Is PriceWaiter enabled for this Customer Group
111
+ $disable = Mage::getStoreConfig('pricewaiter/customer_groups/disable');
112
+ if ($disable) {
113
+ // An admin has chosen to disable the PriceWaiter widget by customer group.
114
+ $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
115
+ $customerGroups = Mage::getStoreConfig('pricewaiter/customer_groups/group_select');
116
+ $customerGroups = preg_split('/,/', $customerGroups);
117
+
118
+ if (in_array($customerGroupId, $customerGroups)) {
119
+ $this->_buttonEnabled = false;
120
+ }
121
+ }
122
+
123
+ // Are Conversion Tools enabled for this Customer Group
124
+ $disableCT = Mage::getStoreConfig('pricewaiter/conversion_tools/customer_group_disable');
125
+ if ($disableCT) {
126
+ // An admin has chosen to disable the Conversion Tools by customer group.
127
+ $customerGroupId = Mage::getSingleton('customer/session')->getCustomerGroupId();
128
+ $customerGroups = Mage::getStoreConfig('pricewaiter/conversion_tools/group_select');
129
+ $customerGroups = preg_split('/,/', $customerGroups);
130
+
131
+ if (in_array($customerGroupId, $customerGroups)) {
132
+ $this->_conversionToolsEnabled = false;
133
+ }
134
+ }
135
+ }
136
+
137
+ public function isConversionToolsEnabled()
138
+ {
139
+ $this->_setEnabledStatus();
140
+
141
+ return $this->_conversionToolsEnabled;
142
+ }
143
+
144
+ public function isButtonEnabled()
145
+ {
146
+ $this->_setEnabledStatus();
147
+
148
+ return $this->_buttonEnabled;
149
+ }
150
+
151
+ public function getButtonSettingsUrl()
152
+ {
153
+ $apiKey = Mage::getStoreConfig('pricewaiter/configuration/api_key');
154
+ $baseUrl = 'https://manage.pricewaiter.com';
155
+ if ($this->_testing) {
156
+ $baseUrl = 'https://manage-staging.pricewaiter.com';
157
+ }
158
+
159
+ return sprintf("%s/stores/%s/button", $baseUrl, $apiKey);
160
+ }
161
+
162
+ public function getWidgetUrl()
163
+ {
164
+ if ($this->isEnabledForStore()) {
165
+ return "https://widget.pricewaiter.com/script/"
166
+ . Mage::getStoreConfig('pricewaiter/configuration/api_key')
167
+ . ".js";
168
+ }
169
+
170
+ return "https://widget.pricewaiter.com/nyp/script/widget.js";
171
+ }
172
+
173
+ public function getApiUrl()
174
+ {
175
+ return "https://api.pricewaiter.com/1/order/verify?api_key="
176
+ . Mage::getStoreConfig('pricewaiter/configuration/api_key');
177
+ }
178
+
179
+ public function getProductPrice($product)
180
+ {
181
+ $productPrice = 0;
182
+
183
+ if ($product->getId()) {
184
+ if ($product->getTypeId() != 'grouped') {
185
+ $productPrice = $product->getFinalPrice();
186
+ }
187
+ }
188
+
189
+ return $productPrice;
190
+ }
191
+
192
+ private function _getProduct()
193
+ {
194
+ if (!$this->_product) {
195
+ $this->_product = Mage::registry('current_product');
196
+ }
197
+
198
+ return $this->_product;
199
+ }
200
+
201
+ public function getGroupedProductInfo()
202
+ {
203
+ $product = $this->_getProduct();
204
+ $javascript = "var PriceWaiterGroupedProductInfo = new Array();\n";
205
+
206
+ $associatedProducts = $product->getTypeInstance(true)->getAssociatedProducts($product);
207
+ foreach ($associatedProducts as $simpleProduct) {
208
+ $javascript .= "PriceWaiterGroupedProductInfo[" . $simpleProduct->getId() . "] = ";
209
+ $javascript .= "new Array('" . htmlentities($simpleProduct->getName()) . "', '"
210
+ . number_format($simpleProduct->getPrice(), 2) . "')\n";
211
+ }
212
+
213
+ return $javascript;
214
+ }
215
+
216
+ public function getStoreByApiKey($apiKey)
217
+ {
218
+ $stores = Mage::app()->getStores();
219
+
220
+ // Find the store with the matching API key by checking the key for each store
221
+ // in Magento
222
+ foreach ($stores as $store) {
223
+ if ($apiKey == Mage::getStoreConfig('pricewaiter/configuration/api_key', $store->getId())) {
224
+ return $store;
225
+ }
226
+ }
227
+
228
+ return Mage::app()->getStore();
229
+ }
230
+
231
+ /**
232
+ * Returns the secret token used when communicating with PriceWaiter.
233
+ * @return {String} Secret token
234
+ */
235
+ public function getSecret()
236
+ {
237
+ $token = Mage::getStoreConfig('pricewaiter/configuration/api_secret');
238
+
239
+ if (is_null($token) || $token == '') {
240
+ $token = bin2hex(openssl_random_pseudo_bytes(24));
241
+ $config = Mage::getModel('core/config');
242
+
243
+ $config->saveConfig('pricewaiter/configuration/api_secret', $token);
244
+ }
245
+
246
+ return $token;
247
+ }
248
+
249
+ /**
250
+ * Returns a signature that can be added to the head of a PriceWaiter API response.
251
+ * @param {String} $responseBody The full body of the request to sign.
252
+ * @return {String} Signature that should be set as the X-PriceWaiter-Signature header.
253
+ */
254
+ public function getResponseSignature($responseBody)
255
+ {
256
+ $signature = 'sha256=' . hash_hmac('sha256', $responseBody, $this->getSecret(), false);
257
+ return $signature;
258
+ }
259
+
260
+ /**
261
+ * Validates that the current request came from PriceWaiter.
262
+ * @param {String} $signatureHeader Full value of the X-PriceWaiter-Signature header.
263
+ * @param {String} $requestBody Complete body of incoming request.
264
+ * @return {Boolean} Wehther the request actually came from PriceWaiter.
265
+ */
266
+ public function isPriceWaiterRequestValid($signatureHeader = null, $requestBody = null)
267
+ {
268
+ if ($signatureHeader === null || $requestBody === null) {
269
+ return false;
270
+ }
271
+
272
+ $detected = 'sha256=' . hash_hmac('sha256', $requestBody, $this->getSecret(), false);
273
+
274
+ if (function_exists('hash_equals')) {
275
+ // Favor PHP's secure hash comparison function in 5.6 and up.
276
+ // For a robust drop-in compatibility shim, see: https://github.com/indigophp/hash-compat
277
+ return hash_equals($detected, $signatureHeader);
278
+ }
279
+
280
+ return $detected === $signatureHeader;
281
+ }
282
+
283
+ /**
284
+ * Finds the Product that matches the given options and SKU
285
+ * @param {String} $sku SKU of the product
286
+ * @param {Array} $productOptions An array of options for the product, name => value
287
+ * @return {Object} Returns Mage_Catalog_Model_Product of product that matches options.
288
+ */
289
+ public function getProductWithOptions($sku, $productOptions)
290
+ {
291
+ $product = Mage::getModel('catalog/product')->getCollection()
292
+ ->addAttributeToFilter('sku', $sku)
293
+ ->addAttributeToSelect('*')
294
+ ->getFirstItem();
295
+
296
+ $additionalCost = null;
297
+
298
+ if ($product->getTypeId() == 'configurable') {
299
+ // Do configurable product specific stuff
300
+ $attrs = $product->getTypeInstance(true)->getConfigurableAttributesAsArray($product);
301
+
302
+ // Find our product based on attributes
303
+ foreach ($attrs as $attr) {
304
+ if (array_key_exists($attr['label'], $productOptions)) {
305
+ foreach ($attr['values'] as $value) {
306
+ if ($value['label'] == $productOptions[$attr['label']]) {
307
+ $valueIndex = $value['value_index'];
308
+ // If this attribute has a price assosciated with it, add it to the price later
309
+ if ($value['pricing_value'] != '') {
310
+ $additionalCost += $value['pricing_value'];
311
+ }
312
+ break;
313
+ }
314
+ }
315
+ unset($productOptions[$attr['label']]);
316
+ $productOptions[$attr['attribute_id']] = $valueIndex;
317
+ }
318
+ }
319
+
320
+ $parentProduct = $product;
321
+ $product = $product->getTypeInstance()->getProductByAttributes($productOptions, $product);
322
+ $product->load($product->getId());
323
+ }
324
+
325
+ if ($additionalCost) {
326
+ $product->setPrice($product->getPrice() + $additionalCost);
327
+ }
328
+
329
+ return $product;
330
+ }
331
+
332
+ public function getGroupedQuantity($productConfiguration)
333
+ {
334
+ $associatedProductIds = array_keys($productConfiguration['super_group']);
335
+ $quantities = array();
336
+ foreach ($associatedProductIds as $associatedProductId) {
337
+ $associatedProduct = Mage::getModel('catalog/product')->load($associatedProductId);
338
+ $quantities[] = $associatedProduct->getStockItem()->getQty();
339
+ }
340
+
341
+ return min($quantities);
342
+ }
343
+
344
+ public function getGroupedFinalPrice($productConfiguration)
345
+ {
346
+ $associatedProductIds = array_keys($productConfiguration['super_group']);
347
+ $finalPrice = 0;
348
+ foreach ($associatedProductIds as $associatedProductId) {
349
+ $associatedProduct = Mage::getModel('catalog/product')->load($associatedProductId);
350
+ $finalPrice += ($associatedProduct->getFinalPrice() * $productConfiguration['super_group'][$associatedProductId]);
351
+ }
352
+ return $finalPrice;
353
+ }
354
+
355
+ public function getGroupedCost($productConfiguration)
356
+ {
357
+ $associatedProductIds = array_keys($productConfiguration['super_group']);
358
+ $costs = array();
359
+ foreach ($associatedProductIds as $associatedProductId) {
360
+ $associatedProduct = Mage::getModel('catalog/product')->load($associatedProductId);
361
+ $costs[] = $associatedProduct->getData('cost');
362
+ }
363
+
364
+ return min($costs);
365
+ }
366
  }
app/code/community/PriceWaiter/NYPWidget/Model/Callback.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,320 +16,310 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Callback
19
  {
20
 
21
- private $_store;
22
- private $_groupId = '1';
23
- private $_sendConfirmation = '0';
24
-
25
- private $orderData = array();
26
- private $_product;
27
-
28
- private $_sourceCustomer;
29
- private $_sourceOrder;
30
-
31
- public function processRequest($request)
32
- {
33
- // If the PriceWaiter extension is in testing mode, skip request validation
34
- if (!Mage::helper('nypwidget')->isTesting()) {
35
- // Build URL to check validity of order notification.
36
- $url = Mage::helper('nypwidget')->getApiUrl();
37
-
38
- $ch = curl_init($url);
39
- curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
40
- curl_setopt($ch, CURLOPT_POST, true);
41
- curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
42
-
43
- // If PriceWaiter returns an invalid response
44
- if (curl_exec($ch) == "1") {
45
- $message = "The Name Your Price Widget has received a valid order notification.";
46
- Mage::log($message);
47
- $this->_log($message);
48
- } else {
49
- $message = "An invalid PriceWaiter order notification has been received.";
50
- Mage::log($message);
51
- $this->_log($message);
52
- return;
53
- }
54
- }
55
-
56
- // Verify that we have not already received this callback based on the `pricewaiter_id` field
57
- $pricewaiterOrder = Mage::getModel('nypwidget/order');
58
- $pricewaiterOrder->loadByPriceWaiterId($request['pricewaiter_id']);
59
- if ($pricewaiterOrder->getId()) {
60
- $message = "Received a duplicate order from the PriceWaiter Callback API. Ignoring.";
61
- $this->_log($message);
62
- return;
63
- }
64
-
65
- try {
66
-
67
- // First, determine the store that this order corresponds to.
68
- // This is a new feature as of 1.2.2, so we need to make sure the API
69
- // is compatible first.
70
- if (array_key_exists('api_key', $request)
71
- && $request['api_key'] != '') {
72
- $store = Mage::helper('nypwidget')->getStoreByApiKey($request['api_key']);
73
- $this->_store = $store;
74
- } else {
75
- // Fallback for when the API key isn't found
76
- $this->_store = Mage::app()->getStore();
77
- }
78
-
79
- // Is this an existing customer?
80
- $customer = Mage::getModel('customer/customer')
81
- ->setWebsiteId($this->_store->getWebsiteId());
82
- $customer->loadByEmail($request['buyer_email']);
83
-
84
- if (!$customer->getId()) {
85
- // Create a new customer with this email
86
- $customer->reset();
87
- $passwordLength = 10;
88
- $passwordCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
89
- $password = '';
90
- for ($p = 0; $p < $passwordLength; $p++) {
91
- $password .= $passwordCharacters[mt_rand(0, strlen($passwordCharacters))];
92
- }
93
-
94
- $customer->setEmail($request['buyer_email']);
95
- $customer->setFirstname($name[2]);
96
- $customer->setLastname($name[3]);
97
- $customer->setPassword($password);
98
- $customer->setConfirmation(null);
99
- $customer->setWebsiteId($this->_store->getWebsiteId());
100
- $customer->save();
101
- if (Mage::getStoreConfig('pricewaiter/customer_interaction/send_welcome_email')) {
102
- $customer->sendNewAccountEmail('registered', '', $this->_store->getId());
103
- }
104
- $customer->load($customer->getId());
105
- }
106
-
107
- $transaction = Mage::getModel('core/resource_transaction');
108
- $reservedOrderId = Mage::getSingleton('eav/config')->getEntityType('order')->fetchNewIncrementId($this->_store->getId());
109
-
110
- $order = Mage::getModel('sales/order')
111
- ->setIncrementId($reservedOrderId)
112
- ->setStoreId($this->_store->getId())
113
- ->setQuoteId(0)
114
- ->setGlobal_currency_code('USD')
115
- ->setBase_currency_code('USD')
116
- ->setStore_currency_code('USD')
117
- ->setOrder_currency_code('USD');
118
-
119
- // set Customer data
120
- $order->setCustomer_email($customer->getEmail())
121
- ->setCustomerFirstname($customer->getFirstname())
122
- ->setCustomerLastname($customer->getLastname())
123
- ->setCustomerGroupId($customer->getGroupId())
124
- ->setCustomer_is_guest(0)
125
- ->setCustomer($customer);
126
-
127
- //Get a phone number, or make a dummy one
128
- if ($request['buyer_shipping_phone']) {
129
- $telephone = $request['buyer_shipping_phone'];
130
- } else {
131
- $telephone = "000-000-0000";
132
- }
133
-
134
- // Find Region ID
135
- $regionModel = Mage::getModel('directory/region')->loadByCode($request['buyer_shipping_state'], $request['buyer_shipping_country']);
136
-
137
- // set Billing Address
138
- $billing = $customer->getDefaultBillingAddress();
139
- $billingAddress = Mage::getModel('sales/order_address')
140
- ->setStoreId($this->_store->getId())
141
- ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING)
142
- ->setCustomerId($customer->getId())
143
- ->setPrefix('')
144
- ->setFirstname($request['buyer_first_name'])
145
- ->setMiddlename('')
146
- ->setLastname($request['buyer_last_name'])
147
- ->setSuffix('')
148
- ->setCompany('')
149
- ->setStreet(array($request['buyer_shipping_address'],$request['buyer_shipping_address2']))
150
- ->setCity($request['buyer_shipping_city'])
151
- ->setCountry_id($request['buyer_shipping_country'])
152
- ->setRegion($request['buyer_shipping_state'])
153
- ->setRegion_id($regionModel->getId())
154
- ->setPostcode($request['buyer_shipping_zip'])
155
- ->setTelephone($telephone)
156
- ->setFax('');
157
- $order->setBillingAddress($billingAddress);
158
-
159
- // Try to get the shipping name. If we fail, fall back on the buyer_first/last_name fields
160
- preg_match('#^(\w+\.)?\s*([\'\’\w]+)\s+([\'\’\w]+)\s*(\w+\.?)?$#',$request['buyer_shipping_name'] , $name);
161
- $request['buyer_shipping_first_name'] = $name[2];
162
- $request['buyer_shipping_last_name'] = $name[3];
163
-
164
- if ($request['buyer_shipping_first_name'] == '') {
165
- $request['buyer_shipping_first_name'] = $request['buyer_first_name'];
166
- $request['buyer_shipping_last_name'] = $request['buyer_last_name'];
167
- }
168
-
169
- // set Shipping Address
170
- $shipping = $customer->getDefaultShippingAddress();
171
- $shippingAddress = Mage::getModel('sales/order_address')
172
- ->setStoreId($this->_store->getId())
173
- ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING)
174
- ->setCustomerId($customer->getId())
175
- ->setPrefix('')
176
- ->setFirstname($request['buyer_shipping_first_name'])
177
- ->setMiddlename('')
178
- ->setLastname($request['buyer_shipping_last_name'])
179
- ->setSuffix('')
180
- ->setCompany('')
181
- ->setStreet(array($request['buyer_shipping_address'],$request['buyer_shipping_address2']))
182
- ->setCity($request['buyer_shipping_city'])
183
- ->setCountry_id($request['buyer_shipping_country'])
184
- ->setRegion($request['buyer_shipping_state'])
185
- ->setRegion_id($regionModel->getId())
186
- ->setPostcode($request['buyer_shipping_zip'])
187
- ->setTelephone($telephone)
188
- ->setFax('');
189
-
190
- // Apply shipping address to order, add PriceWaiter shipping method
191
- $order->setShippingAddress($shippingAddress)
192
- ->setShipping_method('nypwidget_nypwidget')
193
- ->setShipping_amount($request['shipping'])
194
- ->setShippingDescription('PriceWaiter');
195
-
196
- // Add PriceWaiter payment method
197
- $orderPayment = Mage::getModel('sales/order_payment')
198
- ->setStoreId($this->_store->getId())
199
- ->setCustomerPaymentId(0)
200
- ->setMethod('nypwidget');
201
- $order->setPayment($orderPayment);
202
-
203
- // Find the Product from the request
204
- $this->_product = Mage::getModel('catalog/product')->getCollection()
205
- ->addAttributeToFilter('sku', $request['product_sku'])
206
- ->addAttributeToSelect('*')
207
- ->getFirstItem();
208
-
209
- // If we have product options, split them out of the request
210
- $requestOptions = array();
211
-
212
- for ($i = $request['product_option_count']; $i > 0; $i--) {
213
- $requestOptions[$request['product_option_name' . $i]] = $request['product_option_value' . $i];
214
- }
215
-
216
- if ($this->_product->getTypeId() == 'configurable') {
217
- // Do configurable product specific stuff
218
- $attrs = $this->_product->getTypeInstance(true)->getConfigurableAttributesAsArray($this->_product);
219
-
220
- // Find our product based on attributes
221
- foreach ($attrs as $attr) {
222
- if (array_key_exists($attr['label'], $requestOptions)) {
223
- foreach ($attr['values'] as $value) {
224
- if ($value['label'] == $requestOptions[$attr['label']]) {
225
- $valueIndex = $value['value_index'];
226
- break;
227
- }
228
- }
229
- unset($requestOptions[$attr['label']]);
230
- $requestOptions[$attr['attribute_id']] = $valueIndex;
231
- }
232
- }
233
-
234
- $parentProduct = $this->_product;
235
- $this->_product = $this->_product->getTypeInstance()->getProductByAttributes($requestOptions, $this->_product);
236
- $this->_product->load($this->_product->getId());
237
- }
238
-
239
- // Build the pricing information of the product
240
- $subTotal = 0;
241
- $rowTotal = ($request['unit_price'] * $request['quantity']) + $request['tax'];
242
- $itemDiscount = ($this->_product->getPrice() - $request['unit_price']);
243
-
244
- $orderItem = Mage::getModel('sales/order_item')
245
- ->setStoreId($this->_store->getId())
246
- ->setQuoteItemId(0)
247
- ->setQuoteParentItemId(NULL)
248
- ->setProductId($this->_product->getId())
249
- ->setProductType($this->_product->getTypeId())
250
- ->setQtyBackordered(NULL)
251
- ->setTotalQtyOrdered($request['quantity'])
252
- ->setQtyOrdered($request['quantity'])
253
- ->setName($this->_product->getName())
254
- ->setSku($this->_product->getSku())
255
- ->setPrice($request['unit_price'])
256
- ->setBasePrice($request['unit_price'])
257
- ->setOriginalPrice($this->_product->getPrice())
258
- // ->setDiscountAmount($itemDiscount)
259
- ->setTaxAmount($request['tax'])
260
- ->setRowTotal($rowTotal)
261
- ->setBaseRowTotal($rowTotal);
262
-
263
- // Do we have a simple product with custom options, a bundle product, or a grouped product?
264
- if (($this->_product->getTypeId() == 'simple'
265
- || $this->_product->getTypeId() == 'bundle'
266
- || $this->_product->getTypeId() == 'grouped')
267
- && $request['product_option_count'] > 0) {
268
- // Grab the options from the request, build $additionalOptions array
269
- $additionalOptions = array();
270
- for ($i = $request['product_option_count']; $i > 0; $i--) {
271
- $additionalOptions[] = array(
272
- 'label' => $request['product_option_name' . $i],
273
- 'value' => $request['product_option_value' . $i]
274
- );
275
- }
276
-
277
- // Apply the $additionalOptions array to the simple product
278
- $orderItem->setProductOptions(array('additional_options' => $additionalOptions));
279
- }
280
-
281
- // Build and apply the order totals
282
- $subTotal += $rowTotal;
283
- $order->addItem($orderItem);
284
-
285
- $order->setSubtotal($subTotal)
286
- ->setBaseSubtotal($subTotal)
287
- ->setGrandTotal($subTotal + $request['shipping'])
288
- ->setBaseGrandTotal($subTotal + $request['shipping']);
289
-
290
- $order->addStatusHistoryComment("This order has been programmatically created by the PriceWaiter Name Your Price Widget.");
291
-
292
- // Ok, done with the order.
293
- $transaction->addObject($order);
294
- $transaction->addCommitCallback(array($order, 'place'));
295
- $transaction->addCommitCallback(array($order, 'save'));
296
- $transaction->save();
297
- if (Mage::getStoreConfig('pricewaiter/customer_interaction/send_new_order_email')) {
298
- $order->sendNewOrderEmail();
299
- }
300
-
301
- // Capture the invoice
302
- $invoiceId = Mage::getModel('sales/order_invoice_api')
303
- ->create($order->getIncrementId(), array());
304
- $invoice = Mage::getModel('sales/order_invoice')
305
- ->loadByIncrementId($invoiceId);
306
- $invoice->capture()->save();
307
-
308
- // Add this order to the list of received callback orders
309
- $pricewaiterOrder->setData(array(
310
- 'store_id' => $order->getStoreId(),
311
- 'pricewaiter_id' => $request['pricewaiter_id'],
312
- 'order_id' => $order->getId()
313
- ));
314
- $pricewaiterOrder->save();
315
-
316
- Mage::log("The Name Your Price Widget has created order #"
317
- . $order->getIncrementId() . " with order ID " . $order->getId());
318
- $this->_log("The Name Your Price Widget has created order #"
319
- . $order->getIncrementId() . " with order ID " . $order->getId());
320
- }
321
- catch (Exception $e){
322
- $this->_log("PriceWaiter Name Your Price Widget was unable to create order. Check log for details.");
323
- $this->_log($e->getMessage());
324
- }
325
-
326
- }
327
-
328
- private function _log($message)
329
- {
330
- if (Mage::getStoreConfig('pricewaiter/configuration/log')) {
331
- Mage::log($message, null, "PriceWaiter_Callback.log");
332
- }
333
- }
334
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Callback
21
  {
22
 
23
+ private $_store;
24
+ private $_product;
25
+
26
+ private $_test = false;
27
+
28
+ public function processRequest($request)
29
+ {
30
+ if ($request['test'] == 1) {
31
+ $this->_test = true;
32
+ }
33
+
34
+ // Build URL to check validity of order notification.
35
+ $url = Mage::helper('nypwidget')->getApiUrl();
36
+
37
+ $ch = curl_init($url);
38
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
39
+ curl_setopt($ch, CURLOPT_POST, true);
40
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $request);
41
+
42
+ // If PriceWaiter returns an invalid response
43
+ if (curl_exec($ch) == "1") {
44
+ $message = "The Name Your Price Widget has received a valid order notification.";
45
+ if ($this->_test) {
46
+ $message .= ' This is a TEST order that will be created and canceled.';
47
+ }
48
+ Mage::log($message);
49
+ $this->_log($message);
50
+ } else {
51
+ $message = "An invalid PriceWaiter order notification has been received.";
52
+ Mage::log($message);
53
+ $this->_log($message);
54
+ return;
55
+ }
56
+
57
+ // Verify that we have not already received this callback based on the `pricewaiter_id` field
58
+ $pricewaiterOrder = Mage::getModel('nypwidget/order');
59
+ $pricewaiterOrder->loadByPriceWaiterId($request['pricewaiter_id']);
60
+ if ($pricewaiterOrder->getId()) {
61
+ $message = "Received a duplicate order from the PriceWaiter Callback API. Ignoring.";
62
+ $this->_log($message);
63
+ return;
64
+ }
65
+
66
+ try {
67
+
68
+ // First, determine the store that this order corresponds to.
69
+ // This is a new feature as of 1.2.2, so we need to make sure the API
70
+ // is compatible first.
71
+ if (array_key_exists('api_key', $request)
72
+ && $request['api_key'] != ''
73
+ ) {
74
+ $store = Mage::helper('nypwidget')->getStoreByApiKey($request['api_key']);
75
+ $this->_store = $store;
76
+ } else {
77
+ // Fallback for when the API key isn't found
78
+ $this->_store = Mage::app()->getStore();
79
+ }
80
+
81
+ // Is this an existing customer?
82
+ $customer = Mage::getModel('customer/customer')
83
+ ->setWebsiteId($this->_store->getWebsiteId());
84
+ $customer->loadByEmail($request['buyer_email']);
85
+
86
+ if (!$customer->getId()) {
87
+ // Create a new customer with this email
88
+ $customer->reset();
89
+ $passwordLength = 10;
90
+ $passwordCharacters = '0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ';
91
+ $password = '';
92
+ for ($p = 0; $p < $passwordLength; $p++) {
93
+ $password .= $passwordCharacters[mt_rand(0, strlen($passwordCharacters))];
94
+ }
95
+
96
+ $customer->setEmail($request['buyer_email']);
97
+ $customer->setFirstname($request['buyer_first_name']);
98
+ $customer->setLastname($request['buyer_last_name']);
99
+ $customer->setPassword($password);
100
+ $customer->setConfirmation(null);
101
+ $customer->setWebsiteId($this->_store->getWebsiteId());
102
+ $customer->save();
103
+ if (Mage::getStoreConfig('pricewaiter/customer_interaction/send_welcome_email')) {
104
+ $customer->sendNewAccountEmail('registered', '', $this->_store->getId());
105
+ }
106
+ $customer->load($customer->getId());
107
+ }
108
+
109
+ $transaction = Mage::getModel('core/resource_transaction');
110
+ $reservedOrderId = Mage::getSingleton('eav/config')->getEntityType('order')->fetchNewIncrementId($this->_store->getId());
111
+
112
+ // Grab the currency code from the request, if one is set.
113
+ // Otherwise, use the store's default currency code.
114
+ if ($request['currency']) {
115
+ $currencyCode = $request['currency'];
116
+ } else {
117
+ $currencyCode = $this->_store->getDefaultCurrencyCode();
118
+ }
119
+
120
+ $order = Mage::getModel('sales/order')
121
+ ->setIncrementId($reservedOrderId)
122
+ ->setStoreId($this->_store->getId())
123
+ ->setQuoteId(0)
124
+ ->setGlobal_currency_code($currencyCode)
125
+ ->setBase_currency_code($currencyCode)
126
+ ->setStore_currency_code($currencyCode)
127
+ ->setOrder_currency_code($currencyCode);
128
+
129
+ // set Customer data
130
+ $order->setCustomer_email($customer->getEmail())
131
+ ->setCustomerFirstname($customer->getFirstname())
132
+ ->setCustomerLastname($customer->getLastname())
133
+ ->setCustomerGroupId($customer->getGroupId())
134
+ ->setCustomer_is_guest(0)
135
+ ->setCustomer($customer);
136
+
137
+ //Get a phone number, or make a dummy one
138
+ if ($request['buyer_shipping_phone']) {
139
+ $telephone = $request['buyer_shipping_phone'];
140
+ } else {
141
+ $telephone = "000-000-0000";
142
+ }
143
+
144
+ // Find Region ID
145
+ $regionModel = Mage::getModel('directory/region')->loadByCode($request['buyer_shipping_state'], $request['buyer_shipping_country']);
146
+
147
+ // set Billing Address
148
+ $billing = $customer->getDefaultBillingAddress();
149
+ $billingAddress = Mage::getModel('sales/order_address')
150
+ ->setStoreId($this->_store->getId())
151
+ ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING)
152
+ ->setCustomerId($customer->getId())
153
+ ->setPrefix('')
154
+ ->setFirstname($request['buyer_first_name'])
155
+ ->setMiddlename('')
156
+ ->setLastname($request['buyer_last_name'])
157
+ ->setSuffix('')
158
+ ->setCompany('')
159
+ ->setStreet(array($request['buyer_shipping_address'], $request['buyer_shipping_address2']))
160
+ ->setCity($request['buyer_shipping_city'])
161
+ ->setCountry_id($request['buyer_shipping_country'])
162
+ ->setRegion($request['buyer_shipping_state'])
163
+ ->setRegion_id($regionModel->getId())
164
+ ->setPostcode($request['buyer_shipping_zip'])
165
+ ->setTelephone($telephone)
166
+ ->setFax('');
167
+ $order->setBillingAddress($billingAddress);
168
+
169
+ // Try to get the shipping name. If we fail, fall back on the buyer_first/last_name fields
170
+ preg_match('#^(\w+\.)?\s*([\'\’\w]+)\s+([\'\’\w]+)\s*(\w+\.?)?$#', $request['buyer_shipping_name'], $name);
171
+
172
+ if (array_key_exists(2, $name)) {
173
+ $request['buyer_shipping_first_name'] = $name[2];
174
+ $request['buyer_shipping_last_name'] = $name[3];
175
+ } else {
176
+ $request['buyer_shipping_first_name'] = $request['buyer_first_name'];
177
+ $request['buyer_shipping_last_name'] = $request['buyer_last_name'];
178
+ }
179
+
180
+ // set Shipping Address
181
+ $shipping = $customer->getDefaultShippingAddress();
182
+ $shippingAddress = Mage::getModel('sales/order_address')
183
+ ->setStoreId($this->_store->getId())
184
+ ->setAddressType(Mage_Sales_Model_Quote_Address::TYPE_BILLING)
185
+ ->setCustomerId($customer->getId())
186
+ ->setPrefix('')
187
+ ->setFirstname($request['buyer_shipping_first_name'])
188
+ ->setMiddlename('')
189
+ ->setLastname($request['buyer_shipping_last_name'])
190
+ ->setSuffix('')
191
+ ->setCompany('')
192
+ ->setStreet(array($request['buyer_shipping_address'], $request['buyer_shipping_address2']))
193
+ ->setCity($request['buyer_shipping_city'])
194
+ ->setCountry_id($request['buyer_shipping_country'])
195
+ ->setRegion($request['buyer_shipping_state'])
196
+ ->setRegion_id($regionModel->getId())
197
+ ->setPostcode($request['buyer_shipping_zip'])
198
+ ->setTelephone($telephone)
199
+ ->setFax('');
200
+
201
+ // Apply shipping address to order, add PriceWaiter shipping method
202
+ $order->setShippingAddress($shippingAddress)
203
+ ->setShipping_method('nypwidget_nypwidget')
204
+ ->setShipping_amount($request['shipping'])
205
+ ->setShippingDescription('PriceWaiter');
206
+
207
+ // Add PriceWaiter payment method
208
+ $orderPayment = Mage::getModel('sales/order_payment')
209
+ ->setStoreId($this->_store->getId())
210
+ ->setCustomerPaymentId(0)
211
+ ->setMethod('nypwidget');
212
+ $order->setPayment($orderPayment);
213
+
214
+ // Find the Product from the request
215
+ $requestOptions = array();
216
+
217
+ for ($i = $request['product_option_count']; $i > 0; $i--) {
218
+ $requestOptions[$request['product_option_name' . $i]] = $request['product_option_value' . $i];
219
+ }
220
+
221
+ $this->_product = Mage::helper('nypwidget')->getProductWithOptions($request['product_sku'], $requestOptions);
222
+
223
+ // Build the pricing information of the product
224
+ $subTotal = 0;
225
+ $rowTotal = ($request['unit_price'] * $request['quantity']) + $request['tax'];
226
+ $itemDiscount = ($this->_product->getPrice() - $request['unit_price']);
227
+
228
+ $orderItem = Mage::getModel('sales/order_item')
229
+ ->setStoreId($this->_store->getId())
230
+ ->setQuoteItemId(0)
231
+ ->setQuoteParentItemId(NULL)
232
+ ->setProductId($this->_product->getId())
233
+ ->setProductType($this->_product->getTypeId())
234
+ ->setQtyBackordered(NULL)
235
+ ->setTotalQtyOrdered($request['quantity'])
236
+ ->setQtyOrdered($request['quantity'])
237
+ ->setName($this->_product->getName())
238
+ ->setSku($this->_product->getSku())
239
+ ->setPrice($request['unit_price'])
240
+ ->setBasePrice($request['unit_price'])
241
+ ->setOriginalPrice($this->_product->getPrice())
242
+ // ->setDiscountAmount($itemDiscount)
243
+ ->setTaxAmount($request['tax'])
244
+ ->setRowTotal($rowTotal)
245
+ ->setBaseRowTotal($rowTotal);
246
+
247
+ // Do we have a simple product with custom options, a bundle product, or a grouped product?
248
+ if (($this->_product->getTypeId() == 'simple'
249
+ || $this->_product->getTypeId() == 'bundle'
250
+ || $this->_product->getTypeId() == 'grouped')
251
+ && $request['product_option_count'] > 0
252
+ ) {
253
+ // Grab the options from the request, build $additionalOptions array
254
+ $additionalOptions = array();
255
+ for ($i = $request['product_option_count']; $i > 0; $i--) {
256
+ $additionalOptions[] = array(
257
+ 'label' => $request['product_option_name' . $i],
258
+ 'value' => $request['product_option_value' . $i]
259
+ );
260
+ }
261
+
262
+ // Apply the $additionalOptions array to the simple product
263
+ $orderItem->setProductOptions(array('additional_options' => $additionalOptions));
264
+ }
265
+
266
+ // Build and apply the order totals
267
+ $subTotal += $rowTotal;
268
+ $order->addItem($orderItem);
269
+
270
+ $order->setSubtotal($subTotal)
271
+ ->setBaseSubtotal($subTotal)
272
+ ->setGrandTotal($subTotal + $request['shipping'])
273
+ ->setBaseGrandTotal($subTotal + $request['shipping']);
274
+
275
+ $order->addStatusHistoryComment("This order has been programmatically created by the PriceWaiter Name Your Price Widget.");
276
+
277
+ // Ok, done with the order.
278
+ $transaction->addObject($order);
279
+ $transaction->addCommitCallback(array($order, 'place'));
280
+ $transaction->addCommitCallback(array($order, 'save'));
281
+ $transaction->save();
282
+ if (Mage::getStoreConfig('pricewaiter/customer_interaction/send_new_order_email')) {
283
+ $order->sendNewOrderEmail();
284
+ }
285
+
286
+ // If this is a test order, cancel it to prevent it from any further processing.
287
+ if ($this->_test) {
288
+ $order->cancel();
289
+ $order->save();
290
+ return;
291
+ }
292
+
293
+ // Capture the invoice
294
+ $invoiceId = Mage::getModel('sales/order_invoice_api')
295
+ ->create($order->getIncrementId(), array());
296
+ $invoice = Mage::getModel('sales/order_invoice')
297
+ ->loadByIncrementId($invoiceId);
298
+ $invoice->capture()->save();
299
+
300
+ // Add this order to the list of received callback orders
301
+ $pricewaiterOrder->setData(array(
302
+ 'store_id' => $order->getStoreId(),
303
+ 'pricewaiter_id' => $request['pricewaiter_id'],
304
+ 'order_id' => $order->getId()
305
+ ));
306
+ $pricewaiterOrder->save();
307
+
308
+ Mage::log("The Name Your Price Widget has created order #"
309
+ . $order->getIncrementId() . " with order ID " . $order->getId());
310
+ $this->_log("The Name Your Price Widget has created order #"
311
+ . $order->getIncrementId() . " with order ID " . $order->getId());
312
+ } catch (Exception $e) {
313
+ $this->_log("PriceWaiter Name Your Price Widget was unable to create order. Check log for details.");
314
+ $this->_log($e->getMessage());
315
+ }
316
+
317
+ }
318
+
319
+ private function _log($message)
320
+ {
321
+ if (Mage::getStoreConfig('pricewaiter/configuration/log')) {
322
+ Mage::log($message, null, "PriceWaiter_Callback.log");
323
+ }
324
+ }
 
 
 
 
 
 
 
 
 
 
 
325
  }
app/code/community/PriceWaiter/NYPWidget/Model/Carrier/ShippingMethod.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,20 +16,21 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Carrier_ShippingMethod
19
- extends Mage_Shipping_Model_Carrier_Abstract
20
- implements Mage_Shipping_Model_Carrier_Interface
21
  {
22
- protected $_code = 'nypwidget';
23
- protected $_isFixed = true;
24
 
25
- public function collectRates(Mage_Shipping_Model_Rate_Request $request)
26
- {
27
- return;
28
- }
29
 
30
- public function getAllowedMethods()
31
- {
32
- return;
33
- }
34
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Carrier_ShippingMethod
21
+ extends Mage_Shipping_Model_Carrier_Abstract
22
+ implements Mage_Shipping_Model_Carrier_Interface
23
  {
24
+ protected $_code = 'nypwidget';
25
+ protected $_isFixed = true;
26
 
27
+ public function collectRates(Mage_Shipping_Model_Rate_Request $request)
28
+ {
29
+ return;
30
+ }
31
 
32
+ public function getAllowedMethods()
33
+ {
34
+ return;
35
+ }
36
  }
app/code/community/PriceWaiter/NYPWidget/Model/Category.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,77 +16,110 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Category extends Mage_Core_Model_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/category', 'entity_id');
23
- }
24
-
25
- public function loadByCategory($category, $storeId = null)
26
- {
27
- if (is_object($category)) {
28
- $categoryID = $category->getId();
29
- } else {
30
- $categoryID = $category;
31
- }
32
-
33
- if (is_null($storeId)) {
34
- $storeId = Mage::app()->getStore()->getId();
35
- }
36
-
37
- $collection = Mage::getModel('nypwidget/category')
38
- ->getCollection()
39
- ->addFieldToFilter('category_id', $categoryID)
40
- ->addFieldToFilter('store_id', $storeId);
41
-
42
- if (count($collection)) {
43
- $this->load($collection->getFirstItem()->getEntityId());
44
- } else {
45
- $this->setData('category_id', $categoryID);
46
- $this->setData('store_id', $storeId);
47
- $this->save();
48
- }
49
-
50
- return $this;
51
- }
52
-
53
- public function isActive($admin = false)
54
- {
55
- // If we are in the admin, we want to skip all this, so that we return
56
- // the info on this specific category, not parents
57
- if (!$admin) {
58
- // First, check the "All Store Views" store (0)
59
- if ($this->getStoreId() != 0) {
60
- $allStoresCategory = Mage::getModel('nypwidget/category')
61
- ->loadByCategory($this->getCategoryId(), 0);
62
- if (!$allStoresCategory->isActive()) {
63
- return false;
64
- }
65
- }
66
-
67
- // Check the parent category if we already have a category_id and have a parent
68
- if (!is_null($this->getData('category_id'))) {
69
- $category = Mage::getModel('catalog/category')->load($this->getData('category_id'));
70
- if ($category->getParentId() != 0) {
71
- $parentCategory = Mage::getModel('nypwidget/category')->loadByCategory($category->getParentId());
72
- if (!$parentCategory->isActive()) {
73
- return false;
74
- }
75
- }
76
- }
77
- }
78
-
79
- // If the category isn't yet set in the table, default to true.
80
- // Otherwise, check the nypwidget_enabled field.
81
- if (is_null($this->getData('category_id')) or $this->getData('nypwidget_enabled') == 1) {
82
- return true;
83
- }
84
-
85
- if (is_null($this->getData('nypwidget_enabled'))) {
86
- return true;
87
- }
88
-
89
- return false;
90
- }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
91
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Category extends Mage_Core_Model_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/category', 'entity_id');
25
+ }
26
+
27
+ public function loadByCategory($category, $storeId = null)
28
+ {
29
+ if (is_object($category)) {
30
+ $categoryID = $category->getId();
31
+ } else {
32
+ $categoryID = $category;
33
+ }
34
+
35
+ if (is_null($storeId)) {
36
+ $storeId = Mage::app()->getStore()->getId();
37
+ }
38
+
39
+ $collection = Mage::getModel('nypwidget/category')
40
+ ->getCollection()
41
+ ->addFieldToFilter('category_id', $categoryID)
42
+ ->addFieldToFilter('store_id', $storeId);
43
+
44
+ if (count($collection)) {
45
+ $this->load($collection->getFirstItem()->getEntityId());
46
+ } else {
47
+ $this->setData('category_id', $categoryID);
48
+ $this->setData('store_id', $storeId);
49
+ $this->save();
50
+ }
51
+
52
+ return $this;
53
+ }
54
+
55
+ public function isActive($admin = false)
56
+ {
57
+ // If we are in the admin, we want to skip all this, so that we return
58
+ // the info on this specific category, not parents
59
+ if (!$admin) {
60
+ if (!$this->_checkParents('isActive')) {
61
+ return false;
62
+ }
63
+ }
64
+
65
+ // If the category isn't yet set in the table, default to true.
66
+ // Otherwise, check the nypwidget_enabled field.
67
+ if (is_null($this->getData('category_id')) or $this->getData('nypwidget_enabled') == 1) {
68
+ return true;
69
+ }
70
+
71
+ if (is_null($this->getData('nypwidget_enabled'))) {
72
+ return true;
73
+ }
74
+
75
+ return false;
76
+ }
77
+
78
+ public function isConversionToolsEnabled($admin = false)
79
+ {
80
+ // If we are in the admin, we want to skip all this, so that we return
81
+ // the info on this specific category, not parents
82
+ if (!$admin) {
83
+ if (!$this->_checkParents('isConversionToolsEnabled')) {
84
+ return false;
85
+ }
86
+ }
87
+
88
+ // If the category isn't yet set in the table, default to true.
89
+ // Otherwise, check the nypwidget_enabled field.
90
+ if (is_null($this->getData('category_id')) or $this->getData('nypwidget_ct_enabled') == 1) {
91
+ return true;
92
+ }
93
+
94
+ if (is_null($this->getData('nypwidget_ct_enabled'))) {
95
+ return true;
96
+ }
97
+
98
+ return false;
99
+ }
100
+
101
+ private function _checkParents($func)
102
+ {
103
+ // First, check the "All Store Views" store (0)
104
+ if ($this->getStoreId() != 0) {
105
+ $allStoresCategory = Mage::getModel('nypwidget/category')
106
+ ->loadByCategory($this->getCategoryId(), 0);
107
+ if (!call_user_func(array($allStoresCategory, $func))) {
108
+ return false;
109
+ }
110
+ }
111
+
112
+ // Check the parent category if we already have a category_id and have a parent
113
+ if (!is_null($this->getData('category_id'))) {
114
+ $category = Mage::getModel('catalog/category')->load($this->getData('category_id'));
115
+ if ($category->getParentId() != 0) {
116
+ $parentCategory = Mage::getModel('nypwidget/category')->loadByCategory($category->getParentId());
117
+ if (!call_user_func(array($parentCategory, $func))) {
118
+ return false;
119
+ }
120
+ }
121
+ }
122
+
123
+ return true;
124
+ }
125
  }
app/code/community/PriceWaiter/NYPWidget/Model/Display/Phrase.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,6 +16,7 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Display_Phrase
19
  {
20
  public function toOptionArray()
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Display_Phrase
21
  {
22
  public function toOptionArray()
app/code/community/PriceWaiter/NYPWidget/Model/Display/Size.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,6 +16,7 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Display_Size
19
  {
20
  public function toOptionArray()
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Display_Size
21
  {
22
  public function toOptionArray()
app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Category.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,10 +16,11 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Mysql4_Category extends Mage_Core_Model_Mysql4_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/category', 'entity_id');
23
- }
24
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Mysql4_Category extends Mage_Core_Model_Mysql4_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/category', 'entity_id');
25
+ }
26
  }
app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Category/Collection.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,10 +16,11 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Mysql4_Category_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/category', 'entity_id');
23
- }
24
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Mysql4_Category_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/category', 'entity_id');
25
+ }
26
  }
app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Order.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,10 +16,11 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Mysql4_Order extends Mage_Core_Model_Mysql4_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/order', 'entity_id');
23
- }
24
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Mysql4_Order extends Mage_Core_Model_Mysql4_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/order', 'entity_id');
25
+ }
26
  }
app/code/community/PriceWaiter/NYPWidget/Model/Mysql4/Order/Collection.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,10 +16,11 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Mysql4_Order_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/order', 'entity_id');
23
- }
24
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Mysql4_Order_Collection extends Mage_Core_Model_Mysql4_Collection_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/order', 'entity_id');
25
+ }
26
  }
app/code/community/PriceWaiter/NYPWidget/Model/Observer.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,32 +16,35 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Observer
19
  {
20
- // Adds the "PriceWaiter" tab to the "Manage Categories" page
21
- public function addTab(Varien_Event_Observer $observer)
22
- {
23
- $tabs = $observer->getEvent()->getTabs();
24
- $tabs->addTab('pricewaiter', array(
25
- 'label' => Mage::helper('catalog')->__('PriceWaiter'),
26
- 'content' => $tabs->getLayout()->createBlock(
27
- 'nypwidget/category')->toHtml(),
28
  ));
29
- return true;
30
- }
31
 
32
- // Saves "PriceWaiter" options from Category page
33
- public function saveCategory(Varien_Event_Observer $observer)
34
- {
35
- $category = $observer->getEvent()->getCategory();
36
- $enabled = $observer->getEvent()->getRequest()->getPost();
37
- $enabled = $enabled['pricewaiter']['enabled'];
 
38
 
39
- // Save the current setting, by category, and store
40
- $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category, $category->getStore()->getId());
41
- $nypcategory->setData('nypwidget_enabled', $enabled);
42
- $nypcategory->save();
 
43
 
44
- return true;
45
- }
46
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Observer
21
  {
22
+ // Adds the "PriceWaiter" tab to the "Manage Categories" page
23
+ public function addTab(Varien_Event_Observer $observer)
24
+ {
25
+ $tabs = $observer->getEvent()->getTabs();
26
+ $tabs->addTab('pricewaiter', array(
27
+ 'label' => Mage::helper('catalog')->__('PriceWaiter'),
28
+ 'content' => $tabs->getLayout()->createBlock(
29
+ 'nypwidget/category')->toHtml(),
30
  ));
31
+ return true;
32
+ }
33
 
34
+ // Saves "PriceWaiter" options from Category page
35
+ public function saveCategory(Varien_Event_Observer $observer)
36
+ {
37
+ $category = $observer->getEvent()->getCategory();
38
+ $postData = $observer->getEvent()->getRequest()->getPost();
39
+ $enabled = $postData['pricewaiter']['enabled'];
40
+ $ctEnabled = $postData['pricewaiter']['ct_enabled'];
41
 
42
+ // Save the current setting, by category, and store
43
+ $nypcategory = Mage::getModel('nypwidget/category')->loadByCategory($category, $category->getStore()->getId());
44
+ $nypcategory->setData('nypwidget_enabled', $enabled);
45
+ $nypcategory->setData('nypwidget_ct_enabled', $ctEnabled);
46
+ $nypcategory->save();
47
 
48
+ return true;
49
+ }
50
  }
app/code/community/PriceWaiter/NYPWidget/Model/Order.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,28 +16,29 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Order extends Mage_Core_Model_Abstract
19
  {
20
- public function _construct()
21
- {
22
- $this->_init('nypwidget/order', 'entity_id');
23
- }
24
 
25
- public function loadByPriceWaiterId($pricewaiterId)
26
- {
27
- if (is_null($pricewaiterId)) {
28
- return false;
29
- }
30
 
31
- $collection = Mage::getModel('nypwidget/order')
32
- ->getCollection()
33
- ->addFieldToFilter('pricewaiter_id', $pricewaiterId);
34
 
35
- if (count($collection)) {
36
- $this->load($collection->getFirstItem()->getEntityId());
37
- }
38
 
39
- return $this;
40
- }
41
 
42
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Order extends Mage_Core_Model_Abstract
21
  {
22
+ public function _construct()
23
+ {
24
+ $this->_init('nypwidget/order', 'entity_id');
25
+ }
26
 
27
+ public function loadByPriceWaiterId($pricewaiterId)
28
+ {
29
+ if (is_null($pricewaiterId)) {
30
+ return false;
31
+ }
32
 
33
+ $collection = Mage::getModel('nypwidget/order')
34
+ ->getCollection()
35
+ ->addFieldToFilter('pricewaiter_id', $pricewaiterId);
36
 
37
+ if (count($collection)) {
38
+ $this->load($collection->getFirstItem()->getEntityId());
39
+ }
40
 
41
+ return $this;
42
+ }
43
 
44
  }
app/code/community/PriceWaiter/NYPWidget/Model/PaymentMethod.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -20,16 +21,16 @@ class PriceWaiter_NYPWidget_Model_PaymentMethod extends Mage_Payment_Model_Metho
20
  {
21
  protected $_code = 'nypwidget';
22
 
23
- protected $_isGateway = false;
24
- protected $_canOrder = true;
25
- protected $_canAuthorize = false;
26
- protected $_canCapture = false;
27
- protected $_canCapturePartial = false;
28
- protected $_canRefund = false;
29
- protected $_canVoid = true;
30
- protected $_canUseInternal = true;
31
- protected $_canUseCheckout = false;
32
- protected $_canUseForMultishipping = false;
33
 
34
  public function authorize(Varien_Object $payment, $amount)
35
  {
@@ -44,10 +45,10 @@ class PriceWaiter_NYPWidget_Model_PaymentMethod extends Mage_Payment_Model_Metho
44
  public function void(Varien_Object $payment)
45
  {
46
  return $this;
47
- }
48
 
49
- public function isAvailable($quote = null)
50
- {
51
- return false;
52
- }
53
  }
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
21
  {
22
  protected $_code = 'nypwidget';
23
 
24
+ protected $_isGateway = false;
25
+ protected $_canOrder = true;
26
+ protected $_canAuthorize = false;
27
+ protected $_canCapture = false;
28
+ protected $_canCapturePartial = false;
29
+ protected $_canRefund = false;
30
+ protected $_canVoid = true;
31
+ protected $_canUseInternal = true;
32
+ protected $_canUseCheckout = false;
33
+ protected $_canUseForMultishipping = false;
34
 
35
  public function authorize(Varien_Object $payment, $amount)
36
  {
45
  public function void(Varien_Object $payment)
46
  {
47
  return $this;
48
+ }
49
 
50
+ public function isAvailable($quote = null)
51
+ {
52
+ return false;
53
+ }
54
  }
app/code/community/PriceWaiter/NYPWidget/Model/Resource/Eav/Mysql4/Setup.php CHANGED
@@ -1,7 +1,8 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -15,6 +16,7 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_Model_Resource_Eav_Mysql4_Setup extends Mage_Eav_Model_Entity_Setup
19
  {
20
 
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_Model_Resource_Eav_Mysql4_Setup extends Mage_Eav_Model_Entity_Setup
21
  {
22
 
app/code/community/PriceWaiter/NYPWidget/controllers/Adminhtml/PricewaiterController.php ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ class PriceWaiter_NYPWidget_Adminhtml_PriceWaiterController extends Mage_Adminhtml_Controller_Action
21
+ {
22
+
23
+ private $_tokenUrl = 'https://api.pricewaiter.com/store-signups';
24
+
25
+ public function tokenAction()
26
+ {
27
+ try {
28
+ $user = Mage::getSingleton('admin/session')->getUser();
29
+ $scope = Mage::app()->getRequest()->getParam('scope');
30
+
31
+
32
+ // Determine store from scope
33
+ if (preg_match('/^store/', $scope)) {
34
+ $store = Mage::getModel('core/store')->load(substr($scope, 6));
35
+ $website = Mage::getModel('core/website')->load($store->getWebsiteId());
36
+ } else if (preg_match('/^website/', $scope)) {
37
+ $website = Mage::getModel('core/website')->load(substr($scope, 8));
38
+ $store = $website->getStoreCollection()->getFirstItem();
39
+ } else {
40
+ // Load the defaults
41
+ $storeId = Mage::app()->getWebsite(true)->getDefaultGroup()
42
+ ->getDefaultStoreId();
43
+ $store = Mage::getModel('core/store')->load($storeId);
44
+ $website = Mage::getModel('core/website')->load($store->getWebsiteId());
45
+ }
46
+
47
+ // Get the name of the store from the group.
48
+ $storeName = $store->getGroup()->getName();
49
+
50
+ // Build post request and send information to PriceWaiter to assist in signup process.
51
+ $postFields = array(
52
+ 'platform' => 'magento',
53
+ 'admin_email' => $user->getEmail(),
54
+ 'admin_first_name' => $user->getFirstname(),
55
+ 'admin_last_name' => $user->getLastname(),
56
+ 'store_name' => $storeName,
57
+ 'store_url' => $store->getBaseUrl(),
58
+ 'customer_service_name' => Mage::getStoreConfig('trans_email/ident_support/name'),
59
+ 'customer_service_email' => Mage::getStoreConfig('trans_email/ident_support/email'),
60
+ 'store_country' => Mage::getStoreConfig('general/country/default'),
61
+ 'store_shipping_countries' => Mage::getStoreConfig('general/country/allow'),
62
+ 'store_currency' => Mage::getStoreConfig('currency/options/base'),
63
+ 'store_languages' => Mage::getStoreConfig('general/locale/code'),
64
+ 'store_paypal_email' => Mage::getStoreConfig('paypal/general/business_account'),
65
+ 'store_order_callback_url' => Mage::getUrl('pricewaiter/callback'),
66
+ 'product_data_secret' => Mage::helper('nypwidget')->getSecret(),
67
+ 'product_data_url' => Mage::getUrl('pricewaiter/productinfo')
68
+ );
69
+
70
+ // Make a string from the POST fields
71
+ $postString = '';
72
+ foreach ($postFields as $k => $v) {
73
+ if ($v != '') {
74
+ $postString .= $k . '=' . urlencode($v) . '&';
75
+ }
76
+ }
77
+ $postString = rtrim($postString, '&');
78
+
79
+ $ch = curl_init($this->_tokenUrl);
80
+ curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
81
+ curl_setopt($ch, CURLOPT_POST, true);
82
+ curl_setopt($ch, CURLOPT_POSTFIELDS, $postString);
83
+
84
+ $response = curl_exec($ch);
85
+ $response = json_decode($response);
86
+
87
+ if ($response->status == '200') {
88
+ Mage::app()->getResponse()->setBody($response->body->token);
89
+ $config = Mage::getModel('core/config');
90
+ $config->saveConfig('pricewaiter/configuration/sign_up_token', $response->body->token);
91
+ }
92
+ } catch (Exception $e) {
93
+ Mage::log('Unable to generate PriceWaiter signup token.');
94
+ }
95
+
96
+ return;
97
+ }
98
+ }
app/code/community/PriceWaiter/NYPWidget/controllers/CallbackController.php CHANGED
@@ -1,6 +1,7 @@
1
  <?php
 
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -15,6 +16,7 @@
15
  * limitations under the License.
16
  *
17
  */
 
18
  class PriceWaiter_NYPWidget_CallbackController extends Mage_Core_Controller_Front_Action
19
  {
20
 
1
  <?php
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
  *
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
16
  * limitations under the License.
17
  *
18
  */
19
+
20
  class PriceWaiter_NYPWidget_CallbackController extends Mage_Core_Controller_Front_Action
21
  {
22
 
app/code/community/PriceWaiter/NYPWidget/controllers/ProductinfoController.php ADDED
@@ -0,0 +1,164 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ *
6
+ * Licensed under the Apache License, Version 2.0 (the "License");
7
+ * you may not use this file except in compliance with the License.
8
+ * You may obtain a copy of the License at
9
+ *
10
+ * http://www.apache.org/licenses/LICENSE-2.0
11
+ *
12
+ * Unless required by applicable law or agreed to in writing, software
13
+ * distributed under the License is distributed on an "AS IS" BASIS,
14
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
+ * See the License for the specific language governing permissions and
16
+ * limitations under the License.
17
+ *
18
+ */
19
+
20
+ class PriceWaiter_NYPWidget_ProductinfoController extends Mage_Core_Controller_Front_Action
21
+ {
22
+ public function indexAction()
23
+ {
24
+ // Ensure that we have received POST data
25
+ $requestBody = Mage::app()->getRequest()->getRawBody();
26
+ $postFields = Mage::app()->getRequest()->getPost();
27
+
28
+ if (count($postFields) == 0) {
29
+ $this->norouteAction();
30
+ return;
31
+ }
32
+
33
+ // Validate the request
34
+ // - return 400 if signature cannot be verified
35
+ $signature = Mage::app()->getRequest()->getHeader('X-PriceWaiter-Signature');
36
+ if (Mage::helper('nypwidget')->isPriceWaiterRequestValid($signature, $requestBody) == false) {
37
+ Mage::app()->getResponse()->setHeader('HTTP/1.0 400 Bad Request Error', 400, true);
38
+ return false;
39
+ }
40
+
41
+ // Process the request
42
+ // - return 404 if the product does not exist (or PriceWaiter is not enabled)
43
+ $productConfiguration = array();
44
+ parse_str(urldecode($postFields['_magento_product_configuration']), $productConfiguration);
45
+
46
+ // Create a cart and add the product to it
47
+ // This is necessary to make Magento calculate the cost of the item in the correct context.
48
+ try {
49
+ $cart = Mage::getModel('checkout/cart');
50
+
51
+ $product = Mage::getModel('catalog/product')
52
+ ->setStoreId(Mage::app()->getStore()->getId())
53
+ ->load($productConfiguration['product']);
54
+
55
+ $cart->addProduct($product, $productConfiguration);
56
+ $cart->save();
57
+
58
+ $cartItem = $cart->getQuote()->getAllItems();
59
+ if ($product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE
60
+ || $product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_BUNDLE
61
+ || $product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_GROUPED
62
+ ) {
63
+ $cartItem = $cartItem[0];
64
+ } else {
65
+ $cartItem = $cartItem[1];
66
+ }
67
+
68
+ if ($product->getTypeId() != Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
69
+ $product = Mage::getModel('catalog/product')->load($cartItem->getProduct()->getId());
70
+ }
71
+
72
+ // Pull the product information from the cart item.
73
+ if (is_object($product) && $product->getId()) {
74
+ $productInformation = array();
75
+
76
+ if (Mage::helper('nypwidget')->isEnabledForStore() &&
77
+ $product->getData('nypwidget_disabled') == 0
78
+ ) {
79
+ $productInformation['allow_pricewaiter'] = true;
80
+ } else {
81
+ $productInformation['allow_pricewaiter'] = false;
82
+ }
83
+
84
+ $productType = $product->getTypeId();
85
+ if ($productType == Mage_Catalog_Model_Product_Type::TYPE_SIMPLE
86
+ || $productType == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE
87
+ ) {
88
+ $qty = $product->getStockItem()->getQty();
89
+ $productFinalPrice = $product->getFinalPrice();
90
+ $productPrice = $product->getPrice();
91
+ $msrp = $product->getData('msrp');
92
+ $cost = $product->getData('cost');
93
+ } elseif ($productType == Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
94
+ $qty = Mage::helper('nypwidget')->getGroupedQuantity($productConfiguration);
95
+ $productFinalPrice = Mage::helper('nypwidget')->getGroupedFinalPrice($productConfiguration);
96
+ $productPrice = $productFinalPrice;
97
+ $msrp = false;
98
+ $cost = Mage::helper('nypwidget')->getGroupedCost($productConfiguration);
99
+ } else {
100
+ $qty = $cartItem->getProduct()->getStockItem()->getQty();
101
+ $productFinalPrice = $cartItem->getPrice();
102
+ $productPrice = $cartItem->getFinalPrice();
103
+ $msrp = $cartItem->getData('msrp');
104
+ $cost = $cartItem->getData('cost');
105
+ }
106
+
107
+ // Check for backorders set for the site
108
+ $backorder = false;
109
+ if ($product->getStockItem()->getUseConfigBackorders() &&
110
+ Mage::getStoreConfig('cataloginventory/item_options/backorders')
111
+ ) {
112
+ $backorder = true;
113
+ } else if ($product->getStockItem()->getBackorders()) {
114
+ $backorder = true;
115
+ }
116
+
117
+ // If the product is returning a '0' quantity, but is "In Stock", set the "backorder" flag to true.
118
+ if ($product->getStockItem()->getIsInStock() == 1 && $qty == 0) {
119
+ $backorder = true;
120
+ }
121
+
122
+ $productInformation['inventory'] = (int)$qty;
123
+ $productInformation['can_backorder'] = $backorder;
124
+
125
+ $productInformation['inventory'] = (int)$qty;
126
+
127
+ $currency = Mage::app()->getStore()->getCurrentCurrencyCode();
128
+
129
+ if ($productFinalPrice != 0) {
130
+ $productInformation['retail_price'] = (string)$productFinalPrice;
131
+ $productInformation['retail_price_currency'] = $currency;
132
+ }
133
+
134
+ if ($msrp != '') {
135
+ $productInformation['regular_price'] = (string)$msrp;
136
+ $productInformation['regular_price_currency'] = $currency;
137
+ } elseif ($productPrice != 0) {
138
+ $productInformation['regular_price'] = (string)$productPrice;
139
+ $productInformation['regular_price_currency'] = $currency;
140
+ }
141
+
142
+ if ($cost) {
143
+ $productInformation['cost'] = (string)$cost;
144
+ $productInformation['cost_currency'] = (string)$productInformation['retail_price_currency'];
145
+ }
146
+
147
+ // Sign response and send.
148
+ $json = json_encode($productInformation);
149
+ $signature = Mage::helper('nypwidget')->getResponseSignature($json);
150
+
151
+ Mage::app()->getResponse()->setHeader('X-PriceWaiter-Signature', $signature);
152
+ Mage::app()->getResponse()->setBody($json);
153
+ } else {
154
+ Mage::app()->getResponse()->setHeader('HTTP/1.0 404 Not Found', 404, true);
155
+ return;
156
+ }
157
+ } catch (Exception $e) {
158
+ Mage::log("Unable to fulfill PriceWaiter Product Information request for product ID: " . $productConfiguration['product']);
159
+ Mage::log($e->getMessage());
160
+ Mage::app()->getResponse()->setHeader('HTTP/1.0 404 Not Found', 404, true);
161
+ return;
162
+ }
163
+ }
164
+ }
app/code/community/PriceWaiter/NYPWidget/etc/adminhtml.xml CHANGED
@@ -1,6 +1,6 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
app/code/community/PriceWaiter/NYPWidget/etc/config.xml CHANGED
@@ -1,6 +1,6 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
@@ -18,7 +18,7 @@
18
 
19
  <modules>
20
  <PriceWaiter_NYPWidget>
21
- <version>1.2.7</version>
22
  </PriceWaiter_NYPWidget>
23
  </modules>
24
 
@@ -29,7 +29,7 @@
29
  <resourceModel>nypwidget_mysql4</resourceModel>
30
  </nypwidget>
31
  <nypwidget_mysql4>
32
- <class>PriceWaiter_NYPWidget_Model_Mysql4</class>
33
  <entities>
34
  <category>
35
  <table>nypwidget_category</table>
@@ -79,26 +79,26 @@
79
  </nypwidget_read>
80
  </resources>
81
  <events>
82
- <adminhtml_catalog_category_tabs>
83
- <observers>
84
- <adminhtml_catalog_category_tabs_pricewaiter>
85
- <type>model</type>
86
- <class>nypwidget/observer</class>
87
- <method>addTab</method>
88
- <args></args>
89
- </adminhtml_catalog_category_tabs_pricewaiter>
90
- </observers>
91
- </adminhtml_catalog_category_tabs>
92
- <catalog_category_prepare_save>
93
- <observers>
94
- <catalog_category_prepare_save_pricewaiter>
95
- <type>model</type>
96
- <class>nypwidget/observer</class>
97
- <method>saveCategory</method>
98
- <args></args>
99
- </catalog_category_prepare_save_pricewaiter>
100
- </observers>
101
- </catalog_category_prepare_save>
102
  </events>
103
  </global>
104
 
@@ -131,21 +131,42 @@
131
  </layout>
132
  </adminhtml>
133
 
 
 
 
 
 
 
 
 
 
 
 
 
134
  <default>
135
  <pricewaiter>
136
  <configuration>
137
  <enabled>0</enabled>
138
  <log>1</log>
139
  </configuration>
 
 
 
 
 
 
 
 
 
140
  <appearance>
141
  <display_size>1</display_size>
142
  <display_color>5F82D4</display_color>
143
  <display_hover_color>739DFF</display_hover_color>
144
- </appearance>
145
- <customer_interaction>
146
- <send_welcome_email>0</send_welcome_email>
147
- <send_new_order_email>0</send_new_order_email>
148
- </customer_interaction>
149
  <categories>
150
  <disable_by_category>1</disable_by_category>
151
  </categories>
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
18
 
19
  <modules>
20
  <PriceWaiter_NYPWidget>
21
+ <version>2.0.0</version>
22
  </PriceWaiter_NYPWidget>
23
  </modules>
24
 
29
  <resourceModel>nypwidget_mysql4</resourceModel>
30
  </nypwidget>
31
  <nypwidget_mysql4>
32
+ <class>PriceWaiter_NYPWidget_Model_Mysql4</class>
33
  <entities>
34
  <category>
35
  <table>nypwidget_category</table>
79
  </nypwidget_read>
80
  </resources>
81
  <events>
82
+ <adminhtml_catalog_category_tabs>
83
+ <observers>
84
+ <adminhtml_catalog_category_tabs_pricewaiter>
85
+ <type>model</type>
86
+ <class>nypwidget/observer</class>
87
+ <method>addTab</method>
88
+ <args></args>
89
+ </adminhtml_catalog_category_tabs_pricewaiter>
90
+ </observers>
91
+ </adminhtml_catalog_category_tabs>
92
+ <catalog_category_prepare_save>
93
+ <observers>
94
+ <catalog_category_prepare_save_pricewaiter>
95
+ <type>model</type>
96
+ <class>nypwidget/observer</class>
97
+ <method>saveCategory</method>
98
+ <args></args>
99
+ </catalog_category_prepare_save_pricewaiter>
100
+ </observers>
101
+ </catalog_category_prepare_save>
102
  </events>
103
  </global>
104
 
131
  </layout>
132
  </adminhtml>
133
 
134
+ <admin>
135
+ <routers>
136
+ <adminhtml>
137
+ <args>
138
+ <modules>
139
+ <PriceWaiter_NYPWidget after="Mage_Adminhtml">PriceWaiter_NYPWidget</PriceWaiter_NYPWidget>
140
+ </modules>
141
+ </args>
142
+ </adminhtml>
143
+ </routers>
144
+ </admin>
145
+
146
  <default>
147
  <pricewaiter>
148
  <configuration>
149
  <enabled>0</enabled>
150
  <log>1</log>
151
  </configuration>
152
+ <customer_groups>
153
+ <disable>0</disable>
154
+ <group_select>0</group_select>
155
+ </customer_groups>
156
+ <conversion_tools>
157
+ <enabled>1</enabled>
158
+ <customer_group_disable>0</customer_group_disable>
159
+ <disable_by_category>1</disable_by_category>
160
+ </conversion_tools>
161
  <appearance>
162
  <display_size>1</display_size>
163
  <display_color>5F82D4</display_color>
164
  <display_hover_color>739DFF</display_hover_color>
165
+ </appearance>
166
+ <customer_interaction>
167
+ <send_welcome_email>0</send_welcome_email>
168
+ <send_new_order_email>0</send_new_order_email>
169
+ </customer_interaction>
170
  <categories>
171
  <disable_by_category>1</disable_by_category>
172
  </categories>
app/code/community/PriceWaiter/NYPWidget/etc/system.xml CHANGED
@@ -1,6 +1,6 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
@@ -44,7 +44,7 @@
44
  </comment>
45
  <frontend_type>select</frontend_type>
46
  <source_model>adminhtml/system_config_source_yesno</source_model>
47
- <sort_order>10</sort_order>
48
  <show_in_default>1</show_in_default>
49
  <show_in_website>1</show_in_website>
50
  <show_in_store>1</show_in_store>
@@ -53,15 +53,43 @@
53
  <label>API Key</label>
54
  <comment>
55
  <![CDATA[The API Key you were given when signing
56
- up for PriceWaiter. If you do not have one,
57
- sign up <a href="http://www.pricewaiter.com/">here</a>.]]>
58
  </comment>
59
  <frontend_type>text</frontend_type>
60
- <sort_order>20</sort_order>
61
  <show_in_default>1</show_in_default>
62
  <show_in_website>1</show_in_website>
63
  <show_in_store>1</show_in_store>
64
  </api_key>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
65
  <log translate="label comment">
66
  <label>Log Callback Information</label>
67
  <comment>
@@ -73,100 +101,111 @@
73
  </comment>
74
  <frontend_type>select</frontend_type>
75
  <source_model>adminhtml/system_config_source_yesno</source_model>
76
- <sort_order>10</sort_order>
77
  <show_in_default>1</show_in_default>
78
  <show_in_website>1</show_in_website>
79
  <show_in_store>1</show_in_store>
80
  </log>
81
  </fields>
82
  </configuration>
83
- <appearance translate="label">
84
- <label>Appearance</label>
85
  <frontend_type>text</frontend_type>
86
- <sort_order>10</sort_order>
87
  <show_in_default>1</show_in_default>
88
  <show_in_website>1</show_in_website>
89
  <show_in_store>1</show_in_store>
90
  <expanded>1</expanded>
91
  <fields>
92
- <preview translate="label comment"><!--#pricewaiter_appearance_preview-->
93
- <label>Preview</label>
94
  <comment>
95
- <![CDATA[What the "Name Your Price" widget will
96
- look like on your product pages.]]>
97
  </comment>
98
- <frontend_type>hidden</frontend_type>
99
- <sort_order>10</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
- </preview>
104
- </fields>
105
- <fields>
106
- <display_phrase translate="label comment"><!--#pricewaiter_appearance_button_phrase-->
107
- <label>Button Phrase</label>
108
- <comment>
109
- <![CDATA[Should the PriceWaiter Button read "Name Your Price"
110
- or "Make an Offer"?]]>
111
- </comment>
112
- <frontend_type>select</frontend_type>
113
- <source_model>nypwidget/display_phrase</source_model>
114
  <sort_order>10</sort_order>
115
  <show_in_default>1</show_in_default>
116
  <show_in_website>1</show_in_website>
117
  <show_in_store>1</show_in_store>
118
- </display_phrase>
119
  </fields>
 
 
 
 
 
 
 
 
 
120
  <fields>
121
- <display_size translate="label comment"><!--#pricewaiter_appearance_display_size-->
122
- <label>Display Size</label>
123
- <comment></comment>
 
 
 
124
  <frontend_type>select</frontend_type>
125
- <source_model>nypwidget/display_size</source_model>
126
- <sort_order>20</sort_order>
127
  <show_in_default>1</show_in_default>
128
  <show_in_website>1</show_in_website>
129
  <show_in_store>1</show_in_store>
130
- </display_size>
131
- </fields>
132
- <fields>
133
- <display_color translate="label comment"><!--#pricewaiter_appearance_button_color-->
134
- <label>Color</label>
135
  <comment>
136
- <![CDATA[The button background color in hexadecimal notation.]]>
 
137
  </comment>
138
- <frontend_type>text</frontend_type>
139
- <validate>color</validate>
140
- <sort_order>30</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
- </display_color>
145
- <display_hover_color translate="label comment"><!--#pricewaiter_appearance_button_hover_color-->
146
- <label>Hover Color</label>
147
- <comment>
148
- <![CDATA[The button background color, in hexadecimal notation, when it
149
- is being hovered over.]]>
150
- </comment>
151
- <frontend_type>text</frontend_type>
152
- <validate>color</validate>
153
- <sort_order>40</sort_order>
154
  <show_in_default>1</show_in_default>
155
  <show_in_website>1</show_in_website>
156
  <show_in_store>1</show_in_store>
157
- </display_hover_color>
158
- <display_custom_css translate="label comment">
159
- <label>Custom CSS</label>
160
- <comment>
161
- <![CDATA[Add custom CSS that will be added to the container that holds
162
- the PriceWaiter button. This field is not validated.]]>
163
- </comment>
164
- <frontend_type>text</frontend_type>
165
- <sort_order>50</sort_order>
 
 
 
 
 
 
 
 
 
166
  <show_in_default>1</show_in_default>
167
  <show_in_website>1</show_in_website>
168
  <show_in_store>1</show_in_store>
169
- </display_custom_css>
170
  </fields>
171
  </appearance>
172
  <customer_interaction>
@@ -181,7 +220,7 @@
181
  <send_welcome_email>
182
  <label>Send Welcome Email to New Customers?</label>
183
  <comment>
184
- <![CDATA[With this enabled, new customers created when Magento receives a new
185
  order notification will receive your store's Welcome email in addition to
186
  PriceWaiter's.]]>
187
  </comment>
@@ -195,7 +234,7 @@
195
  <send_new_order_email>
196
  <label>Send New Order Email to Customers?</label>
197
  <comment>
198
- <![CDATA[With this enabled, new orders created when Magento receives a new
199
  order notification will trigger your store's New Order email in addition to
200
  PriceWaiter's.]]>
201
  </comment>
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
44
  </comment>
45
  <frontend_type>select</frontend_type>
46
  <source_model>adminhtml/system_config_source_yesno</source_model>
47
+ <sort_order>0</sort_order>
48
  <show_in_default>1</show_in_default>
49
  <show_in_website>1</show_in_website>
50
  <show_in_store>1</show_in_store>
53
  <label>API Key</label>
54
  <comment>
55
  <![CDATA[The API Key you were given when signing
56
+ up for PriceWaiter.]]>
 
57
  </comment>
58
  <frontend_type>text</frontend_type>
59
+ <sort_order>10</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
  </api_key>
64
+ <sign_up_token>
65
+ <frontend_type>hidden</frontend_type>
66
+ <sort_order>100</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
+ </sign_up_token>
71
+ <sign_up>
72
+ <label></label>
73
+ <comment></comment>
74
+ <frontend_type>button</frontend_type>
75
+ <frontend_model>nypwidget/adminhtml_signup</frontend_model>
76
+ <sort_order>20</sort_order>
77
+ <show_in_default>1</show_in_default>
78
+ <show_in_website>1</show_in_website>
79
+ <show_in_store>1</show_in_store>
80
+ </sign_up>
81
+ <api_secret translate="label comment">
82
+ <label>API Secret</label>
83
+ <comment>
84
+ <![CDATA[The API Secret is not necessary to use PriceWaiter,
85
+ but is required by some premium features.]]>
86
+ </comment>
87
+ <frontend_type>text</frontend_type>
88
+ <sort_order>25</sort_order>
89
+ <show_in_default>1</show_in_default>
90
+ <show_in_website>1</show_in_website>
91
+ <show_in_store>1</show_in_store>
92
+ </api_secret>
93
  <log translate="label comment">
94
  <label>Log Callback Information</label>
95
  <comment>
101
  </comment>
102
  <frontend_type>select</frontend_type>
103
  <source_model>adminhtml/system_config_source_yesno</source_model>
104
+ <sort_order>30</sort_order>
105
  <show_in_default>1</show_in_default>
106
  <show_in_website>1</show_in_website>
107
  <show_in_store>1</show_in_store>
108
  </log>
109
  </fields>
110
  </configuration>
111
+ <customer_groups translate="label">
112
+ <label>Disable button by Customer Groups</label>
113
  <frontend_type>text</frontend_type>
114
+ <sort_order>5</sort_order>
115
  <show_in_default>1</show_in_default>
116
  <show_in_website>1</show_in_website>
117
  <show_in_store>1</show_in_store>
118
  <expanded>1</expanded>
119
  <fields>
120
+ <disable translate="label comment">
121
+ <label>Disable the "Name Your Price" widget by customer group?</label>
122
  <comment>
123
+ <![CDATA[Setting this option to "Yes" will disable the widget for customer groups
124
+ selected below]]>
125
  </comment>
126
+ <frontend_type>select</frontend_type>
127
+ <source_model>adminhtml/system_config_source_yesno</source_model>
128
+ <sort_order>0</sort_order>
129
  <show_in_default>1</show_in_default>
130
  <show_in_website>1</show_in_website>
131
  <show_in_store>1</show_in_store>
132
+ </disable>
133
+ <group_select translate="label comment">
134
+ <label>Customer Groups</label>
135
+ <frontend_type>multiselect</frontend_type>
136
+ <source_model>customer/resource_group_collection</source_model>
 
 
 
 
 
 
137
  <sort_order>10</sort_order>
138
  <show_in_default>1</show_in_default>
139
  <show_in_website>1</show_in_website>
140
  <show_in_store>1</show_in_store>
141
+ </group_select>
142
  </fields>
143
+ </customer_groups>
144
+ <conversion_tools translate="label">
145
+ <label>Conversion Tools (such as Exit Intent)</label>
146
+ <frontend_type>text</frontend_type>
147
+ <sort_order>7</sort_order>
148
+ <show_in_default>1</show_in_default>
149
+ <show_in_website>1</show_in_website>
150
+ <show_in_store>1</show_in_store>
151
+ <expanded>1</expanded>
152
  <fields>
153
+ <enabled translate="label comment">
154
+ <label>Enabled</label>
155
+ <comment>
156
+ <![CDATA[Disabling this option will disable Conversion Tools on your site. You must have a 'Premium'
157
+ account for Conversion Tools to display on your site.]]>
158
+ </comment>
159
  <frontend_type>select</frontend_type>
160
+ <source_model>adminhtml/system_config_source_yesno</source_model>
161
+ <sort_order>0</sort_order>
162
  <show_in_default>1</show_in_default>
163
  <show_in_website>1</show_in_website>
164
  <show_in_store>1</show_in_store>
165
+ </enabled>
166
+ <customer_group_disable translate="label comment">
167
+ <label>Disable Conversion Tools by customer group?</label>
 
 
168
  <comment>
169
+ <![CDATA[Setting this option to "Yes" will disable conversion tools for customer groups
170
+ selected below]]>
171
  </comment>
172
+ <frontend_type>select</frontend_type>
173
+ <source_model>adminhtml/system_config_source_yesno</source_model>
174
+ <sort_order>5</sort_order>
175
  <show_in_default>1</show_in_default>
176
  <show_in_website>1</show_in_website>
177
  <show_in_store>1</show_in_store>
178
+ </customer_group_disable>
179
+ <group_select translate="label comment">
180
+ <label>Customer Groups</label>
181
+ <frontend_type>multiselect</frontend_type>
182
+ <source_model>customer/resource_group_collection</source_model>
183
+ <sort_order>10</sort_order>
 
 
 
 
184
  <show_in_default>1</show_in_default>
185
  <show_in_website>1</show_in_website>
186
  <show_in_store>1</show_in_store>
187
+ </group_select>
188
+ </fields>
189
+ </conversion_tools>
190
+ <appearance translate="label">
191
+ <label>Appearance</label>
192
+ <frontend_type>text</frontend_type>
193
+ <sort_order>10</sort_order>
194
+ <show_in_default>1</show_in_default>
195
+ <show_in_website>1</show_in_website>
196
+ <show_in_store>1</show_in_store>
197
+ <expanded>1</expanded>
198
+ <fields>
199
+ <button_link translate="label comment">
200
+ <label>Widget Appearance</label>
201
+ <frontend_type>link</frontend_type>
202
+ <frontend_model>nypwidget/adminhtml_link</frontend_model>
203
+ <comment><![CDATA[Follow the provided link to customize the PriceWaiter widget appearance.]]></comment>
204
+ <sort_order>10</sort_order>
205
  <show_in_default>1</show_in_default>
206
  <show_in_website>1</show_in_website>
207
  <show_in_store>1</show_in_store>
208
+ </button_link>
209
  </fields>
210
  </appearance>
211
  <customer_interaction>
220
  <send_welcome_email>
221
  <label>Send Welcome Email to New Customers?</label>
222
  <comment>
223
+ <![CDATA[With this enabled, new customers created when Magento receives a new
224
  order notification will receive your store's Welcome email in addition to
225
  PriceWaiter's.]]>
226
  </comment>
234
  <send_new_order_email>
235
  <label>Send New Order Email to Customers?</label>
236
  <comment>
237
+ <![CDATA[With this enabled, new orders created when Magento receives a new
238
  order notification will trigger your store's New Order email in addition to
239
  PriceWaiter's.]]>
240
  </comment>
app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-install-1.0.0.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
1
  <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.1.2-1.1.3.php CHANGED
@@ -1,7 +1,7 @@
1
  <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -27,25 +27,25 @@ $installer->removeAttribute('catalog_product', 'nypwidget_enabled');
27
  // Add a new attribute to all prodcuts to toggle the Widget on/off
28
  $installer->addAttribute('catalog_product', 'nypwidget_disabled',
29
  array(
30
- 'group' => 'General',
31
- 'label' => 'Disable PriceWaiter Widget?',
32
- 'type' => 'int',
33
- 'input' => 'boolean',
34
- 'default' => '0',
35
- 'class' => '',
36
- 'backend' => '',
37
- 'frontend' => '',
38
- 'source' => '',
39
- 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
40
- 'visible' => true,
41
- 'required' => true,
42
- 'user_defined' => false,
43
- 'searchable' => true,
44
- 'filterable' => true,
45
- 'comparable' => true,
46
- 'visible_on_front' => true,
47
  'visible_in_advanced_search' => false,
48
- 'unique' => false,
49
- 'apply_to' => $supportTypeIds,
50
  )
51
  );
1
  <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
+ *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
27
  // Add a new attribute to all prodcuts to toggle the Widget on/off
28
  $installer->addAttribute('catalog_product', 'nypwidget_disabled',
29
  array(
30
+ 'group' => 'General',
31
+ 'label' => 'Disable PriceWaiter Widget?',
32
+ 'type' => 'int',
33
+ 'input' => 'boolean',
34
+ 'default' => '0',
35
+ 'class' => '',
36
+ 'backend' => '',
37
+ 'frontend' => '',
38
+ 'source' => '',
39
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
40
+ 'visible' => true,
41
+ 'required' => true,
42
+ 'user_defined' => false,
43
+ 'searchable' => true,
44
+ 'filterable' => true,
45
+ 'comparable' => true,
46
+ 'visible_on_front' => true,
47
  'visible_in_advanced_search' => false,
48
+ 'unique' => false,
49
+ 'apply_to' => $supportTypeIds,
50
  )
51
  );
app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.1.7-1.1.8.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
1
  <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.2.4-1.2.5.php CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
1
  <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
app/code/community/PriceWaiter/NYPWidget/sql/nypwidget_setup/mysql4-upgrade-1.3.0-1.3.1.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
+ *
5
+ * Licensed under the Apache License, Version 2.0 (the "License");
6
+ * you may not use this file except in compliance with the License.
7
+ * You may obtain a copy of the License at
8
+ *
9
+ * http://www.apache.org/licenses/LICENSE-2.0
10
+ *
11
+ * Unless required by applicable law or agreed to in writing, software
12
+ * distributed under the License is distributed on an "AS IS" BASIS,
13
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
+ * See the License for the specific language governing permissions and
15
+ * limitations under the License.
16
+ *
17
+ */
18
+
19
+ // Product types supported by the Name Your Price Widget
20
+ $supportTypeIds = array('simple', 'configurable', 'grouped', 'bundle');
21
+
22
+ $installer = $this;
23
+ $installer->startSetup();
24
+
25
+ // Add a new attribute to all products to toggle the Conversion Tools on/off
26
+ $installer->addAttribute('catalog_product', 'nypwidget_ct_disabled',
27
+ array(
28
+ 'group' => 'General',
29
+ 'label' => 'Disable PriceWaiter Conversion Tools? (such as Exit Intent)',
30
+ 'type' => 'int',
31
+ 'input' => 'boolean',
32
+ 'default' => '0',
33
+ 'class' => '',
34
+ 'backend' => '',
35
+ 'frontend' => '',
36
+ 'source' => '',
37
+ 'global' => Mage_Catalog_Model_Resource_Eav_Attribute::SCOPE_STORE,
38
+ 'visible' => true,
39
+ 'required' => true,
40
+ 'user_defined' => false,
41
+ 'searchable' => true,
42
+ 'filterable' => true,
43
+ 'comparable' => true,
44
+ 'visible_on_front' => true,
45
+ 'visible_in_advanced_search' => false,
46
+ 'unique' => false,
47
+ 'apply_to' => $supportTypeIds,
48
+ )
49
+ );
50
+
51
+ // Add an attribute to our nypwidget_category table to hold conversion tools information
52
+ $installer->run("
53
+ ALTER TABLE {$this->getTable('nypwidget_category')} ADD COLUMN `nypwidget_ct_enabled` tinyint(1) NOT NULL default '1' AFTER nypwidget_enabled;
54
+ ");
app/design/adminhtml/default/default/layout/pricewaiter.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
-
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
7
  You may obtain a copy of the License at
@@ -17,12 +17,12 @@
17
  <layout>
18
  <adminhtml_system_config_edit>
19
  <reference name="head">
20
- <action method="addCss"><name>pricewaiter.css</name></action>
21
- <action method="addJs"><name>jscolor-pw/jscolor.js</name></action>
22
- <action method="addJs"><name>pricewaiter/product-pages.js</name></action>
23
- </reference>
24
- <reference name="content">
25
- <block type="nypwidget/adminhtml_widget" name="widget_preview" as="widget_preview" template="pricewaiter/admin_widget.phtml"></block>
26
  </reference>
27
  </adminhtml_system_config_edit>
28
  </layout>
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
+
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
7
  You may obtain a copy of the License at
17
  <layout>
18
  <adminhtml_system_config_edit>
19
  <reference name="head">
20
+ <action method="addCss">
21
+ <name>pricewaiter.css</name>
22
+ </action>
23
+ <action method="addJs">
24
+ <name>pricewaiter/token.js</name>
25
+ </action>
26
  </reference>
27
  </adminhtml_system_config_edit>
28
  </layout>
app/design/adminhtml/default/default/template/pricewaiter/admin_widget.phtml DELETED
@@ -1,32 +0,0 @@
1
- <?php
2
- /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
- * Licensed under the Apache License, Version 2.0 (the "License");
6
- * you may not use this file except in compliance with the License.
7
- * You may obtain a copy of the License at
8
- *
9
- * http://www.apache.org/licenses/LICENSE-2.0
10
- *
11
- * Unless required by applicable law or agreed to in writing, software
12
- * distributed under the License is distributed on an "AS IS" BASIS,
13
- * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14
- * See the License for the specific language governing permissions and
15
- * limitations under the License.
16
- *
17
- */
18
- ?>
19
- <?php $helper = $this->_getHelper(); ?>
20
- <script type="text/javascript">
21
- //<![CDATA[
22
- <?php echo $helper->getPriceWaiterOptions(); ?>
23
- <?php echo $helper->getProductOptions(true); ?>
24
-
25
- var PriceWaiterWidgetUrl = "<?php echo $helper->getWidgetUrl(); ?>";
26
-
27
- function adminPW() {
28
- $('pricewaiter_appearance_preview').up().innerHTML = '<span id="pricewaiter"></span><p class="note"><span> What the "Name Your Price" widget will look like on your product pages. </span></p>';
29
- }
30
-
31
- //]]>
32
- </script>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
app/design/adminhtml/default/default/template/pricewaiter/categorytab.phtml CHANGED
@@ -1,7 +1,7 @@
1
- <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
- *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
@@ -16,33 +16,47 @@
16
  *
17
  */
18
  ?>
19
- <?php
20
  $enabled = $this->getIsEnabled();
 
21
  ?>
22
  <div class="entry-edit">
23
- <div class="entry-edit-head">
24
- <h4 class="icon-head head-edit-form fieldset-legend">PriceWaiter Widget</h4>
25
- </div>
26
- <div class="fieldset fieldset-wide" id="group_pricewaiter">
27
- <div class="hor-scroll">
28
- <table cellspacing="0" class="form-list">
29
- <tbody>
 
 
 
 
 
 
 
 
 
 
 
 
 
30
 
31
- <tr>
32
- <td class="label"><label for="group_pricewaiter_enabled">Enabled</label></td>
33
- <td class="value">
34
- <select id="group_pricewaiter_enabled" name="pricewaiter[enabled]" class=" select">
35
- <option value="1" <?php if ($enabled):?>selected="selected"<?php endif;?>>Yes</option>
36
- <option value="0" <?php if (!$enabled):?>selected="selected"<?php endif;?>>No</option>
37
- </select>
38
- </td>
39
- <td class="scope-label">
40
- <span class="nobr">[STORE VIEW]</span>
41
- </td>
42
- </tr>
43
 
44
- </tbody>
45
- </table>
46
- </div>
47
- </div>
48
  </div>
1
+ <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
+ *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
7
  * You may obtain a copy of the License at
16
  *
17
  */
18
  ?>
19
+ <?php
20
  $enabled = $this->getIsEnabled();
21
+ $ctEnabled = $this->getIsConversionToolsEnabled();
22
  ?>
23
  <div class="entry-edit">
24
+ <div class="entry-edit-head">
25
+ <h4 class="icon-head head-edit-form fieldset-legend">PriceWaiter Widget</h4>
26
+ </div>
27
+ <div class="fieldset fieldset-wide" id="group_pricewaiter">
28
+ <div class="hor-scroll">
29
+ <table cellspacing="0" class="form-list">
30
+ <tbody>
31
+
32
+ <tr>
33
+ <td class="label"><label for="group_pricewaiter_enabled">Enabled</label></td>
34
+ <td class="value">
35
+ <select id="group_pricewaiter_enabled" name="pricewaiter[enabled]" class=" select">
36
+ <option value="1" <?php if ($enabled): ?>selected="selected"<?php endif; ?>>Yes</option>
37
+ <option value="0" <?php if (!$enabled): ?>selected="selected"<?php endif; ?>>No</option>
38
+ </select>
39
+ </td>
40
+ <td class="scope-label">
41
+ <span class="nobr">[STORE VIEW]</span>
42
+ </td>
43
+ </tr>
44
 
45
+ <tr>
46
+ <td class="label"><label for="group_pricewaiter_conversion_tools_enabled">Conversion Tools Enabled</label></td>
47
+ <td class="value">
48
+ <select id="group_pricewaiter_conversion_tools_enabled" name="pricewaiter[ct_enabled]" class=" select">
49
+ <option value="1" <?php if ($ctEnabled): ?>selected="selected"<?php endif; ?>>Yes</option>
50
+ <option value="0" <?php if (!$ctEnabled): ?>selected="selected"<?php endif; ?>>No</option>
51
+ </select>
52
+ </td>
53
+ <td class="scope-label">
54
+ <span class="nobr">[STORE VIEW]</span>
55
+ </td>
56
+ </tr>
57
 
58
+ </tbody>
59
+ </table>
60
+ </div>
61
+ </div>
62
  </div>
app/design/adminhtml/default/default/template/pricewaiter/signup.phtml ADDED
@@ -0,0 +1,4 @@
 
 
 
 
1
+ <?php echo $this->getButtonHtml(); ?>
2
+ <script type="text/javascript">
3
+ var priceWaiterTokenURL = '<?php echo $this->getTokenUrl(); ?>';
4
+ </script>
app/design/frontend/base/default/layout/pricewaiter.xml CHANGED
@@ -1,6 +1,6 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
@@ -16,11 +16,13 @@
16
  -->
17
  <layout>
18
  <catalog_product_view>
19
- <reference name="head">
20
- <action method="addJs"><name>pricewaiter/product-pages.js</name></action>
21
- </reference>
 
 
22
  <reference name="product.info.addtocart">
23
- <block type="nypwidget/widget" name="pricewaiter_widget" template="pricewaiter/widget.phtml" as="pricewaiter.widget" />
24
  </reference>
25
  </catalog_product_view>
26
  </layout>
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
 
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
16
  -->
17
  <layout>
18
  <catalog_product_view>
19
+ <reference name="head">
20
+ <action method="addJs">
21
+ <name>pricewaiter/product-pages.js</name>
22
+ </action>
23
+ </reference>
24
  <reference name="product.info.addtocart">
25
+ <block type="nypwidget/widget" name="pricewaiter_widget" template="pricewaiter/widget.phtml" as="pricewaiter.widget"/>
26
  </reference>
27
  </catalog_product_view>
28
  </layout>
app/design/frontend/base/default/template/pricewaiter/widget.phtml CHANGED
@@ -1,6 +1,6 @@
1
  <?php
2
  /*
3
- * Copyright 2013 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
@@ -17,21 +17,74 @@
17
  */
18
  ?>
19
  <?php $_product = Mage::registry('current_product'); ?>
20
- <?php if($_product->isSaleable()): ?>
21
- <?php
22
- $customCss = Mage::getStoreConfig('pricewaiter/appearance/display_custom_css');
23
- $helper = $this->_getHelper();
24
- if ($helper->isEnabled()):
25
- ?>
26
- <script type="text/javascript">
27
- //<![CDATA[
28
- <?php echo $helper->getPriceWaiterOptions(); ?>
29
- <?php echo $helper->getProductOptions(); ?>
30
- var PriceWaiterWidgetUrl = "<?php echo $helper->getWidgetUrl(); ?>";
31
- //]]>
32
- </script>
33
- <div class="name-your-price-widget" style='display: block; clear: both; padding-top: 10px; <?php echo $customCss; ?>'>
34
- <span id="pricewaiter"></span>
35
- </div>
36
- <?php endif; ?>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
37
  <?php endif; ?>
1
  <?php
2
  /*
3
+ * Copyright 2013-2015 Price Waiter, LLC
4
  *
5
  * Licensed under the Apache License, Version 2.0 (the "License");
6
  * you may not use this file except in compliance with the License.
17
  */
18
  ?>
19
  <?php $_product = Mage::registry('current_product'); ?>
20
+ <?php if ($_product->isSaleable()): ?>
21
+ <?php
22
+ $customCss = Mage::getStoreConfig('pricewaiter/appearance/display_custom_css');
23
+ $helper = $this->_getHelper();
24
+
25
+ $brand = $_product->getData('brand');
26
+ $image = $_product->getImageUrl();
27
+ $currency = Mage::app()->getStore()->getCurrentCurrencyCode();
28
+ if ($_product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_GROUPED) {
29
+ $groupedInformation = $helper->getGroupedProductInfo();
30
+ } else {
31
+ $groupedInformation = '';
32
+ }
33
+ if ($helper->isEnabledForStore()):
34
+ ?>
35
+ <script type="text/javascript">
36
+ //<![CDATA[
37
+ <?php echo $groupedInformation; ?>
38
+ var PriceWaiterOptions = {
39
+ <?php if ($helper->isButtonEnabled()): ?>
40
+ enableButton: true,
41
+ <?php else: ?>
42
+ enableButton: false,
43
+ <?php endif; ?>
44
+ currency: '<?php echo $currency; ?>',
45
+ <?php if ($helper->isConversionToolsEnabled()): ?>
46
+ enableConversionTools: true,
47
+ <?php else: ?>
48
+ enableConversionTools: false,
49
+ <?php endif; ?>
50
+
51
+ product: {
52
+ <?php if ($brand): ?>
53
+ brand: <?php json_encode($brand); ?>,
54
+ <?php endif; ?>
55
+ sku: <?php echo json_encode($_product->getSku()); ?>,
56
+ name: <?php echo json_encode($_product->getName()); ?>,
57
+ price: <?php echo json_encode($helper->getProductPrice($_product)); ?>,
58
+ <?php if ($image != ''): ?>
59
+ image: <?php echo json_encode($image); ?>
60
+ <?php endif; ?>
61
+ }
62
+ };
63
+
64
+ var PriceWaiterRegularPrice = '<?php echo (float) $_product->getPrice(); ?>';
65
+ var PriceWaiterProductType = '<?php echo $_product->getTypeId(); ?>';
66
+ var PriceWaiterWidgetUrl = "<?php echo $helper->getWidgetUrl(); ?>";
67
+ //]]>
68
+ </script>
69
+ <div class="name-your-price-widget"
70
+ style='display: block; clear: both; padding-top: 10px; <?php echo $customCss; ?>'>
71
+ <span id="pricewaiter"></span>
72
+ </div>
73
+ <?php endif; ?>
74
+ <?php if ($_product->getTypeId() == Mage_Catalog_Model_Product_Type::TYPE_CONFIGURABLE): ?>
75
+ <?php
76
+ $simples = Mage::getModel('catalog/product_type_configurable')->setProduct($_product)
77
+ ->getUsedProductCollection()
78
+ ->addAttributeToSelect('sku');
79
+
80
+ $idToSku = array();
81
+ foreach ($simples as $simple) {
82
+ $idToSku[$simple->getId()] = $simple->getSku();
83
+ } ?>
84
+ <?php if (count($idToSku) > 0): ?>
85
+ <script type="text/javascript">
86
+ var PriceWaiterIdToSkus = <?php echo json_encode($idToSku); ?>;
87
+ </script>
88
+ <?php endif; ?>
89
+ <?php endif; ?>
90
  <?php endif; ?>
app/etc/modules/PriceWaiter_NYPWidget.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
- Copyright 2013 Price Waiter, LLC
4
-
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
7
  You may obtain a copy of the License at
@@ -19,6 +19,6 @@
19
  <PriceWaiter_NYPWidget>
20
  <active>true</active>
21
  <codePool>community</codePool>
22
- </PriceWaiter_NYPWidget>
23
  </modules>
24
  </config>
1
  <?xml version="1.0" encoding="utf-8"?>
2
  <!--
3
+ Copyright 2013-2015 Price Waiter, LLC
4
+
5
  Licensed under the Apache License, Version 2.0 (the "License");
6
  you may not use this file except in compliance with the License.
7
  You may obtain a copy of the License at
19
  <PriceWaiter_NYPWidget>
20
  <active>true</active>
21
  <codePool>community</codePool>
22
+ </PriceWaiter_NYPWidget>
23
  </modules>
24
  </config>
js/jscolor-pw/arrow.gif DELETED
Binary file
js/jscolor-pw/cross.gif DELETED
Binary file
js/jscolor-pw/hs.png DELETED
Binary file
js/jscolor-pw/hv.png DELETED
Binary file
js/jscolor-pw/jscolor.js DELETED
@@ -1,935 +0,0 @@
1
- /**
2
- * jscolor, JavaScript Color Picker
3
- *
4
- * @version 1.3.13
5
- * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html
6
- * @author Jan Odvarko, http://odvarko.cz
7
- * @created 2008-06-15
8
- * @updated 2012-01-19
9
- * @link http://jscolor.com
10
- */
11
-
12
-
13
- var jscolor = {
14
-
15
-
16
- dir : '', // location of jscolor directory (leave empty to autodetect)
17
- bindClass : 'color', // class name
18
- binding : true, // automatic binding via <input class="...">
19
- preloading : true, // use image preloading?
20
-
21
-
22
- install : function() {
23
- jscolor.addEvent(window, 'load', jscolor.init);
24
- },
25
-
26
-
27
- init : function() {
28
- if(jscolor.binding) {
29
- jscolor.bind();
30
- }
31
- if(jscolor.preloading) {
32
- jscolor.preload();
33
- }
34
- },
35
-
36
-
37
- getDir : function() {
38
- if(!jscolor.dir) {
39
- var detected = jscolor.detectDir();
40
- jscolor.dir = detected!==false ? detected : 'jscolor/';
41
- }
42
- return jscolor.dir;
43
- },
44
-
45
-
46
- detectDir : function() {
47
- var base = location.href;
48
-
49
- var e = document.getElementsByTagName('base');
50
- for(var i=0; i<e.length; i+=1) {
51
- if(e[i].href) { base = e[i].href; }
52
- }
53
-
54
- var e = document.getElementsByTagName('script');
55
- for(var i=0; i<e.length; i+=1) {
56
- if(e[i].src && /(^|\/)jscolor\.js([?#].*)?$/i.test(e[i].src)) {
57
- var src = new jscolor.URI(e[i].src);
58
- var srcAbs = src.toAbsolute(base);
59
- srcAbs.path = srcAbs.path.replace(/[^\/]+$/, ''); // remove filename
60
- srcAbs.query = null;
61
- srcAbs.fragment = null;
62
- return srcAbs.toString();
63
- }
64
- }
65
- return false;
66
- },
67
-
68
-
69
- bind : function() {
70
- var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')\\s*(\\{[^}]*\\})?', 'i');
71
- var e = document.getElementsByTagName('input');
72
- for(var i=0; i<e.length; i+=1) {
73
- var m;
74
- if(!e[i].color && e[i].className && (m = e[i].className.match(matchClass))) {
75
- var prop = {};
76
- if(m[3]) {
77
- try {
78
- eval('prop='+m[3]);
79
- } catch(eInvalidProp) {}
80
- }
81
- e[i].color = new jscolor.color(e[i], prop);
82
- }
83
- }
84
- },
85
-
86
-
87
- preload : function() {
88
- for(var fn in jscolor.imgRequire) {
89
- if(jscolor.imgRequire.hasOwnProperty(fn)) {
90
- jscolor.loadImage(fn);
91
- }
92
- }
93
- },
94
-
95
-
96
- images : {
97
- pad : [ 181, 101 ],
98
- sld : [ 16, 101 ],
99
- cross : [ 15, 15 ],
100
- arrow : [ 7, 11 ]
101
- },
102
-
103
-
104
- imgRequire : {},
105
- imgLoaded : {},
106
-
107
-
108
- requireImage : function(filename) {
109
- jscolor.imgRequire[filename] = true;
110
- },
111
-
112
-
113
- loadImage : function(filename) {
114
- if(!jscolor.imgLoaded[filename]) {
115
- jscolor.imgLoaded[filename] = new Image();
116
- jscolor.imgLoaded[filename].src = jscolor.getDir()+filename;
117
- }
118
- },
119
-
120
-
121
- fetchElement : function(mixed) {
122
- return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
123
- },
124
-
125
-
126
- addEvent : function(el, evnt, func) {
127
- if(el.addEventListener) {
128
- el.addEventListener(evnt, func, false);
129
- } else if(el.attachEvent) {
130
- el.attachEvent('on'+evnt, func);
131
- }
132
- },
133
-
134
-
135
- fireEvent : function(el, evnt) {
136
- if(!el) {
137
- return;
138
- }
139
- if(document.createEvent) {
140
- var ev = document.createEvent('HTMLEvents');
141
- ev.initEvent(evnt, true, true);
142
- el.dispatchEvent(ev);
143
- } else if(document.createEventObject) {
144
- var ev = document.createEventObject();
145
- el.fireEvent('on'+evnt, ev);
146
- } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5)
147
- el['on'+evnt]();
148
- }
149
- },
150
-
151
-
152
- getElementPos : function(e) {
153
- var e1=e, e2=e;
154
- var x=0, y=0;
155
- if(e1.offsetParent) {
156
- do {
157
- x += e1.offsetLeft;
158
- y += e1.offsetTop;
159
- } while(e1 = e1.offsetParent);
160
- }
161
- while((e2 = e2.parentNode) && e2.nodeName.toUpperCase() !== 'BODY') {
162
- x -= e2.scrollLeft;
163
- y -= e2.scrollTop;
164
- }
165
- return [x, y];
166
- },
167
-
168
-
169
- getElementSize : function(e) {
170
- return [e.offsetWidth, e.offsetHeight];
171
- },
172
-
173
-
174
- getRelMousePos : function(e) {
175
- var x = 0, y = 0;
176
- if (!e) { e = window.event; }
177
- if (typeof e.offsetX === 'number') {
178
- x = e.offsetX;
179
- y = e.offsetY;
180
- } else if (typeof e.layerX === 'number') {
181
- x = e.layerX;
182
- y = e.layerY;
183
- }
184
- return { x: x, y: y };
185
- },
186
-
187
-
188
- getViewPos : function() {
189
- if(typeof window.pageYOffset === 'number') {
190
- return [window.pageXOffset, window.pageYOffset];
191
- } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
192
- return [document.body.scrollLeft, document.body.scrollTop];
193
- } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
194
- return [document.documentElement.scrollLeft, document.documentElement.scrollTop];
195
- } else {
196
- return [0, 0];
197
- }
198
- },
199
-
200
-
201
- getViewSize : function() {
202
- if(typeof window.innerWidth === 'number') {
203
- return [window.innerWidth, window.innerHeight];
204
- } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
205
- return [document.body.clientWidth, document.body.clientHeight];
206
- } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
207
- return [document.documentElement.clientWidth, document.documentElement.clientHeight];
208
- } else {
209
- return [0, 0];
210
- }
211
- },
212
-
213
-
214
- URI : function(uri) { // See RFC3986
215
-
216
- this.scheme = null;
217
- this.authority = null;
218
- this.path = '';
219
- this.query = null;
220
- this.fragment = null;
221
-
222
- this.parse = function(uri) {
223
- var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/);
224
- this.scheme = m[3] ? m[2] : null;
225
- this.authority = m[5] ? m[6] : null;
226
- this.path = m[7];
227
- this.query = m[9] ? m[10] : null;
228
- this.fragment = m[12] ? m[13] : null;
229
- return this;
230
- };
231
-
232
- this.toString = function() {
233
- var result = '';
234
- if(this.scheme !== null) { result = result + this.scheme + ':'; }
235
- if(this.authority !== null) { result = result + '//' + this.authority; }
236
- if(this.path !== null) { result = result + this.path; }
237
- if(this.query !== null) { result = result + '?' + this.query; }
238
- if(this.fragment !== null) { result = result + '#' + this.fragment; }
239
- return result;
240
- };
241
-
242
- this.toAbsolute = function(base) {
243
- var base = new jscolor.URI(base);
244
- var r = this;
245
- var t = new jscolor.URI;
246
-
247
- if(base.scheme === null) { return false; }
248
-
249
- if(r.scheme !== null && r.scheme.toLowerCase() === base.scheme.toLowerCase()) {
250
- r.scheme = null;
251
- }
252
-
253
- if(r.scheme !== null) {
254
- t.scheme = r.scheme;
255
- t.authority = r.authority;
256
- t.path = removeDotSegments(r.path);
257
- t.query = r.query;
258
- } else {
259
- if(r.authority !== null) {
260
- t.authority = r.authority;
261
- t.path = removeDotSegments(r.path);
262
- t.query = r.query;
263
- } else {
264
- if(r.path === '') { // TODO: == or === ?
265
- t.path = base.path;
266
- if(r.query !== null) {
267
- t.query = r.query;
268
- } else {
269
- t.query = base.query;
270
- }
271
- } else {
272
- if(r.path.substr(0,1) === '/') {
273
- t.path = removeDotSegments(r.path);
274
- } else {
275
- if(base.authority !== null && base.path === '') { // TODO: == or === ?
276
- t.path = '/'+r.path;
277
- } else {
278
- t.path = base.path.replace(/[^\/]+$/,'')+r.path;
279
- }
280
- t.path = removeDotSegments(t.path);
281
- }
282
- t.query = r.query;
283
- }
284
- t.authority = base.authority;
285
- }
286
- t.scheme = base.scheme;
287
- }
288
- t.fragment = r.fragment;
289
-
290
- return t;
291
- };
292
-
293
- function removeDotSegments(path) {
294
- var out = '';
295
- while(path) {
296
- if(path.substr(0,3)==='../' || path.substr(0,2)==='./') {
297
- path = path.replace(/^\.+/,'').substr(1);
298
- } else if(path.substr(0,3)==='/./' || path==='/.') {
299
- path = '/'+path.substr(3);
300
- } else if(path.substr(0,4)==='/../' || path==='/..') {
301
- path = '/'+path.substr(4);
302
- out = out.replace(/\/?[^\/]*$/, '');
303
- } else if(path==='.' || path==='..') {
304
- path = '';
305
- } else {
306
- var rm = path.match(/^\/?[^\/]*/)[0];
307
- path = path.substr(rm.length);
308
- out = out + rm;
309
- }
310
- }
311
- return out;
312
- }
313
-
314
- if(uri) {
315
- this.parse(uri);
316
- }
317
-
318
- },
319
-
320
-
321
- /*
322
- * Usage example:
323
- * var myColor = new jscolor.color(myInputElement)
324
- */
325
-
326
- color : function(target, prop) {
327
-
328
-
329
- this.required = true; // refuse empty values?
330
- this.adjust = true; // adjust value to uniform notation?
331
- this.hash = false; // prefix color with # symbol?
332
- this.caps = true; // uppercase?
333
- this.slider = true; // show the value/saturation slider?
334
- this.valueElement = target; // value holder
335
- this.styleElement = target; // where to reflect current color
336
- this.onImmediateChange = null; // onchange callback (can be either string or function)
337
- this.hsv = [0, 0, 1]; // read-only 0-6, 0-1, 0-1
338
- this.rgb = [1, 1, 1]; // read-only 0-1, 0-1, 0-1
339
-
340
- this.pickerOnfocus = true; // display picker on focus?
341
- this.pickerMode = 'HSV'; // HSV | HVS
342
- this.pickerPosition = 'bottom'; // left | right | top | bottom
343
- this.pickerSmartPosition = true; // automatically adjust picker position when necessary
344
- this.pickerButtonHeight = 20; // px
345
- this.pickerClosable = false;
346
- this.pickerCloseText = 'Close';
347
- this.pickerButtonColor = 'ButtonText'; // px
348
- this.pickerFace = 10; // px
349
- this.pickerFaceColor = 'ThreeDFace'; // CSS color
350
- this.pickerBorder = 1; // px
351
- this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight'; // CSS color
352
- this.pickerInset = 1; // px
353
- this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow'; // CSS color
354
- this.pickerZIndex = 10000;
355
-
356
-
357
- for(var p in prop) {
358
- if(prop.hasOwnProperty(p)) {
359
- this[p] = prop[p];
360
- }
361
- }
362
-
363
-
364
- this.hidePicker = function() {
365
- if(isPickerOwner()) {
366
- removePicker();
367
- }
368
- };
369
-
370
-
371
- this.showPicker = function() {
372
- if(!isPickerOwner()) {
373
- var tp = jscolor.getElementPos(target); // target pos
374
- var ts = jscolor.getElementSize(target); // target size
375
- var vp = jscolor.getViewPos(); // view pos
376
- var vs = jscolor.getViewSize(); // view size
377
- var ps = getPickerDims(this); // picker size
378
- var a, b, c;
379
- switch(this.pickerPosition.toLowerCase()) {
380
- case 'left': a=1; b=0; c=-1; break;
381
- case 'right':a=1; b=0; c=1; break;
382
- case 'top': a=0; b=1; c=-1; break;
383
- default: a=0; b=1; c=1; break;
384
- }
385
- var l = (ts[b]+ps[b])/2;
386
-
387
- // picker pos
388
- if (!this.pickerSmartPosition) {
389
- var pp = [
390
- tp[a],
391
- tp[b]+ts[b]-l+l*c
392
- ];
393
- } else {
394
- var pp = [
395
- -vp[a]+tp[a]+ps[a] > vs[a] ?
396
- (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
397
- tp[a],
398
- -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
399
- (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
400
- (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
401
- ];
402
- }
403
- drawPicker(pp[a], pp[b]);
404
- }
405
- };
406
-
407
-
408
- this.importColor = function() {
409
- if(!valueElement) {
410
- this.exportColor();
411
- } else {
412
- if(!this.adjust) {
413
- if(!this.fromString(valueElement.value, leaveValue)) {
414
- styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
415
- styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
416
- styleElement.style.color = styleElement.jscStyle.color;
417
- this.exportColor(leaveValue | leaveStyle);
418
- }
419
- } else if(!this.required && /^\s*$/.test(valueElement.value)) {
420
- valueElement.value = '';
421
- styleElement.style.backgroundImage = styleElement.jscStyle.backgroundImage;
422
- styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
423
- styleElement.style.color = styleElement.jscStyle.color;
424
- this.exportColor(leaveValue | leaveStyle);
425
-
426
- } else if(this.fromString(valueElement.value)) {
427
- // OK
428
- } else {
429
- this.exportColor();
430
- }
431
- }
432
- };
433
-
434
-
435
- this.exportColor = function(flags) {
436
- if(!(flags & leaveValue) && valueElement) {
437
- var value = this.toString();
438
- if(this.caps) { value = value.toUpperCase(); }
439
- if(this.hash) { value = '#'+value; }
440
- valueElement.value = value;
441
- }
442
- if(!(flags & leaveStyle) && styleElement) {
443
- styleElement.style.backgroundImage = "none";
444
- styleElement.style.backgroundColor =
445
- '#'+this.toString();
446
- styleElement.style.color =
447
- 0.213 * this.rgb[0] +
448
- 0.715 * this.rgb[1] +
449
- 0.072 * this.rgb[2]
450
- < 0.5 ? '#FFF' : '#000';
451
- }
452
- if(!(flags & leavePad) && isPickerOwner()) {
453
- redrawPad();
454
- }
455
- if(!(flags & leaveSld) && isPickerOwner()) {
456
- redrawSld();
457
- }
458
- };
459
-
460
-
461
- this.fromHSV = function(h, s, v, flags) { // null = don't change
462
- h<0 && (h=0) || h>6 && (h=6);
463
- s<0 && (s=0) || s>1 && (s=1);
464
- v<0 && (v=0) || v>1 && (v=1);
465
- this.rgb = HSV_RGB(
466
- h===null ? this.hsv[0] : (this.hsv[0]=h),
467
- s===null ? this.hsv[1] : (this.hsv[1]=s),
468
- v===null ? this.hsv[2] : (this.hsv[2]=v)
469
- );
470
- this.exportColor(flags);
471
- };
472
-
473
-
474
- this.fromRGB = function(r, g, b, flags) { // null = don't change
475
- r<0 && (r=0) || r>1 && (r=1);
476
- g<0 && (g=0) || g>1 && (g=1);
477
- b<0 && (b=0) || b>1 && (b=1);
478
- var hsv = RGB_HSV(
479
- r===null ? this.rgb[0] : (this.rgb[0]=r),
480
- g===null ? this.rgb[1] : (this.rgb[1]=g),
481
- b===null ? this.rgb[2] : (this.rgb[2]=b)
482
- );
483
- if(hsv[0] !== null) {
484
- this.hsv[0] = hsv[0];
485
- }
486
- if(hsv[2] !== 0) {
487
- this.hsv[1] = hsv[1];
488
- }
489
- this.hsv[2] = hsv[2];
490
- this.exportColor(flags);
491
- };
492
-
493
-
494
- this.fromString = function(hex, flags) {
495
- var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
496
- if(!m) {
497
- return false;
498
- } else {
499
- if(m[1].length === 6) { // 6-char notation
500
- this.fromRGB(
501
- parseInt(m[1].substr(0,2),16) / 255,
502
- parseInt(m[1].substr(2,2),16) / 255,
503
- parseInt(m[1].substr(4,2),16) / 255,
504
- flags
505
- );
506
- } else { // 3-char notation
507
- this.fromRGB(
508
- parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255,
509
- parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255,
510
- parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255,
511
- flags
512
- );
513
- }
514
- return true;
515
- }
516
- };
517
-
518
-
519
- this.toString = function() {
520
- return (
521
- (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) +
522
- (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) +
523
- (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1)
524
- );
525
- };
526
-
527
-
528
- function RGB_HSV(r, g, b) {
529
- var n = Math.min(Math.min(r,g),b);
530
- var v = Math.max(Math.max(r,g),b);
531
- var m = v - n;
532
- if(m === 0) { return [ null, 0, v ]; }
533
- var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
534
- return [ h===6?0:h, m/v, v ];
535
- }
536
-
537
-
538
- function HSV_RGB(h, s, v) {
539
- if(h === null) { return [ v, v, v ]; }
540
- var i = Math.floor(h);
541
- var f = i%2 ? h-i : 1-(h-i);
542
- var m = v * (1 - s);
543
- var n = v * (1 - s*f);
544
- switch(i) {
545
- case 6:
546
- case 0: return [v,n,m];
547
- case 1: return [n,v,m];
548
- case 2: return [m,v,n];
549
- case 3: return [m,n,v];
550
- case 4: return [n,m,v];
551
- case 5: return [v,m,n];
552
- }
553
- }
554
-
555
-
556
- function removePicker() {
557
- delete jscolor.picker.owner;
558
- document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB);
559
- }
560
-
561
-
562
- function drawPicker(x, y) {
563
- if(!jscolor.picker) {
564
- jscolor.picker = {
565
- box : document.createElement('div'),
566
- boxB : document.createElement('div'),
567
- pad : document.createElement('div'),
568
- padB : document.createElement('div'),
569
- padM : document.createElement('div'),
570
- sld : document.createElement('div'),
571
- sldB : document.createElement('div'),
572
- sldM : document.createElement('div'),
573
- btn : document.createElement('div'),
574
- btnS : document.createElement('span'),
575
- btnT : document.createTextNode(THIS.pickerCloseText)
576
- };
577
- for(var i=0,segSize=4; i<jscolor.images.sld[1]; i+=segSize) {
578
- var seg = document.createElement('div');
579
- seg.style.height = segSize+'px';
580
- seg.style.fontSize = '1px';
581
- seg.style.lineHeight = '0';
582
- jscolor.picker.sld.appendChild(seg);
583
- }
584
- jscolor.picker.sldB.appendChild(jscolor.picker.sld);
585
- jscolor.picker.box.appendChild(jscolor.picker.sldB);
586
- jscolor.picker.box.appendChild(jscolor.picker.sldM);
587
- jscolor.picker.padB.appendChild(jscolor.picker.pad);
588
- jscolor.picker.box.appendChild(jscolor.picker.padB);
589
- jscolor.picker.box.appendChild(jscolor.picker.padM);
590
- jscolor.picker.btnS.appendChild(jscolor.picker.btnT);
591
- jscolor.picker.btn.appendChild(jscolor.picker.btnS);
592
- jscolor.picker.box.appendChild(jscolor.picker.btn);
593
- jscolor.picker.boxB.appendChild(jscolor.picker.box);
594
- }
595
-
596
- var p = jscolor.picker;
597
-
598
- // controls interaction
599
- p.box.onmouseup =
600
- p.box.onmouseout = function() { target.focus(); };
601
- p.box.onmousedown = function() { abortBlur=true; };
602
- p.box.onmousemove = function(e) {
603
- if (holdPad || holdSld) {
604
- holdPad && setPad(e);
605
- holdSld && setSld(e);
606
- if (document.selection) {
607
- document.selection.empty();
608
- } else if (window.getSelection) {
609
- window.getSelection().removeAllRanges();
610
- }
611
- dispatchImmediateChange();
612
- }
613
- };
614
- p.padM.onmouseup =
615
- p.padM.onmouseout = function() { if(holdPad) { holdPad=false; jscolor.fireEvent(valueElement,'change'); } };
616
- p.padM.onmousedown = function(e) {
617
- // if the slider is at the bottom, move it up
618
- switch(modeID) {
619
- case 0: if (THIS.hsv[2] === 0) { THIS.fromHSV(null, null, 1.0); }; break;
620
- case 1: if (THIS.hsv[1] === 0) { THIS.fromHSV(null, 1.0, null); }; break;
621
- }
622
- holdPad=true;
623
- setPad(e);
624
- dispatchImmediateChange();
625
- };
626
- p.sldM.onmouseup =
627
- p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change'); } };
628
- p.sldM.onmousedown = function(e) {
629
- holdSld=true;
630
- setSld(e);
631
- dispatchImmediateChange();
632
- };
633
-
634
- // picker
635
- var dims = getPickerDims(THIS);
636
- p.box.style.width = dims[0] + 'px';
637
- p.box.style.height = dims[1] + 'px';
638
-
639
- // picker border
640
- p.boxB.style.position = 'absolute';
641
- p.boxB.style.clear = 'both';
642
- p.boxB.style.left = x+'px';
643
- p.boxB.style.top = y+'px';
644
- p.boxB.style.zIndex = THIS.pickerZIndex;
645
- p.boxB.style.border = THIS.pickerBorder+'px solid';
646
- p.boxB.style.borderColor = THIS.pickerBorderColor;
647
- p.boxB.style.background = THIS.pickerFaceColor;
648
-
649
- // pad image
650
- p.pad.style.width = jscolor.images.pad[0]+'px';
651
- p.pad.style.height = jscolor.images.pad[1]+'px';
652
-
653
- // pad border
654
- p.padB.style.position = 'absolute';
655
- p.padB.style.left = THIS.pickerFace+'px';
656
- p.padB.style.top = THIS.pickerFace+'px';
657
- p.padB.style.border = THIS.pickerInset+'px solid';
658
- p.padB.style.borderColor = THIS.pickerInsetColor;
659
-
660
- // pad mouse area
661
- p.padM.style.position = 'absolute';
662
- p.padM.style.left = '0';
663
- p.padM.style.top = '0';
664
- p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px';
665
- p.padM.style.height = p.box.style.height;
666
- p.padM.style.cursor = 'crosshair';
667
-
668
- // slider image
669
- p.sld.style.overflow = 'hidden';
670
- p.sld.style.width = jscolor.images.sld[0]+'px';
671
- p.sld.style.height = jscolor.images.sld[1]+'px';
672
-
673
- // slider border
674
- p.sldB.style.display = THIS.slider ? 'block' : 'none';
675
- p.sldB.style.position = 'absolute';
676
- p.sldB.style.right = THIS.pickerFace+'px';
677
- p.sldB.style.top = THIS.pickerFace+'px';
678
- p.sldB.style.border = THIS.pickerInset+'px solid';
679
- p.sldB.style.borderColor = THIS.pickerInsetColor;
680
-
681
- // slider mouse area
682
- p.sldM.style.display = THIS.slider ? 'block' : 'none';
683
- p.sldM.style.position = 'absolute';
684
- p.sldM.style.right = '0';
685
- p.sldM.style.top = '0';
686
- p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px';
687
- p.sldM.style.height = p.box.style.height;
688
- try {
689
- p.sldM.style.cursor = 'pointer';
690
- } catch(eOldIE) {
691
- p.sldM.style.cursor = 'hand';
692
- }
693
-
694
- // "close" button
695
- function setBtnBorder() {
696
- var insetColors = THIS.pickerInsetColor.split(/\s+/);
697
- var pickerOutsetColor = insetColors.length < 2 ? insetColors[0] : insetColors[1] + ' ' + insetColors[0] + ' ' + insetColors[0] + ' ' + insetColors[1];
698
- p.btn.style.borderColor = pickerOutsetColor;
699
- }
700
- p.btn.style.display = THIS.pickerClosable ? 'block' : 'none';
701
- p.btn.style.position = 'absolute';
702
- p.btn.style.left = THIS.pickerFace + 'px';
703
- p.btn.style.bottom = THIS.pickerFace + 'px';
704
- p.btn.style.padding = '0 15px';
705
- p.btn.style.height = '18px';
706
- p.btn.style.border = THIS.pickerInset + 'px solid';
707
- setBtnBorder();
708
- p.btn.style.color = THIS.pickerButtonColor;
709
- p.btn.style.font = '12px sans-serif';
710
- p.btn.style.textAlign = 'center';
711
- try {
712
- p.btn.style.cursor = 'pointer';
713
- } catch(eOldIE) {
714
- p.btn.style.cursor = 'hand';
715
- }
716
- p.btn.onmousedown = function () {
717
- THIS.hidePicker();
718
- };
719
- p.btnS.style.lineHeight = p.btn.style.height;
720
-
721
- // load images in optimal order
722
- switch(modeID) {
723
- case 0: var padImg = 'hs.png'; break;
724
- case 1: var padImg = 'hv.png'; break;
725
- }
726
- p.padM.style.backgroundImage = "url('"+jscolor.getDir()+"cross.gif')";
727
- p.padM.style.backgroundRepeat = "no-repeat";
728
- p.sldM.style.backgroundImage = "url('"+jscolor.getDir()+"arrow.gif')";
729
- p.sldM.style.backgroundRepeat = "no-repeat";
730
- p.pad.style.backgroundImage = "url('"+jscolor.getDir()+padImg+"')";
731
- p.pad.style.backgroundRepeat = "no-repeat";
732
- p.pad.style.backgroundPosition = "0 0";
733
-
734
- // place pointers
735
- redrawPad();
736
- redrawSld();
737
-
738
- jscolor.picker.owner = THIS;
739
- document.getElementsByTagName('body')[0].appendChild(p.boxB);
740
- }
741
-
742
-
743
- function getPickerDims(o) {
744
- var dims = [
745
- 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[0] +
746
- (o.slider ? 2*o.pickerInset + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] : 0),
747
- o.pickerClosable ?
748
- 4*o.pickerInset + 3*o.pickerFace + jscolor.images.pad[1] + o.pickerButtonHeight :
749
- 2*o.pickerInset + 2*o.pickerFace + jscolor.images.pad[1]
750
- ];
751
- return dims;
752
- }
753
-
754
-
755
- function redrawPad() {
756
- // redraw the pad pointer
757
- switch(modeID) {
758
- case 0: var yComponent = 1; break;
759
- case 1: var yComponent = 2; break;
760
- }
761
- var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1));
762
- var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1));
763
- jscolor.picker.padM.style.backgroundPosition =
764
- (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' +
765
- (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px';
766
-
767
- // redraw the slider image
768
- var seg = jscolor.picker.sld.childNodes;
769
-
770
- switch(modeID) {
771
- case 0:
772
- var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1);
773
- for(var i=0; i<seg.length; i+=1) {
774
- seg[i].style.backgroundColor = 'rgb('+
775
- (rgb[0]*(1-i/seg.length)*100)+'%,'+
776
- (rgb[1]*(1-i/seg.length)*100)+'%,'+
777
- (rgb[2]*(1-i/seg.length)*100)+'%)';
778
- }
779
- break;
780
- case 1:
781
- var rgb, s, c = [ THIS.hsv[2], 0, 0 ];
782
- var i = Math.floor(THIS.hsv[0]);
783
- var f = i%2 ? THIS.hsv[0]-i : 1-(THIS.hsv[0]-i);
784
- switch(i) {
785
- case 6:
786
- case 0: rgb=[0,1,2]; break;
787
- case 1: rgb=[1,0,2]; break;
788
- case 2: rgb=[2,0,1]; break;
789
- case 3: rgb=[2,1,0]; break;
790
- case 4: rgb=[1,2,0]; break;
791
- case 5: rgb=[0,2,1]; break;
792
- }
793
- for(var i=0; i<seg.length; i+=1) {
794
- s = 1 - 1/(seg.length-1)*i;
795
- c[1] = c[0] * (1 - s*f);
796
- c[2] = c[0] * (1 - s);
797
- seg[i].style.backgroundColor = 'rgb('+
798
- (c[rgb[0]]*100)+'%,'+
799
- (c[rgb[1]]*100)+'%,'+
800
- (c[rgb[2]]*100)+'%)';
801
- }
802
- break;
803
- }
804
- }
805
-
806
-
807
- function redrawSld() {
808
- // redraw the slider pointer
809
- switch(modeID) {
810
- case 0: var yComponent = 2; break;
811
- case 1: var yComponent = 1; break;
812
- }
813
- var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.sld[1]-1));
814
- jscolor.picker.sldM.style.backgroundPosition =
815
- '0 ' + (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.arrow[1]/2)) + 'px';
816
- }
817
-
818
-
819
- function isPickerOwner() {
820
- return jscolor.picker && jscolor.picker.owner === THIS;
821
- }
822
-
823
-
824
- function blurTarget() {
825
- if(valueElement === target) {
826
- THIS.importColor();
827
- }
828
- if(THIS.pickerOnfocus) {
829
- THIS.hidePicker();
830
- }
831
- }
832
-
833
-
834
- function blurValue() {
835
- if(valueElement !== target) {
836
- THIS.importColor();
837
- }
838
- }
839
-
840
-
841
- function setPad(e) {
842
- var mpos = jscolor.getRelMousePos(e);
843
- var x = mpos.x - THIS.pickerFace - THIS.pickerInset;
844
- var y = mpos.y - THIS.pickerFace - THIS.pickerInset;
845
- switch(modeID) {
846
- case 0: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), 1 - y/(jscolor.images.pad[1]-1), null, leaveSld); break;
847
- case 1: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), null, 1 - y/(jscolor.images.pad[1]-1), leaveSld); break;
848
- }
849
- }
850
-
851
-
852
- function setSld(e) {
853
- var mpos = jscolor.getRelMousePos(e);
854
- var y = mpos.y - THIS.pickerFace - THIS.pickerInset;
855
- switch(modeID) {
856
- case 0: THIS.fromHSV(null, null, 1 - y/(jscolor.images.sld[1]-1), leavePad); break;
857
- case 1: THIS.fromHSV(null, 1 - y/(jscolor.images.sld[1]-1), null, leavePad); break;
858
- }
859
- }
860
-
861
-
862
- function dispatchImmediateChange() {
863
- if (THIS.onImmediateChange) {
864
- if (typeof THIS.onImmediateChange === 'string') {
865
- eval(THIS.onImmediateChange);
866
- } else {
867
- THIS.onImmediateChange(THIS);
868
- }
869
- }
870
- }
871
-
872
-
873
- var THIS = this;
874
- var modeID = this.pickerMode.toLowerCase()==='hvs' ? 1 : 0;
875
- var abortBlur = false;
876
- var
877
- valueElement = jscolor.fetchElement(this.valueElement),
878
- styleElement = jscolor.fetchElement(this.styleElement);
879
- var
880
- holdPad = false,
881
- holdSld = false;
882
- var
883
- leaveValue = 1<<0,
884
- leaveStyle = 1<<1,
885
- leavePad = 1<<2,
886
- leaveSld = 1<<3;
887
-
888
- // target
889
- jscolor.addEvent(target, 'focus', function() {
890
- if(THIS.pickerOnfocus) { THIS.showPicker(); }
891
- });
892
- jscolor.addEvent(target, 'blur', function() {
893
- if(!abortBlur) {
894
- window.setTimeout(function(){ abortBlur || blurTarget(); abortBlur=false; }, 0);
895
- } else {
896
- abortBlur = false;
897
- }
898
- });
899
-
900
- // valueElement
901
- if(valueElement) {
902
- var updateField = function() {
903
- THIS.fromString(valueElement.value, leaveValue);
904
- dispatchImmediateChange();
905
- };
906
- jscolor.addEvent(valueElement, 'keyup', updateField);
907
- jscolor.addEvent(valueElement, 'input', updateField);
908
- jscolor.addEvent(valueElement, 'blur', blurValue);
909
- valueElement.setAttribute('autocomplete', 'off');
910
- }
911
-
912
- // styleElement
913
- if(styleElement) {
914
- styleElement.jscStyle = {
915
- backgroundImage : styleElement.style.backgroundImage,
916
- backgroundColor : styleElement.style.backgroundColor,
917
- color : styleElement.style.color
918
- };
919
- }
920
-
921
- // require images
922
- switch(modeID) {
923
- case 0: jscolor.requireImage('hs.png'); break;
924
- case 1: jscolor.requireImage('hv.png'); break;
925
- }
926
- jscolor.requireImage('cross.gif');
927
- jscolor.requireImage('arrow.gif');
928
-
929
- this.importColor();
930
- }
931
-
932
- };
933
-
934
-
935
- jscolor.install();
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
js/pricewaiter/product-pages.js CHANGED
@@ -1,298 +1,274 @@
 
 
1
  /*
2
- * Copyright 2013 Price Waiter, LLC
3
- *
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
  * you may not use this file except in compliance with the License.
6
  * You may obtain a copy of the License at
7
- *
8
  * http://www.apache.org/licenses/LICENSE-2.0
9
- *
10
  * Unless required by applicable law or agreed to in writing, software
11
  * distributed under the License is distributed on an "AS IS" BASIS,
12
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13
  * See the License for the specific language governing permissions and
14
  * limitations under the License.
15
- *
16
  */
17
- $(document).observe('dom:loaded', function() {
18
- if (typeof adminPW == 'function') {
19
- adminPW();
20
- }
21
- if (typeof PriceWaiterOptions == 'object') {
22
- PriceWaiterOptions.onload =
23
- function(PriceWaiter) {
24
- PriceWaiter.setRegularPrice(PriceWaiterRegularPrice);
25
-
26
- // define indexof, needed for older versions of IE
27
- if(!Array.prototype.indexof) {
28
- Array.prototype.indexof = function(needle) {
29
- for(var i = 0; i < this.length; i++) {
30
- if(this[i] === needle) {
31
- return i;
32
- }
33
- }
34
- return -1;
35
- };
36
- }
37
-
38
- // define getElementsByRegex to find required bundle options
39
- document['getElementsByRegex'] = function(pattern) {
40
- var arrElements = []; // to accumulate matching elements
41
- var re = new RegExp(pattern); // the regex to match with
42
-
43
- function findRecursively(aNode) { // recursive function to traverse dom
44
- if (!aNode)
45
- return;
46
- if (aNode.id !== undefined && aNode.id.search(re) != -1)
47
- arrElements.push(aNode); // found one!
48
- for (var idx in aNode.childNodes) // search children...
49
- findRecursively(aNode.childNodes[idx]);
50
- }
51
-
52
- findRecursively(document); // initiate recursive matching
53
- return arrElements; // return matching elements
54
- };
55
-
56
- // Bind to Qty: input
57
- if ($('qty') !== null) {
58
- $('qty').observe('change', function(){
59
- PriceWaiter.setQuantity($('qty').value);
60
- });
61
- }
62
-
63
- switch(PriceWaiterProductType) {
64
- case 'simple':
65
- handleSimples();
66
- break;
67
- case 'configurable':
68
- handleConfigurables();
69
- break;
70
- case 'bundle':
71
- handleBundles();
72
- break;
73
- case 'grouped':
74
- handleGrouped();
75
- break;
76
- }
77
-
78
- function simplesSelect(select, name) {
79
- select.observe('change', function(){
80
- PriceWaiter.setProductOption(name, select.options[select.selectedIndex].text);
81
- });
82
- }
83
-
84
- function simplesInput(select, name) {
85
- if (select.type == "text" || select.tagName == 'TEXTAREA') {
86
- select.observe('change', function(){
87
- PriceWaiter.setProductOption(name, select.value);
88
- });
89
- } else {
90
- select.observe('change', function(){
91
- var optionValue = select.next('span').select('label')[0].innerHTML;
92
- optionValue = optionValue.replace(/\s*<span.*\/span>/, '');
93
- PriceWaiter.setProductOption(name, optionValue);
94
- });
95
- }
96
- }
97
-
98
-
99
- function handleSimples() {
100
- // if there are no custom options, we don't have anything to do
101
- if (typeof(opConfig) == 'undefined') {
102
- return;
103
- }
104
-
105
- // If this product has an upload file option, we can't use the NYP widget
106
- var productForm = $('product_addtocart_form');
107
- if (productForm.getInputs('file').length !== 0) {
108
- console.log("The PriceWaiter Name Your Price Widget does not support upload file options.");
109
- $$('div.name-your-price-widget').each(function(pww){
110
- pww.setStyle({display: 'none'});
111
- });
112
- }
113
-
114
- // Grab the updated price before opening the PriceWaiter window
115
- PriceWaiter.originalOpen = PriceWaiter.open;
116
- PriceWaiter.open = function() {
117
- var productPrice = 0;
118
- var priceElement = document.getElementsByRegex('^product-price-');
119
- var innerSpan = priceElement[0].select('span');
120
- if (typeof(innerSpan[0]) == 'undefined') {
121
- productPrice = priceElement[0].innerHTML;
122
- } else {
123
- productPrice = innerSpan[0].innerHTML;
124
- }
125
- PriceWaiter.setPrice(productPrice);
126
- PriceWaiter.originalOpen();
127
- };
128
-
129
- // Find the available options, and bind to them
130
- var productCustomOptions = $$('.product-custom-option');
131
- for (var current in productCustomOptions) {
132
- if (!isNaN(parseInt(current, 10))) {
133
- // Find the option label
134
- var optionLabel = productCustomOptions[current].up('dd').previous('dt').select('label')[0];
135
- var optionName = optionLabel.innerHTML.replace(/^<em.*\/em>/, '');
136
- // Check if this is a required option
137
- if (optionLabel.hasClassName('required')) {
138
- PriceWaiter.setProductOptionRequired(optionName);
139
- }
140
- // we have to handle different inputs a bit differently.
141
- switch (productCustomOptions[current].tagName) {
142
- case 'SELECT':
143
- simplesSelect(productCustomOptions[current], optionName);
144
- break;
145
- case 'INPUT':
146
- case 'TEXTAREA':
147
- simplesInput(productCustomOptions[current], optionName);
148
- break;
149
- }
150
- }
151
- }
152
- }
153
-
154
- function handleConfigurables() {
155
- // Bind to each configurable options 'change' event
156
- spConfig.settings.each(function(setting){
157
- var attributeId = $(setting).id;
158
- attributeId = attributeId.replace(/attribute/,'');
159
- var optionName = spConfig.config.attributes[attributeId].label;
160
- // If this option is required, tell the PriceWaiter widget about the requirement
161
- if ($(setting).hasClassName('required-entry') && (typeof PriceWaiter.setProductOptionRequired == 'function')) {
162
- PriceWaiter.setProductOptionRequired(optionName, true);
163
- }
164
- Event.observe(setting, 'change', function(event){
165
- // Update PriceWaiter's price and options when changes are made
166
- PriceWaiter.setPrice(Number(spConfig.config.basePrice) + Number(spConfig.reloadPrice()));
167
- var optionValue = setting.value !== "" ? setting.options[setting.selectedIndex].innerHTML : undefined;
168
- // if the option value is undefined, clear the option. Otherwise, set the newly selected option.
169
- if (optionValue === undefined) {
170
- PriceWaiter.clearProductOption(optionName);
171
- } else {
172
- PriceWaiter.setProductOption(optionName, optionValue);
173
- }
174
- });
175
- });
176
- }
177
-
178
- function handleBundles() {
179
- // Find options that are marked as required
180
- var requiredOptions = [];
181
- var bundleElements = document.getElementsByRegex('^bundle-option-');
182
- var rePattern = /\[(\d*)\]/;
183
- for (var bundleOption in bundleElements) {
184
- if (!isNaN(parseInt(bundleOption, 10))) {
185
- var obj = bundleElements[bundleOption];
186
- if (obj.hasClassName('required-entry') || obj.hasClassName('validate-one-required-by-name')) {
187
- var matched = rePattern.exec(obj.name);
188
- requiredOptions.push(parseInt(matched[1], 10));
189
- }
190
- }
191
- }
192
- requiredOptions = requiredOptions.uniq();
193
-
194
- // Add required Options to PriceWaiter
195
- for (var key in bundle.config.options) {
196
- if (requiredOptions.indexOf(parseInt(key, 10)) > -1) {
197
- var opt = bundle.config.options[key];
198
- PriceWaiter.setProductOptionRequired(opt.title, true);
199
- }
200
- }
201
-
202
- // Bind to event fired when price is changed on bundle
203
- document.observe("bundle:reload-price", function(event) {
204
- PriceWaiter.setPrice(event.memo.priceInclTax);
205
- var bSelected = event.memo.bundle.config.selected;
206
- var bOptions = event.memo.bundle.config.options;
207
- for (var current in bSelected) {
208
- // Find which value is selected
209
- var currentSelected = bSelected[current];
210
- if (currentSelected.length === 0) {
211
- // If none, unset the Product option
212
- PriceWaiter.clearProductOption(bOptions[current].title);
213
- } else {
214
- // Otherwise, find the quantity of the selection
215
- var qty = bOptions[current].selections[currentSelected].qty;
216
- // Now find the value of the selected option, and set priceInclTax
217
- var selectedValue = bOptions[current].selections[currentSelected].name;
218
- if (qty > 1) {
219
- selectedValue += " - Quantity: " + qty;
220
- }
221
- PriceWaiter.setProductOption(bOptions[current].title, selectedValue);
222
- }
223
- }
224
- });
225
-
226
- // Reload the bundle's price, to pull the initial options into PriceWaiter
227
- if (typeof(bundle) != 'undefined') {
228
- bundle.reloadPrice();
229
- }
230
- }
231
-
232
- function handleGrouped() {
233
- // Get the Grouped product table rows
234
- var productTable = $$('table.grouped-items-table')[0];
235
- var productRows = productTable.select('tbody')[0];
236
- productRows = productRows.childElements();
237
- // Prevent users from attempting to name a price on grouped products without
238
- // setting any quantities
239
- if (productRows.length > 0) {
240
- PriceWaiter.setProductOptionRequired('Quantity of Products', true);
241
- }
242
-
243
- for (var row in productRows) {
244
- if (!isNaN(parseInt(row, 10))) {
245
- // Bind to the Quantity change
246
- productRows[row].select('input.qty')[0].observe('change', function(event){
247
- var qty = this.value;
248
- // Find the name and price based on the input's product ID
249
- // The product ID is found in the input's name inside the square brackets
250
- var pattern = /\[(.*)\]/;
251
- var inputName = this.name;
252
- var productID = pattern.exec(inputName);
253
- productID = productID[1];
254
-
255
- var productName = window.PriceWaiterGroupedProductInfo[productID][0];
256
- var productPrice = window.PriceWaiterGroupedProductInfo[productID][1];
257
-
258
- // The user changed the quantity field. We need to find the previous quantity and price
259
- var previousQuantity = PriceWaiter.getProductOptions()[productName + " (" + productPrice + ")"];
260
- var amountToRemove = Number(previousQuantity * productPrice);
261
- if (qty > 0) {
262
- // Entered a quantity, set product name as option name, add quantity as value
263
- PriceWaiter.setProductOption(productName + " (" + productPrice + ")", qty);
264
- // Add the price to the product's total
265
- PriceWaiter.setPrice(Number(PriceWaiter.getPrice()) + Number(productPrice * qty));
266
- } else {
267
- PriceWaiter.clearProductOption(productName + " (" + productPrice + ")");
268
- }
269
- // If they previously had a quantity for this option, remove it from the total
270
- if (previousQuantity > 0) {
271
- PriceWaiter.setPrice(Number(PriceWaiter.getPrice() - amountToRemove));
272
- }
273
- // Test if any Product Options are set. If they are, we can disable
274
- // our required option. Otherwise, ensure it is in place.
275
- if (Object.keys(PriceWaiter.getProductOptions()).length > 0) {
276
- PriceWaiter.clearRequiredProductOptions();
277
- } else {
278
- PriceWaiter.setProductOptionRequired('Quantity of Products', true);
279
- }
280
- });
281
- }
282
- }
283
- }
284
- };
285
- }
286
 
287
- if (window.PriceWaiterWidgetUrl) {
288
- (function() {
289
- var pw = document.createElement('script');
290
- pw.type = 'text/javascript';
291
- pw.src = window.PriceWaiterWidgetUrl;
292
- pw.async = true;
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
293
 
294
- var s = document.getElementsByTagName('script')[0];
295
- s.parentNode.insertBefore(pw, s);
296
- })();
297
- }
298
- });
1
+ // Generated by CoffeeScript 1.9.1
2
+
3
  /*
4
+ * Copyright 2013-2015 Price Waiter, LLC
5
+ #
6
  * Licensed under the Apache License, Version 2.0 (the "License");
7
  * you may not use this file except in compliance with the License.
8
  * You may obtain a copy of the License at
9
+ #
10
  * http://www.apache.org/licenses/LICENSE-2.0
11
+ #
12
  * Unless required by applicable law or agreed to in writing, software
13
  * distributed under the License is distributed on an "AS IS" BASIS,
14
  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15
  * See the License for the specific language governing permissions and
16
  * limitations under the License.
17
+ #
18
  */
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
 
20
+ (function() {
21
+ $(document).observe('dom:loaded', function() {
22
+ var getSimpleProductSku;
23
+ if (typeof PriceWaiterOptions === 'object') {
24
+ getSimpleProductSku = function() {
25
+ if (PriceWaiterProductType === 'configurable') {
26
+ spConfig.settings.each(function(setting) {
27
+ var options, productId, settingId;
28
+ settingId = setting.id.replace('attribute', '');
29
+ options = spConfig.config.attributes[settingId].options;
30
+ productId = options.find(function(option) {
31
+ return option.id === setting.value;
32
+ }).allowedProducts[0];
33
+ return PriceWaiter.setSKU(PriceWaiterIdToSkus[productId]);
34
+ });
35
+ }
36
+ return PriceWaiter.getSKU();
37
+ };
38
+ PriceWaiterOptions.onButtonClick = function(PriceWaiter, platformOnButtonClick) {
39
+ var productConfiguration, productForm;
40
+ productForm = $('product_addtocart_form');
41
+ productConfiguration = productForm.serialize();
42
+ PriceWaiter.setMetadata('_magento_product_configuration', encodeURIComponent(productConfiguration));
43
+ PriceWaiter.setSKU(getSimpleProductSku());
44
+ return true;
45
+ };
46
+ PriceWaiterOptions.onload = function(PriceWaiter) {
47
+ var handleBundles, handleConfigurables, handleGrouped, handleSimples, simplesInput, simplesSelect;
48
+ simplesSelect = function(select, name) {
49
+ select.observe('change', function() {
50
+ PriceWaiter.setProductOption(name, select.options[select.selectedIndex].text);
51
+ });
52
+ };
53
+ simplesInput = function(select, name) {
54
+ if (select.type === 'text' || select.tagName === 'TEXTAREA') {
55
+ select.observe('change', function() {
56
+ PriceWaiter.setProductOption(name, select.value);
57
+ });
58
+ } else {
59
+ select.observe('change', function() {
60
+ var optionValue;
61
+ optionValue = select.next('span').select('label')[0].innerHTML;
62
+ optionValue = optionValue.replace(/\s*<span.*\/span>/, '');
63
+ PriceWaiter.setProductOption(name, optionValue);
64
+ });
65
+ }
66
+ };
67
+ handleSimples = function() {
68
+ var current, optionLabel, optionName, productCustomOptions, productForm;
69
+ if (typeof opConfig === 'undefined') {
70
+ return;
71
+ }
72
+ productForm = $('product_addtocart_form');
73
+ if (productForm.getInputs('file').length !== 0) {
74
+ console.log('The PriceWaiter Name Your Price Widget does not support upload file options.');
75
+ $$('div.name-your-price-widget').each(function(pww) {
76
+ pww.setStyle({
77
+ display: 'none'
78
+ });
79
+ });
80
+ }
81
+ PriceWaiter.originalOpen = PriceWaiter.open;
82
+ PriceWaiter.open = function() {
83
+ var innerSpan, priceElement, productPrice;
84
+ productPrice = 0;
85
+ priceElement = document.getElementsByRegex('^product-price-');
86
+ innerSpan = priceElement[0].select('span');
87
+ if (typeof innerSpan[0] === 'undefined') {
88
+ productPrice = priceElement[0].innerHTML;
89
+ } else {
90
+ productPrice = innerSpan[0].innerHTML;
91
+ }
92
+ PriceWaiter.setPrice(productPrice);
93
+ PriceWaiter.originalOpen();
94
+ };
95
+ productCustomOptions = $$('.product-custom-option');
96
+ for (current in productCustomOptions) {
97
+ if (!isNaN(parseInt(current, 10))) {
98
+ optionLabel = productCustomOptions[current].up('dd').previous('dt').select('label')[0];
99
+ optionName = optionLabel.innerHTML.replace(/^<em.*\/em>/, '');
100
+ if (optionLabel.hasClassName('required')) {
101
+ PriceWaiter.setProductOptionRequired(optionName);
102
+ }
103
+ switch (productCustomOptions[current].tagName) {
104
+ case 'SELECT':
105
+ simplesSelect(productCustomOptions[current], optionName);
106
+ break;
107
+ case 'INPUT':
108
+ case 'TEXTAREA':
109
+ simplesInput(productCustomOptions[current], optionName);
110
+ }
111
+ }
112
+ }
113
+ };
114
+ handleConfigurables = function() {
115
+ spConfig.settings.each(function(setting) {
116
+ var attributeId, optionName;
117
+ attributeId = $(setting).id;
118
+ attributeId = attributeId.replace(/attribute/, '');
119
+ optionName = spConfig.config.attributes[attributeId].label;
120
+ if ($(setting).hasClassName('required-entry') && typeof PriceWaiter.setProductOptionRequired === 'function') {
121
+ PriceWaiter.setProductOptionRequired(optionName, true);
122
+ }
123
+ Event.observe(setting, 'change', function(event) {
124
+ var optionValue;
125
+ PriceWaiter.setPrice(Number(spConfig.config.basePrice) + Number(spConfig.reloadPrice()));
126
+ optionValue = setting.value !== '' ? setting.options[setting.selectedIndex].innerHTML : void 0;
127
+ if (optionValue === void 0) {
128
+ PriceWaiter.clearProductOption(optionName);
129
+ } else {
130
+ PriceWaiter.setProductOption(optionName, optionValue);
131
+ }
132
+ });
133
+ });
134
+ };
135
+ handleBundles = function() {
136
+ var bundleElements, bundleOption, key, matched, obj, opt, rePattern, requiredOptions;
137
+ requiredOptions = [];
138
+ bundleElements = document.getElementsByRegex('^bundle-option-');
139
+ rePattern = /\[(\d*)\]/;
140
+ for (bundleOption in bundleElements) {
141
+ if (!isNaN(parseInt(bundleOption, 10))) {
142
+ obj = bundleElements[bundleOption];
143
+ if (obj.hasClassName('required-entry') || obj.hasClassName('validate-one-required-by-name')) {
144
+ matched = rePattern.exec(obj.name);
145
+ requiredOptions.push(parseInt(matched[1], 10));
146
+ }
147
+ }
148
+ }
149
+ requiredOptions = requiredOptions.uniq();
150
+ for (key in bundle.config.options) {
151
+ if (requiredOptions.indexOf(parseInt(key, 10)) > -1) {
152
+ opt = bundle.config.options[key];
153
+ PriceWaiter.setProductOptionRequired(opt.title, true);
154
+ }
155
+ }
156
+ document.observe('bundle:reload-price', function(event) {
157
+ var bOptions, bSelected, current, currentSelected, qty, selectedValue;
158
+ PriceWaiter.setPrice(event.memo.priceInclTax);
159
+ bSelected = event.memo.bundle.config.selected;
160
+ bOptions = event.memo.bundle.config.options;
161
+ for (current in bSelected) {
162
+ if (isNaN(current)) {
163
+ continue;
164
+ }
165
+ currentSelected = bSelected[current];
166
+ if (currentSelected.length === 0) {
167
+ PriceWaiter.clearProductOption(bOptions[current].title);
168
+ } else {
169
+ qty = bOptions[current].selections[currentSelected].qty;
170
+ selectedValue = bOptions[current].selections[currentSelected].name;
171
+ if (qty > 1) {
172
+ selectedValue += ' - Quantity: ' + qty;
173
+ }
174
+ PriceWaiter.setProductOption(bOptions[current].title, selectedValue);
175
+ }
176
+ }
177
+ });
178
+ if (typeof bundle !== 'undefined') {
179
+ bundle.reloadPrice();
180
+ }
181
+ };
182
+ handleGrouped = function() {
183
+ var productRows, productTable, row;
184
+ productTable = $$('table.grouped-items-table')[0];
185
+ productRows = productTable.select('tbody')[0];
186
+ productRows = productRows.childElements();
187
+ if (productRows.length > 0) {
188
+ PriceWaiter.setProductOptionRequired('Quantity of Products', true);
189
+ }
190
+ for (row in productRows) {
191
+ if (!isNaN(parseInt(row, 10))) {
192
+ productRows[row].select('input.qty')[0].observe('change', function(event) {
193
+ var amountToRemove, inputName, pattern, previousQuantity, productID, productName, productPrice, qty;
194
+ qty = this.value;
195
+ pattern = /\[(.*)\]/;
196
+ inputName = this.name;
197
+ productID = pattern.exec(inputName);
198
+ productID = productID[1];
199
+ productName = window.PriceWaiterGroupedProductInfo[productID][0];
200
+ productPrice = window.PriceWaiterGroupedProductInfo[productID][1];
201
+ previousQuantity = PriceWaiter.getProductOptions()[productName + ' (' + productPrice + ')'];
202
+ amountToRemove = Number(previousQuantity * productPrice);
203
+ if (qty > 0) {
204
+ PriceWaiter.setProductOption(productName + ' (' + productPrice + ')', qty);
205
+ PriceWaiter.setPrice(Number(PriceWaiter.getPrice()) + Number(productPrice * qty));
206
+ } else {
207
+ PriceWaiter.clearProductOption(productName + ' (' + productPrice + ')');
208
+ }
209
+ if (previousQuantity > 0) {
210
+ PriceWaiter.setPrice(Number(PriceWaiter.getPrice() - amountToRemove));
211
+ }
212
+ if (Object.keys(PriceWaiter.getProductOptions()).length > 0) {
213
+ PriceWaiter.clearRequiredProductOptions();
214
+ } else {
215
+ PriceWaiter.setProductOptionRequired('Quantity of Products', true);
216
+ }
217
+ });
218
+ }
219
+ }
220
+ };
221
+ PriceWaiter.setRegularPrice(PriceWaiterRegularPrice);
222
+ document['getElementsByRegex'] = function(pattern) {
223
+ var arrElements, findRecursively, re;
224
+ arrElements = [];
225
+ re = new RegExp(pattern);
226
+ findRecursively = function(aNode) {
227
+ var idx;
228
+ if (!aNode) {
229
+ return;
230
+ }
231
+ if (aNode.id !== void 0 && aNode.id.search(re) !== -1) {
232
+ arrElements.push(aNode);
233
+ }
234
+ for (idx in aNode.childNodes) {
235
+ findRecursively(aNode.childNodes[idx]);
236
+ }
237
+ };
238
+ findRecursively(document);
239
+ return arrElements;
240
+ };
241
+ if ($('qty') !== null) {
242
+ $('qty').observe('change', function() {
243
+ PriceWaiter.setQuantity($('qty').value);
244
+ });
245
+ }
246
+ switch (PriceWaiterProductType) {
247
+ case 'simple':
248
+ handleSimples();
249
+ break;
250
+ case 'configurable':
251
+ handleConfigurables();
252
+ break;
253
+ case 'bundle':
254
+ handleBundles();
255
+ break;
256
+ case 'grouped':
257
+ handleGrouped();
258
+ }
259
+ };
260
+ }
261
+ if (window.PriceWaiterWidgetUrl) {
262
+ (function() {
263
+ var pw, s;
264
+ pw = document.createElement('script');
265
+ pw.type = 'text/javascript';
266
+ pw.src = window.PriceWaiterWidgetUrl;
267
+ pw.async = true;
268
+ s = document.getElementsByTagName('script')[0];
269
+ s.parentNode.insertBefore(pw, s);
270
+ })();
271
+ }
272
+ });
273
 
274
+ }).call(this);
 
 
 
 
js/pricewaiter/token.js ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ // Generated by CoffeeScript 1.9.1
2
+ (function() {
3
+ document.observe('dom:loaded', function() {
4
+ var button, enableButton, fetchToken, pwSignup, scope, tokenInput;
5
+ if (typeof priceWaiterTokenURL === 'undefined') {
6
+ return;
7
+ }
8
+ tokenInput = document.getElementById('pricewaiter_configuration_sign_up_token');
9
+ button = document.getElementById('nypwidget_signup');
10
+ scope = document.getElementById('store_switcher');
11
+ if (typeof button === 'undefined') {
12
+ return;
13
+ }
14
+ fetchToken = function() {
15
+ new Ajax.Request(priceWaiterTokenURL, {
16
+ method: 'post',
17
+ parameters: 'scope=' + scope.value,
18
+ onSuccess: function(transport) {
19
+ tokenInput.value = transport.responseText;
20
+ },
21
+ onComplete: function() {
22
+ enableButton();
23
+ }
24
+ });
25
+ };
26
+ pwSignup = function() {
27
+ window.open('https://manage.pricewaiter.com/sign-up?token=' + tokenInput.value);
28
+ return false;
29
+ };
30
+ enableButton = function() {
31
+ button.className = button.className.replace(/(?:^|\s)disabled(?!\S)/g, '');
32
+ button.enable();
33
+ };
34
+ button.observe('click', function() {
35
+ pwSignup();
36
+ });
37
+ if (tokenInput.value === '') {
38
+ fetchToken();
39
+ } else {
40
+ enableButton();
41
+ }
42
+ });
43
+
44
+ }).call(this);
package.xml CHANGED
@@ -1,21 +1,159 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>nypwidget</name>
4
- <version>1.2.7</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License, Version 2.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>PriceWaiter&#xAE; let's buyers make offers on your products that you can easily accept, counter offer or reject.</summary>
10
- <description>Sell more, immediately, with the PriceWaiter&#xAE; widget. Convert comparison shoppers you might have lost, increase sales and conversions, and stop "minimum advertised price" from preventing sales before they even start.&#xD;
11
- PriceWaiter&#xAE; lets customers make offers on products you sell-- offers you can accept, reject or counter. The widget embeds a simple Name Your Price button on any product page or category that you choose. Simply install the extension and you'll have full control over PriceWaiter&#xAE; in your Magento admin control panel.</description>
12
- <notes>Bug Fixes:&#xD;
13
- - Improved compatibility with grouped products.&#xD;
14
- </notes>
15
- <authors><author><name>PriceWaiter</name><user>pricewaiter</user><email>bobby.b@pricewaiter.com</email></author></authors>
16
- <date>2014-02-03</date>
17
- <time>09:33:00</time>
18
- <contents><target name="magecommunity"><dir name="PriceWaiter"><dir name="NYPWidget"><dir name="Block"><dir name="Adminhtml"><file name="Widget.php" hash="cffdba25dabdb8f9b6a2eac21c0e82e0"/></dir><file name="Category.php" hash="ba5bcfb87399356266eb2874bf691d6e"/><file name="Widget.php" hash="25489ee6ae666d91db98b70dd6adbf40"/></dir><dir name="Helper"><file name="Data.php" hash="e2d7bf749fa77e436b4166411c807487"/><file name=".Data.php.un~" hash="ebf997909064b973c4bb0720e63a48c0"/></dir><dir name="Model"><file name="Callback.php" hash="8f9b7fcc444a2b8edb13f76cfce2b670"/><dir name="Carrier"><file name="ShippingMethod.php" hash="1df7b75009a6e6e8e41b554fecb813db"/></dir><file name="Category.php" hash="55588e458cacb778b92fdacd8edeb22a"/><dir name="Display"><file name="Phrase.php" hash="ad605b93302ec648c5a7d3e3401f47b5"/><file name="Size.php" hash="42c2917e730811b78fd12e7591cb9159"/></dir><dir name="Mysql4"><dir name="Category"><file name="Collection.php" hash="adbbb19ccafb1498bb0d4c5d20abddd1"/></dir><file name="Category.php" hash="ba6b693541711d91edc5b7edae799a97"/><dir name="Order"><file name="Collection.php" hash="de7e92559722c9735b32a6d30862087e"/></dir><file name="Order.php" hash="237302190fa65833b5ff187dd0bbe71a"/></dir><file name="Observer.php" hash="a5b643d09e366068028dc1df1abee154"/><file name="Order.php" hash="c44f2d228a38e991843cee197abd397c"/><file name="PaymentMethod.php" hash="0106a5c193079d4cf07005fc9d22dd29"/><dir name="Resource"><dir name="Eav"><dir name="Mysql4"><file name="Setup.php" hash="da87eaa37fc5a09a5d5c38f9bbecabb1"/></dir></dir></dir></dir><dir name="controllers"><file name="CallbackController.php" hash="8b95003b06ebc0e1a05430655f2caacd"/></dir><dir name="etc"><file name="adminhtml.xml" hash="022f1761ba091c7e1f3e4901d40d5ce0"/><file name="config.xml" hash="5b75615e909d9f10b6c63af5c6488b21"/><file name="system.xml" hash="8b65aaf26f9bb75eee863e169b25a7ae"/><file name=".config.xml.un~" hash="dbeb241a6a168c330afedc248d5a8350"/></dir><dir name="sql"><dir name="nypwidget_setup"><file name="mysql4-install-1.0.0.php" hash="b30a0b38090a9c7aafb1a419b21755fe"/><file name="mysql4-upgrade-1.1.2-1.1.3.php" hash="8d4bd167694c277a0e8ab8034d87cb1b"/><file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="2a8de13744724f647e23e612ecf1d196"/><file name="mysql4-upgrade-1.2.4-1.2.5.php" hash="4b0ef14d3e455afea1d966f8f1641d6b"/><file name=".mysql4-install-1.0.0.php.un~" hash="4ac3da846a54fea6461349a73b2a8a0b"/><file name=".mysql4-upgrade-1.2.4-1.2.5.php.un~" hash="38d59b3e5dd699ac95c81d747a1f5dcc"/></dir></dir></dir></dir></target><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="pricewaiter.xml" hash="cc51462b56118a611be1a329b308d528"/></dir><dir name="template"><dir name="pricewaiter"><file name="admin_widget.phtml" hash="daae86cfa34fbe5e786715c0c579e398"/><file name="categorytab.phtml" hash="43f8af9feca6775e4a1e8a149a86268e"/></dir></dir></dir></dir></dir><dir name="frontend"><dir name="base"><dir name="default"><dir name="layout"><file name="pricewaiter.xml" hash="0da284d426574c7ae1f154b096f8b413"/></dir><dir name="template"><dir name="pricewaiter"><file name="widget.phtml" hash="d4e9f431922f843d5911a8b9ec2b814e"/></dir></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="PriceWaiter_NYPWidget.xml" hash="d3b86fa976b99e64df65f9e98d689257"/></dir></target><target name="mageweb"><dir name="js"><dir name="jscolor-pw"><file name="arrow.gif" hash="5034704a76cd55c1cbcbc58ea6bf523f"/><file name="cross.gif" hash="ba9a274b9323753cd95bc3b1eb2f4e5f"/><file name="hs.png" hash="fefa1a03d92ebad25c88dca94a0b63db"/><file name="hv.png" hash="990d71cada17da100653636cf8490884"/><file name="jscolor.js" hash="668050b57cb3ad59d0a56a16fddf1a91"/></dir><dir name="pricewaiter"><file name="product-pages.js" hash="13abcb256a75027c883c247af09392a3"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="images"><file name="pricewaiter_logo.png" hash="becb9713a561131ff69eabb7503d3e74"/><file name="pricewaiter_tab.png" hash="1bab71be6b1a93aee2ae7aeae3807484"/></dir><file name="pricewaiter.css" hash="6a58cdaa35d8f61cbb305a6a1a206816"/></dir></dir></dir></target></contents>
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
19
  <compatible/>
20
- <dependencies><required><php><min>5.2.0</min><max>6.0.0</max></php></required></dependencies>
 
 
 
 
 
 
 
21
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>nypwidget</name>
4
+ <version>2.0.0</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.apache.org/licenses/LICENSE-2.0.html">Apache License, Version 2.0</license>
7
  <channel>community</channel>
8
  <extends/>
9
  <summary>PriceWaiter&#xAE; let's buyers make offers on your products that you can easily accept, counter offer or reject.</summary>
10
+ <description>Sell more, immediately, with the PriceWaiter&#xAE; widget. Convert comparison shoppers you might have lost, increase sales and conversions, and stop "minimum advertised price" from preventing sales before they even start.&#xD;&#xD; PriceWaiter&#xAE; lets customers make offers on products you sell-- offers you can accept, reject or counter. The widget embeds a simple Name Your Price button on any product page or category that you choose. Simply install the extension and you'll have full control over PriceWaiter&#xAE; in your Magento admin control panel.</description>
11
+ <notes>Features:&#xD;- New, more powerful, button configuration controls:&#xD;- Easier setup with a new assisted PriceWaiter signup process:&#xD;- Support for Automated Acceptance</notes>
12
+ <authors>
13
+ <author>
14
+ <name>PriceWaiter</name>
15
+ <user>pricewaiter</user>
16
+ <email>bobby.b@pricewaiter.com</email>
17
+ </author>
18
+ </authors>
19
+ <date>2014-02-17</date>
20
+ <time>21:05:35</time>
21
+ <contents>
22
+ <target name="magecommunity">
23
+ <dir name="PriceWaiter">
24
+ <dir name="NYPWidget">
25
+ <dir name="Block">
26
+ <dir name="Adminhtml">
27
+ <file name="Widget.php" hash="b781daf1de34d7856de7faba65afe414"/>
28
+ <file name="Link.php" hash="848a4e3813a3d238cacdd812334bb780"/>
29
+ <file name="Signup.php" hash="dab8d9a3da78ce206c70877e1e8f71b9"/>
30
+ </dir>
31
+ <file name="Category.php" hash="de6397a45d7deabc803bef83a83d6b9a"/>
32
+ <file name="Widget.php" hash="193d694c4acc2133d8402f1e59d4dc25"/>
33
+ </dir>
34
+ <dir name="Helper">
35
+ <file name="Data.php" hash="49a7fdd4928b3c0d358ad7e1d240d874"/>
36
+ </dir>
37
+ <dir name="Model">
38
+ <file name="Callback.php" hash="65f978209a660f847954795c6a8525e8"/>
39
+ <dir name="Carrier">
40
+ <file name="ShippingMethod.php" hash="43a6ec1ad462797a5359238dcf9a749d"/>
41
+ </dir>
42
+ <file name="Category.php" hash="884685769be745cb273833ab7d691593"/>
43
+ <dir name="Display">
44
+ <file name="Phrase.php" hash="5b595a42b487930154c505a8e9a1301c"/>
45
+ <file name="Size.php" hash="8a596164268f48c3c034274550b13b96"/>
46
+ </dir>
47
+ <dir name="Mysql4">
48
+ <dir name="Category">
49
+ <file name="Collection.php" hash="45eaa532cd5935b69102b8969da848fa"/>
50
+ </dir>
51
+ <file name="Category.php" hash="f4e761813ec4bb81d919f30895ce3578"/>
52
+ <dir name="Order">
53
+ <file name="Collection.php" hash="4dc5b344274c0e5a391a24864fd1c003"/>
54
+ </dir>
55
+ <file name="Order.php" hash="c08b340cec16bf774a7c178726dee0ac"/>
56
+ </dir>
57
+ <file name="Observer.php" hash="2399e210dd82633091570483f144bf12"/>
58
+ <file name="Order.php" hash="080844dcc4cf55d516abe27175a3a62a"/>
59
+ <file name="PaymentMethod.php" hash="386134e1ac803580222263523f0ced31"/>
60
+ <dir name="Resource">
61
+ <dir name="Eav">
62
+ <dir name="Mysql4">
63
+ <file name="Setup.php" hash="d63678e9cc718ee87e8db3ca5163a8fd"/>
64
+ </dir>
65
+ </dir>
66
+ </dir>
67
+ </dir>
68
+ <dir name="controllers">
69
+ <dir name="Adminhtml">
70
+ <file name="PricewaiterController.php" hash="2dbf6509bca54d915c6f83de40e572bb"/>
71
+ </dir>
72
+ <file name="CallbackController.php" hash="d16b43353b74924298ff4cf7cf989f33"/>
73
+ <file name="ProductinfoController.php" hash="116869b03b42e93c66fde077aeec22ce"/>
74
+ </dir>
75
+ <dir name="etc">
76
+ <file name="adminhtml.xml" hash="dff2f6de0dacaf5a933048fa4a347f2f"/>
77
+ <file name="config.xml" hash="5f3051ad2ee38e9642dd6cac5a52926a"/>
78
+ <file name="system.xml" hash="82bb83cf7eb6a1d0ebf6bb774cd24414"/>
79
+ </dir>
80
+ <dir name="sql">
81
+ <dir name="nypwidget_setup">
82
+ <file name="mysql4-install-1.0.0.php" hash="cd1b7892e75e4452ee94afbbefb4de6e"/>
83
+ <file name="mysql4-upgrade-1.1.2-1.1.3.php" hash="d1ae05f5cbe4a8f833e92b9f49d395db"/>
84
+ <file name="mysql4-upgrade-1.1.7-1.1.8.php" hash="bd342c802f6c91de6f9f51b0a4a25414"/>
85
+ <file name="mysql4-upgrade-1.2.4-1.2.5.php" hash="b1ced0226bef6e950e026402b933872f"/>
86
+ <file name="mysql4-upgrade-1.3.0-1.3.1.php" hash="106b36065c125be31fc67424d80acdd4"/>
87
+ </dir>
88
+ </dir>
89
+ </dir>
90
+ </dir>
91
+ </target>
92
+ <target name="magedesign">
93
+ <dir name="adminhtml">
94
+ <dir name="default">
95
+ <dir name="default">
96
+ <dir name="layout">
97
+ <file name="pricewaiter.xml" hash="9e06026a8a820224336de4c9a7dde3fd"/>
98
+ </dir>
99
+ <dir name="template">
100
+ <dir name="pricewaiter">
101
+ <file name="categorytab.phtml" hash="d1d2c333cc9b18c909a44d333d8ab077"/>
102
+ <file name="signup.phtml" hash="1a1f3c3cd82b8e3360951c1012dc1131"/>
103
+ </dir>
104
+ </dir>
105
+ </dir>
106
+ </dir>
107
+ </dir>
108
+ <dir name="frontend">
109
+ <dir name="base">
110
+ <dir name="default">
111
+ <dir name="layout">
112
+ <file name="pricewaiter.xml" hash="cbaa61566545d46740d2e9b6078d1874"/>
113
+ </dir>
114
+ <dir name="template">
115
+ <dir name="pricewaiter">
116
+ <file name="widget.phtml" hash="9b2734821e5ed45d51b6926f51f834a0"/>
117
+ </dir>
118
+ </dir>
119
+ </dir>
120
+ </dir>
121
+ </dir>
122
+ </target>
123
+ <target name="mageetc">
124
+ <dir name="modules">
125
+ <file name="PriceWaiter_NYPWidget.xml" hash="72be18d9a8a741abc8926866449619cd"/>
126
+ </dir>
127
+ </target>
128
+ <target name="mage">
129
+ <dir name="js">
130
+ <dir name="pricewaiter">
131
+ <file name="product-pages.js" hash="cac0eecf149dc4ec34691a94f53737fa"/>
132
+ <file name="token.js" hash="25dddc701bf69053bdc94ff897e82cfa"/>
133
+ </dir>
134
+ </dir>
135
+ </target>
136
+ <target name="mageskin">
137
+ <dir name="adminhtml">
138
+ <dir name="default">
139
+ <dir name="default">
140
+ <dir name="images">
141
+ <file name="pricewaiter_logo.png" hash="becb9713a561131ff69eabb7503d3e74"/>
142
+ <file name="pricewaiter_tab.png" hash="1bab71be6b1a93aee2ae7aeae3807484"/>
143
+ </dir>
144
+ <file name="pricewaiter.css" hash="c4061169f3e505c28bd09924108ca0ad"/>
145
+ </dir>
146
+ </dir>
147
+ </dir>
148
+ </target>
149
+ </contents>
150
  <compatible/>
151
+ <dependencies>
152
+ <required>
153
+ <php>
154
+ <min>5.2.0</min>
155
+ <max>6.0.0</max>
156
+ </php>
157
+ </required>
158
+ </dependencies>
159
  </package>
skin/adminhtml/default/default/pricewaiter.css CHANGED
@@ -1,6 +1,6 @@
1
  /*
2
- * Copyright 2013 Price Waiter, LLC
3
- *
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
  * you may not use this file except in compliance with the License.
6
  * You may obtain a copy of the License at
@@ -15,35 +15,35 @@
15
  *
16
  */
17
  h3.pricewaiter-header {
18
- background:url(images/pricewaiter_logo.png) no-repeat 0 0;
19
- height:0px;
20
- overflow:hidden;
21
- padding:50px 0 0 0;
22
  margin: 0px;
23
- width:145px;
24
  }
25
 
26
  ul.tabs a.pricewaiter-tab,
27
  ul.tabs a.pricewaiter-tab:hover {
28
- background:url(images/tabs_span_bg.gif) repeat-x 0 100%;
29
- border-bottom:none;
30
- padding:0.5em 0.5em 0.28em 1.5em;
31
  }
32
 
33
  ul.tabs a.pricewaiter-tab:hover {
34
- background-color:#d8e6e6;
35
  }
36
 
37
  ul.tabs a.pricewaiter-tab.active,
38
  ul.tabs a.pricewaiter-tab.active:hover {
39
- background-color:#fff;
40
  }
41
 
42
  ul.tabs a.pricewaiter-tab span,
43
  ul.tabs a.pricewaiter-tab:hover span {
44
- background:url(images/pricewaiter_tab.png) no-repeat 0 0;
45
- height:0;
46
- overflow:hidden;
47
- padding:14px 0 0;
48
- width:300x;
49
  }
1
  /*
2
+ * Copyright 2013-2015 Price Waiter, LLC
3
+ *
4
  * Licensed under the Apache License, Version 2.0 (the "License");
5
  * you may not use this file except in compliance with the License.
6
  * You may obtain a copy of the License at
15
  *
16
  */
17
  h3.pricewaiter-header {
18
+ background: url(images/pricewaiter_logo.png) no-repeat 0 0;
19
+ height: 0px;
20
+ overflow: hidden;
21
+ padding: 50px 0 0 0;
22
  margin: 0px;
23
+ width: 145px;
24
  }
25
 
26
  ul.tabs a.pricewaiter-tab,
27
  ul.tabs a.pricewaiter-tab:hover {
28
+ background: url(images/tabs_span_bg.gif) repeat-x 0 100%;
29
+ border-bottom: none;
30
+ padding: 0.5em 0.5em 0.28em 1.5em;
31
  }
32
 
33
  ul.tabs a.pricewaiter-tab:hover {
34
+ background-color: #d8e6e6;
35
  }
36
 
37
  ul.tabs a.pricewaiter-tab.active,
38
  ul.tabs a.pricewaiter-tab.active:hover {
39
+ background-color: #fff;
40
  }
41
 
42
  ul.tabs a.pricewaiter-tab span,
43
  ul.tabs a.pricewaiter-tab:hover span {
44
+ background: url(images/pricewaiter_tab.png) no-repeat 0 0;
45
+ height: 0;
46
+ overflow: hidden;
47
+ padding: 14px 0 0;
48
+ width: 300x;
49
  }