SMSNotifier - Version 1.0.0

Version Notes

Visit product homepage at:
http://www.artio.net/e-shop/magento-extensions/magento-sms-notifier

Download this release

Release Info

Developer Magento Core Team
Extension SMSNotifier
Version 1.0.0
Comparing to
See all releases


Version 1.0.0

Files changed (35) hide show
  1. app/code/community/Artio/SMSNotifier/Block/Adminhtml/Data/Form/Element/CustomerNumbers.php +156 -0
  2. app/code/community/Artio/SMSNotifier/Block/Adminhtml/Send.php +54 -0
  3. app/code/community/Artio/SMSNotifier/Block/Adminhtml/Send/Form.php +75 -0
  4. app/code/community/Artio/SMSNotifier/Helper/Data.php +176 -0
  5. app/code/community/Artio/SMSNotifier/Helper/SMSLog.php +92 -0
  6. app/code/community/Artio/SMSNotifier/Model/Config.php +322 -0
  7. app/code/community/Artio/SMSNotifier/Model/Observer.php +180 -0
  8. app/code/community/Artio/SMSNotifier/Model/Service.php +226 -0
  9. app/code/community/Artio/SMSNotifier/Model/Sms.php +300 -0
  10. app/code/community/Artio/SMSNotifier/Model/Sms/Observer.php +201 -0
  11. app/code/community/Artio/SMSNotifier/Model/Sms/Template.php +255 -0
  12. app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Addresses.php +42 -0
  13. app/code/community/Artio/SMSNotifier/Model/System/Config/Source/CountryFilter.php +43 -0
  14. app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Gateway.php +41 -0
  15. app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Log.php +44 -0
  16. app/code/community/Artio/SMSNotifier/Model/System/Config/Source/SendToAdmin.php +72 -0
  17. app/code/community/Artio/SMSNotifier/controllers/AdminhtmlController.php +468 -0
  18. app/code/community/Artio/SMSNotifier/etc/adminhtml.xml +41 -0
  19. app/code/community/Artio/SMSNotifier/etc/config.xml +166 -0
  20. app/code/community/Artio/SMSNotifier/etc/system.xml +346 -0
  21. app/design/adminhtml/default/default/layout/smsnotify.xml +98 -0
  22. app/design/adminhtml/default/default/template/smsnotify/order/comments/view.phtml +97 -0
  23. app/design/adminhtml/default/default/template/smsnotify/order/view/history.phtml +196 -0
  24. app/etc/modules/Artio_SMSNotifyForMagento.xml +29 -0
  25. js/artio/numberfilters.js +1385 -0
  26. lib/Artio/SMSService/httphelper.php +243 -0
  27. lib/Artio/SMSService/smsservice.php +272 -0
  28. lib/Varien/Data/Form/Element/Accountinfo.php +138 -0
  29. lib/Varien/Data/Form/Element/Numberfilters.php +109 -0
  30. lib/Varien/Data/Form/Element/Selectdynamic.php +36 -0
  31. lib/Varien/Data/Form/Element/Smstextarea.php +183 -0
  32. package.xml +19 -0
  33. skin/adminhtml/default/default/images/entry_edit_head_arrow_x.gif +0 -0
  34. skin/adminhtml/default/default/images/ico_mobil.png +0 -0
  35. skin/adminhtml/default/default/smsnotify.css +109 -0
app/code/community/Artio/SMSNotifier/Block/Adminhtml/Data/Form/Element/CustomerNumbers.php ADDED
@@ -0,0 +1,156 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Send form.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team (info@artio.net)
23
+ */
24
+ class Artio_SMSNotifier_Block_Adminhtml_Data_Form_Element_CustomerNumbers extends Varien_Data_Form_Element_Multiselect
25
+ {
26
+
27
+ public function getElementHtml()
28
+ {
29
+ $config = Mage::getSingleton('smsnotify/config');
30
+
31
+ $helper = Mage::helper('smsnotify');
32
+ $url = Mage::helper("adminhtml")->getUrl('*/*/getnumbers');
33
+ $conurl = Mage::helper("adminhtml")->getUrl('adminhtml/system_config/edit/section/smsnotify');
34
+
35
+ $length = Mage::getStoreConfig("smsnotify/general/min_length_with_prefix");
36
+ $prefix = $config->getDialPrefix(Mage::getStoreConfig("smsnotify/general/local_country"));
37
+
38
+ $html = "
39
+ <input type=\"text\" id=\"search\" name=\"q\" value=\"\" class=\"input-text\" maxlength=\"128\" autocomplete=\"off\" /><br />
40
+ <p class=\"note\"><span>"
41
+ .$helper->__("Enter phone number or customer's name.")."<br />"
42
+ .$helper->__("There will be added dial prefix '%s' to numbers which are %s digits length or shorter.", $prefix, $length).' '
43
+ .$helper->__('Change this <a href="%s">here</a>.', $conurl).
44
+ "</span></p>
45
+ <div id=\"search_autocomplete\" class=\"search-autocomplete\" style=\"display:none;\"></div>
46
+ <input type=\"hidden\" id=\"customer_numbers\" name=\"customer_numbers\" value=\"\" />
47
+ <table id=\"table-numbers\" class=\"empty-table\">
48
+ <tbody id=\"table-numbers-tbody\">
49
+ <tr id=\"table-numbers-template\" style=\"display:none\">
50
+ <td><span class=\"phone\" style=\"display:none\"></span><span class=\"label\"></span></td>
51
+ <td class=\"last\"><button type=\"button\" onclick=\"removeNumber(this);\" class=\"delete\" ><span></span></button></td>
52
+ </tr>
53
+ </tbody>
54
+ </table>
55
+ <script type=\"text/javascript\">
56
+ //<![CDATA[
57
+ var searchForm = new Varien.searchForm('edit_form', 'search', '');
58
+ function removeNumber(element) {
59
+ var row = $(element).up('TR');
60
+ row.remove();
61
+ updateValues();
62
+ }
63
+ function updateValues() {
64
+ var vals = [];
65
+ $$('#table-numbers span.phone').each(function(span) {
66
+ var val = '';
67
+ if (span.up('TR').id != 'table-numbers-template')
68
+ val = span.innerHTML;
69
+ if (span.id)
70
+ val = val + ',' + span.id.replace('customer-', '');
71
+ if (val)
72
+ vals.push(val);
73
+ });
74
+ if (vals.length == 0)
75
+ $('table-numbers').addClassName('empty-table');
76
+ else
77
+ $('table-numbers').removeClassName('empty-table');
78
+ $('customer_numbers').value = vals.join(';');
79
+ }
80
+ new Ajax.Autocompleter(
81
+ searchForm.field,
82
+ 'search_autocomplete',
83
+ '".$url."',
84
+ {
85
+ paramName: searchForm.field.name,
86
+ method: 'get',
87
+ minChars: 2,
88
+ updateElement: function(element) {
89
+
90
+ if(typeof String.prototype.trim !== 'function') {
91
+ String.prototype.trim = function() {
92
+ return this.replace(/^\s+|\s+$/g, '');
93
+ }
94
+ }
95
+
96
+ var parts = element.innerHTML.split(',');
97
+
98
+ var name = (parts.length == 2) ? parts[0] : '';
99
+ var number = (parts.length == 2) ? parts[1] : parts[0];
100
+
101
+ name = new String(name);
102
+ number = new String(number);
103
+
104
+ name = name.trim();
105
+ number = number.trim();
106
+
107
+ var alreadyExist = $$('.table-numbers tr span.phone').any(function(span) {
108
+ return (span.innerHTML == number);
109
+ });
110
+ var allowed = !element.hasClassName('not-allowed');
111
+
112
+ if (!alreadyExist && allowed)
113
+ {
114
+ var newrow = $('table-numbers-template').cloneNode(true);
115
+ newrow.id = '';
116
+ newrow.style.display = '';
117
+
118
+ newrow.select('span.phone').each(function(span) {
119
+ span.innerHTML = number;
120
+ span.id = element.id;
121
+ });
122
+ newrow.select('span.label').each(function(span) {
123
+ span.innerHTML = element.innerHTML;
124
+ });
125
+
126
+ $('table-numbers-tbody').appendChild(newrow);
127
+ }
128
+
129
+ updateValues();
130
+
131
+ },
132
+ onShow : function(element, update) {
133
+ if(!update.style.position || update.style.position=='absolute') {
134
+ update.style.position = 'absolute';
135
+ Position.clone(element, update, {
136
+ setHeight: false,
137
+ offsetTop: element.offsetHeight
138
+ });
139
+ }
140
+ Effect.Appear(update,{duration:0});
141
+ //if (update.select('ul li').length > 1)
142
+ // update.removeClassName('empty-list');
143
+ //else
144
+ // update.addClassName('empty-list');
145
+ }
146
+
147
+ }
148
+ );
149
+ //]]>
150
+ </script>";
151
+
152
+ return $html;
153
+ }
154
+
155
+
156
+ }
app/code/community/Artio/SMSNotifier/Block/Adminhtml/Send.php ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Send form.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team (info@artio.net)
23
+ */
24
+ class Artio_SMSNotifier_Block_Adminhtml_Send extends Mage_Adminhtml_Block_Widget_Form_Container
25
+ {
26
+
27
+ public function __construct()
28
+ {
29
+ $this->_objectId = 'page_id';
30
+ $this->_blockGroup = 'smsnotify';
31
+ $this->_controller = 'adminhtml';
32
+
33
+ parent::__construct();
34
+
35
+ $this->_removeButton('reset');
36
+ $this->_removeButton('save');
37
+
38
+ $this->_addButton('save', array(
39
+ 'label' => Mage::helper('smsnotify')->__('Send SMS'),
40
+ 'onclick' => 'editForm.submit();',
41
+ 'class' => 'save',
42
+ ), 1);
43
+ }
44
+
45
+ /**
46
+ * Retrieve text for header element depending on loaded page
47
+ *
48
+ * @return string
49
+ */
50
+ public function getHeaderText() {
51
+ return Mage::helper('smsnotify')->__('SMS Notifier - Send SMS');
52
+ }
53
+
54
+ }
app/code/community/Artio/SMSNotifier/Block/Adminhtml/Send/Form.php ADDED
@@ -0,0 +1,75 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Send form.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team (info@artio.net)
23
+ */
24
+ class Artio_SMSNotifier_Block_Adminhtml_Send_Form extends Mage_Adminhtml_Block_Widget_Form
25
+ {
26
+
27
+
28
+ /**
29
+ * Prepare form.
30
+ */
31
+ protected function _prepareForm()
32
+ {
33
+ $form = new Varien_Data_Form(array(
34
+ 'name' => 'send_form',
35
+ 'id' => 'edit_form',
36
+ 'action' => $this->getData('action'), 'method' => 'post')
37
+ );
38
+
39
+ $fieldset = $form->addFieldset('sendsms_fieldset', array(
40
+ 'legend' => Mage::helper('smsnotify')->__('Telephone Number List'),
41
+ 'class' => 'fieldset'
42
+ ));
43
+
44
+ $fieldset->addType('customer_numbers', 'Artio_SMSNotifier_Block_Adminhtml_Data_Form_Element_CustomerNumbers');
45
+ $fieldset->addField('customer_numbers', 'customer_numbers', array(
46
+ 'name' => 'customer_numbers',
47
+ 'label' => Mage::helper('smsnotify')->__('Telephone Number List')
48
+ ));
49
+
50
+ $fieldset->addField('admin', 'select', array(
51
+ 'name' => 'admin',
52
+ 'label' => Mage::helper('smsnotify')->__('Send to administrator'),
53
+ 'options' => Mage::getModel('smsnotify/system_config_source_sendToAdmin')->toOptions()
54
+ ));
55
+
56
+ $fieldset2 = $form->addFieldset('textsms_fieldset', array(
57
+ 'legend' => Mage::helper('smsnotify')->__('SMS Text'),
58
+ 'class' => 'fieldset-wide'
59
+ ));
60
+
61
+ $fieldset2->addType('smstextarea', 'Varien_Data_Form_Element_Smstextarea');
62
+ $fieldset2->addField('sms_text', 'smstextarea', array(
63
+ 'name' => 'sms_text',
64
+ 'label' => Mage::helper('smsnotify')->__('Message'),
65
+ 'required' => true
66
+ ));
67
+
68
+ $form->setUseContainer(true);
69
+ $this->setForm($form);
70
+
71
+ return parent::_prepareForm();
72
+ }
73
+
74
+
75
+ }
app/code/community/Artio/SMSNotifier/Helper/Data.php ADDED
@@ -0,0 +1,176 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Standard helper.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Helper_Data extends Mage_Core_Helper_Abstract
25
+ {
26
+
27
+ /**
28
+ * Code for event new order.
29
+ * Code is related to config value, do not change it, please!
30
+ * @var string
31
+ */
32
+ const EVENT_NEW_ORDER = 'new_order';
33
+
34
+ /**
35
+ * Code for event new invoice.
36
+ * Code is related to config value, do not change it, please!
37
+ * @var string
38
+ */
39
+ const EVENT_NEW_INVOICE = 'new_invoice';
40
+
41
+ /**
42
+ * Code for event new shipment.
43
+ * Code is related to config value, do not change it, please!
44
+ * @var string
45
+ */
46
+ const EVENT_NEW_SHIPMENT = 'new_shipment';
47
+
48
+
49
+ /**
50
+ * All SMS order/invoice/shipment statuses should start
51
+ * this mark.
52
+ *
53
+ * @var string
54
+ */
55
+ const SMS_MARK = 'STATUS_SMS';
56
+
57
+
58
+ /**
59
+ * Determie whether there is allowed to send message
60
+ * for this event.
61
+ *
62
+ * @param string $type new_order|new_invoice|new_shipment
63
+ * @param Mage_Core_Model_Abstract $object
64
+ * @return bool
65
+ */
66
+ public function isEventAllowed($type, $object)
67
+ {
68
+ return $this->_getConfig()->isEventAllowed($type, $object->getStoreId());
69
+ }
70
+
71
+
72
+ /**
73
+ * Get customer's number.
74
+ *
75
+ * @param string $type new_order|new_invoice|new_shipment
76
+ * @param Mage_Core_Model_Abstract $object
77
+ */
78
+ public function getCustomerNumber($type, $object)
79
+ {
80
+ // no, we do not want to notify custoemr
81
+ if (!$this->_getConfig()->getNotifyCustomerForEvent($type, $object->getStoreId()))
82
+ return "";
83
+
84
+ $address = $this->_getConfig()->getUsedAddress($object->getStoreId());
85
+
86
+ $phone = '';
87
+
88
+ if ($address == 'billing')
89
+ {
90
+ $primary = $object->getBillingAddress();
91
+ $secondary = $object->getShippingAddress();
92
+ }
93
+ else
94
+ {
95
+ $primary = $object->getShippingAddress();
96
+ $secondary = $object->getBillingAddress();
97
+ }
98
+
99
+ $phone = $primary->getTelephone();
100
+
101
+ if (!$phone)
102
+ $phone = $secondary->getTelephone();
103
+
104
+ // add dial prefix if necessary
105
+ if ($phone)
106
+ $phone = $this->_getConfig()->sanitizeNumber($phone, $object->getStoreId());
107
+
108
+ return $phone;
109
+ }
110
+
111
+
112
+ /**
113
+ * Get country code.
114
+ *
115
+ * @param string $type new_order|new_invoice|new_shipment
116
+ * @param Mage_Core_Model_Abstract $object
117
+ */
118
+ public function getCountryCode($type, $object)
119
+ {
120
+ $address = $this->_getConfig()->getUsedAddress($object->getStoreId());
121
+
122
+ $country = '';
123
+
124
+ if ($address == 'billing')
125
+ {
126
+ $primary = $object->getBillingAddress();
127
+ $secondary = $object->getShippingAddress();
128
+ }
129
+ else
130
+ {
131
+ $primary = $object->getShippingAddress();
132
+ $secondary = $object->getBillingAddress();
133
+ }
134
+
135
+ $country = $primary->getCountry();
136
+
137
+ if (!$country)
138
+ $country = $secondary->getCountry();
139
+
140
+ return $country;
141
+ }
142
+
143
+
144
+ /**
145
+ *
146
+ * @param string $type new_order|new_invoice|new_shipment
147
+ * @param Mage_Core_Model_Abstract $object
148
+ */
149
+ public function getAdminNumber($type, $object)
150
+ {
151
+ return $this->_getConfig()->getAdminNumberForEvent($type, $object->getStoreId());
152
+ }
153
+
154
+
155
+ /**
156
+ *
157
+ * @param string $type new_order|new_invoice|new_shipment
158
+ * @param Mage_Core_Model_Abstract $object
159
+ */
160
+ public function getText($type, $object)
161
+ {
162
+ return $this->_getConfig()->getTextForEvent($type, $object->getStoreId());
163
+ }
164
+
165
+
166
+ /**
167
+ * Get standard configuration model.
168
+ *
169
+ * @return Artio_SMSNotifier_Helper_Model_Config
170
+ */
171
+ protected function _getConfig()
172
+ {
173
+ return Mage::getSingleton('smsnotify/config');
174
+ }
175
+
176
+ }
app/code/community/Artio/SMSNotifier/Helper/SMSLog.php ADDED
@@ -0,0 +1,92 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Standard helper.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Helper_SMSLog extends Mage_Core_Helper_Abstract
25
+ {
26
+
27
+
28
+ /**
29
+ * Log sended SMS to file var/log/smsnotify.log.
30
+ * Log must be enabled other method does nothing.
31
+ *
32
+ * Method return $this for keep the influence interface.
33
+ *
34
+ * @param Artio_SMSNotifier_Model_Sms $sms
35
+ * @return Artio_SMSNotifier_Helper_SMSLog $this
36
+ */
37
+ public function logSendedSMS(Artio_SMSNotifier_Model_Sms $sms)
38
+ {
39
+ $text = sprintf("SENT (%s)", $this->_smsToString($sms));
40
+
41
+ Mage::log($text, Zend_Log::DEBUG, 'smsnotify.log');
42
+
43
+ return $this;
44
+ }
45
+
46
+
47
+ /**
48
+ * Log sended SMS to file var/log/smsnotify.log.
49
+ * Log must be enabled other method does nothing.
50
+ *
51
+ * Method return $this for keep the influence interface.
52
+ *
53
+ * @param Artio_SMSNotifier_Model_Sms $sms
54
+ * @param string $errorMessage
55
+ * @return Artio_SMSNotifier_Helper_SMSLog
56
+ */
57
+ public function logNotSendedSMS(Artio_SMSNotifier_Model_Sms $sms, $errorMessage = '')
58
+ {
59
+ $text = sprintf("NOT SENT (error: %s) (%s)", $errorMessage, $this->_smsToString($sms));
60
+
61
+ Mage::log($text, Zend_Log::DEBUG, 'smsnotify.log');
62
+
63
+ return $this;
64
+ }
65
+
66
+
67
+ /**
68
+ * Convert $sms to string.
69
+ *
70
+ * @param Artio_SMSNotifier_Model_Sms $sms
71
+ * @return string
72
+ */
73
+ protected function _smsToString(Artio_SMSNotifier_Model_Sms $sms)
74
+ {
75
+ return sprintf("Type: %s; Number: %s; Text: %s",
76
+ $sms->isCustomerSMS() ? 'customer' : 'administrator',
77
+ $sms->getNumber(),
78
+ $sms->getText());
79
+ }
80
+
81
+
82
+ /**
83
+ * Get standard configuration model.
84
+ *
85
+ * @return Artio_SMSNotifier_Model_Config $config
86
+ */
87
+ protected function _getConfig()
88
+ {
89
+ Mage::getStoreConfig('smsnotify/config');
90
+ }
91
+
92
+ }
app/code/community/Artio/SMSNotifier/Model/Config.php ADDED
@@ -0,0 +1,322 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * SMS Model
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_Config
25
+ {
26
+
27
+
28
+ /**
29
+ * Determine whether number is allowed or not.
30
+ *
31
+ * For possible events look to Artio_SMSNotifier_Helper_Data
32
+ * constants.
33
+ *
34
+ * @param string $event
35
+ * @param int $storeId
36
+ * @return bool
37
+ */
38
+ public function isEventAllowed($event, $storeId = null)
39
+ {
40
+ return (bool) Mage::getStoreConfig("smsnotify/$event/enabled", $storeId);
41
+ }
42
+
43
+
44
+ /**
45
+ * Get message's text for an event.
46
+ *
47
+ * For possible events look to Artio_SMSNotifier_Helper_Data
48
+ * constants.
49
+ *
50
+ * @param string $event
51
+ * @param int $storeId
52
+ * @return string
53
+ */
54
+ public function getTextForEvent($event, $storeId = null)
55
+ {
56
+ return (string) Mage::getStoreConfig("smsnotify/$event/sms_text", $storeId);
57
+ }
58
+
59
+
60
+ /**
61
+ * Method determines whether there is allowed to notify the customer.
62
+ *
63
+ * @param string $event
64
+ * @param int $storeId
65
+ * @return bool
66
+ */
67
+ public function getNotifyCustomerForEvent($event, $storeId = null)
68
+ {
69
+ return (bool) Mage::getStoreConfig("smsnotify/$event/to_customer", $storeId);
70
+ }
71
+
72
+
73
+ /**
74
+ * Get administrator's number for an event.
75
+ *
76
+ * For possible events look to Artio_SMSNotifier_Helper_Data
77
+ * constants.
78
+ *
79
+ * Returned number is sanitizied (related to dial prefix).
80
+ *
81
+ * @param string $event
82
+ * @param int $storeId
83
+ * @return string
84
+ */
85
+ public function getAdminNumberForEvent($event, $storeId = null)
86
+ {
87
+ $index = (int) Mage::getStoreConfig("smsnotify/$event/to_admin", $storeId);
88
+
89
+ return $this->getAdminNumberByIndex($index, $storeId);
90
+ }
91
+
92
+
93
+ /**
94
+ * Get administrator's phone number by index.
95
+ *
96
+ * 1 - means primary phone number
97
+ * 2 - means secondary phone number
98
+ *
99
+ * on other values method returns false.
100
+ *
101
+ * Returned number is sanitizied (related to dial prefix).
102
+ *
103
+ * @param int $index
104
+ * @param int $storeId
105
+ * @return string|false
106
+ */
107
+ public function getAdminNumberByIndex($index, $storeId = null)
108
+ {
109
+ if ($index == 1)
110
+ return $this->sanitizeNumber(Mage::getStoreConfig("smsnotify/general/primary_admin", $storeId));
111
+ else if ($index == 2)
112
+ return $this->sanitizeNumber(Mage::getStoreConfig("smsnotify/general/secondary_admin", $storeId));
113
+ else
114
+ return false;
115
+ }
116
+
117
+
118
+ /**
119
+ * Method determines whether there is allowed to send the messages
120
+ * to country specified by $countryCode.
121
+ *
122
+ * $countryCode is two-char code of country (US,UK,DE etc.)
123
+ *
124
+ * If $countryCode is not specified method returns true
125
+ *
126
+ * @param string $countryCode
127
+ * @param int $storeId
128
+ * @return bool
129
+ */
130
+ public function isCountryAllowed($countryCode, $storeId = null)
131
+ {
132
+ if (!$countryCode)
133
+ return true;
134
+
135
+ $local = Mage::getStoreConfig("smsnotify/general/local_country", $storeId);
136
+ $type = Mage::getStoreConfig("smsnotify/country_filter/type", $storeId);
137
+ $countries = Mage::getStoreConfig("smsnotify/country_filter/specificcountry", $storeId);
138
+
139
+ switch ($type)
140
+ {
141
+ // we can send only to local country
142
+ case 'local':
143
+
144
+ $iso3 = Mage::getModel('directory/country')->load($countryCode)->getIso3Code();
145
+
146
+ $part = explode(',', $local);
147
+
148
+ if (!isset($part[0]) || !$part[0])
149
+ {
150
+ Mage::log(__CLASS__.":".__METHOD__.": Invalid local country code: '$local'.", Zend_Log::WARN);
151
+ return false;
152
+ }
153
+
154
+ return ($part[0] == $iso3);
155
+
156
+ // we can send message everywhere
157
+ case 'everywhere':
158
+ return true;
159
+
160
+ // we can send message to specified country
161
+ case 'specific':
162
+ return in_array($countryCode, explode(',', $countries));
163
+
164
+ // invalid country filter
165
+ default:
166
+ Mage::log(__CLASS__.":".__METHOD__.": Invalid country filter type: '$countryCode'.", Zend_Log::WARN);
167
+ return false;
168
+ }
169
+ }
170
+
171
+
172
+ /**
173
+ * Add dial prefix of local country if needed.
174
+ *
175
+ * @param string $number
176
+ * @return string
177
+ */
178
+ public function sanitizeNumber($number, $storeId = null)
179
+ {
180
+ $length = Mage::getStoreConfig("smsnotify/general/min_length_with_prefix", $storeId);
181
+ $local = Mage::getStoreConfig("smsnotify/general/local_country", $storeId);
182
+
183
+ $prefix = $this->getDialPrefix($local);
184
+
185
+ $number = trim($number);
186
+ $number = ltrim($number, "+");
187
+
188
+ if (strlen($number) <= $length)
189
+ $number = $prefix.$number;
190
+
191
+ return $number;
192
+ }
193
+
194
+
195
+ /**
196
+ * Determine whether number is allowed or not.
197
+ *
198
+ * @param string $number
199
+ * @param int $storeId
200
+ * @return bool
201
+ */
202
+ public function isNumberAllowed($number, $storeId = null)
203
+ {
204
+ $exclude = Mage::getStoreConfig("smsnotify/filter/exclude", $storeId);
205
+ $include = Mage::getStoreConfig("smsnotify/filter/include", $storeId);
206
+
207
+ $isExcluded = $this->_matchNumberFilters($number, $exclude);
208
+ $isIncluded = $this->_matchNumberFilters($number, $include);
209
+
210
+ return (!$isExcluded || $isIncluded);
211
+ }
212
+
213
+
214
+ /**
215
+ * Determine whether there is allowed log not sended messages.
216
+ *
217
+ * @param int $storeId
218
+ * @return bool
219
+ */
220
+ public function isAllowedLogNotSended($storeId = null)
221
+ {
222
+ return in_array((int)Mage::getStoreConfig("smsnotify/general/log"), array(0, 1));
223
+ }
224
+
225
+
226
+ /**
227
+ * Determine whether there is allowed log sended messages.
228
+ *
229
+ * @param int $storeId
230
+ * @return bool
231
+ */
232
+ public function isAllowedLogSended($storeId = null)
233
+ {
234
+ return in_array((int)Mage::getStoreConfig("smsnotify/general/log"), array(0, 2));
235
+ }
236
+
237
+
238
+ /**
239
+ * Extract dial prefix from $localCode.
240
+ *
241
+ * $localCode has format CODE,DIAL_PREFIX.
242
+ *
243
+ * @param string $localCode
244
+ * @return string
245
+ */
246
+ public function getDialPrefix($localCode)
247
+ {
248
+ $parts = explode(',', $localCode);
249
+
250
+ return (count($parts)==2) ? trim($parts[1]) : '';
251
+ }
252
+
253
+
254
+ /**
255
+ * Get used addresses.
256
+ *
257
+ * @param int $storeId
258
+ * @return string billing|shipping
259
+ */
260
+ public function getUsedAddress($storeId = null)
261
+ {
262
+ return Mage::getStoreConfig('smsnotify/general/used_addresses', $storeId);
263
+ }
264
+
265
+
266
+ /**
267
+ * Filters is a string:
268
+ *
269
+ * CODE,DIAL_PREFIX,FILTER;CODE,DIAL_PREFIX,FILTER ...
270
+ *
271
+ * FILTER is a string:
272
+ * 09?99?8*
273
+ *
274
+ * @param string $number
275
+ * @param array $filters
276
+ * @return bool
277
+ */
278
+ protected function _matchNumberFilters($number, $filters)
279
+ {
280
+ $maxLength = Artio_SMSNotifier_Model_Sms::MAX_LENGTH_NUMBER;
281
+
282
+ $filters = explode(';', $filters);
283
+
284
+ foreach ($filters as $filter)
285
+ {
286
+ list($country, $dialprefix, $filter) = explode(',', $filter);
287
+
288
+ $parts = explode('-', $filter);
289
+
290
+ // range
291
+ if (count($parts) == 2)
292
+ {
293
+ $from = str_replace(array('*', '?'), array('', '0'), $parts[0]);
294
+ $to = str_replace(array('*', '?'), array('', '9'), $parts[1]);
295
+
296
+ $from = $dialprefix.$from;
297
+ $to = $dialprefix.$to;
298
+
299
+ $from = str_pad($from, $maxLength, '0', STR_PAD_RIGHT);
300
+ $to = str_pad($to, $maxLength, '9', STR_PAD_RIGHT);
301
+
302
+ $number = str_pad($number, $maxLength, '0', STR_PAD_RIGHT);
303
+
304
+ if (strcmp($from, $number) <= 0 && strcmp($number, $to) <= 0)
305
+ return true;
306
+ }
307
+ // pattern
308
+ else
309
+ {
310
+ $regexp = '/^'.$dialprefix.str_replace(array('*', '?'), array('', '[0-9]'), $parts[0]).'/';
311
+
312
+ if (preg_match($regexp, $number))
313
+ return true;
314
+ }
315
+
316
+ }
317
+
318
+ return false;
319
+ }
320
+
321
+
322
+ }
app/code/community/Artio/SMSNotifier/Model/Observer.php ADDED
@@ -0,0 +1,180 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * SMS Model
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_Observer
25
+ {
26
+
27
+ /**
28
+ *
29
+ *
30
+ * @param Varien_Event_Observer $observer
31
+ * @return Artio_SMSNotifier_Model_Observer
32
+ */
33
+ public function beforeSaveAbstract($observer)
34
+ {
35
+ try
36
+ {
37
+ $event = $observer->getEvent();
38
+ $object = $event->getData('object');
39
+
40
+ if (
41
+ ($object instanceof Mage_Sales_Model_Order)
42
+ || ($object instanceof Mage_Sales_Model_Order_Invoice)
43
+ || ($object instanceof Mage_Sales_Model_Order_Shipment))
44
+ {
45
+ if (!$object->getId())
46
+ {
47
+ Mage::register('smsnotify_object', $object, $graceful = true);
48
+ }
49
+ }
50
+ }
51
+ catch (Exception $e)
52
+ {
53
+ Mage::logException($e);
54
+ Mage::log(__CLASS__.":".__METHOD__.":".$e->getMessage(), Zend_Log::ERR);
55
+ }
56
+
57
+ Mage::unregister('_helper/smsnotify/data');
58
+
59
+ return $this;
60
+ }
61
+
62
+
63
+ /**
64
+ *
65
+ * @param Varien_Event_Observer $observer
66
+ * @return Artio_SMSNotifier_Model_Observer
67
+ */
68
+ public function afterSaveAbstract($observer)
69
+ {
70
+ // get registered object (from beforeSaveAbstract)
71
+ $registered = Mage::registry('smsnotify_object');
72
+
73
+ // get saving object
74
+ $event = $observer->getEvent();
75
+ $object = $event->getData('object');
76
+
77
+ // if this does not match then we do not check this object type
78
+ if ($object != $registered)
79
+ return $this;
80
+
81
+ // flush registered object
82
+ Mage::unregister('smsnotify_object');
83
+
84
+ try
85
+ {
86
+ // get helper
87
+ $helper = Mage::helper('smsnotify');
88
+
89
+ // get event code by object type
90
+ $eventCode = '';
91
+
92
+ if ($object instanceof Mage_Sales_Model_Order)
93
+ $eventCode = Artio_SMSNotifier_Helper_Data::EVENT_NEW_ORDER;
94
+
95
+ if ($object instanceof Mage_Sales_Model_Order_Invoice)
96
+ $eventCode = Artio_SMSNotifier_Helper_Data::EVENT_NEW_INVOICE;
97
+
98
+ if ($object instanceof Mage_Sales_Model_Order_Shipment)
99
+ $eventCode = Artio_SMSNotifier_Helper_Data::EVENT_NEW_SHIPMENT;
100
+
101
+ // unknow event?
102
+ if (!$eventCode)
103
+ return $this;
104
+
105
+ // is there allowed send message?
106
+ if (!$helper->isEventAllowed($eventCode, $object))
107
+ return;
108
+
109
+ // get configuration
110
+ $text = $helper->getText($eventCode, $object);
111
+ $customerNumber = $helper->getCustomerNumber($eventCode, $object);
112
+ $adminNumber = $helper->getAdminNumber($eventCode, $object);
113
+ $country = $helper->getCountryCode($eventCode, $object);
114
+
115
+ // process text message
116
+ if ($eventCode == Artio_SMSNotifier_Helper_Data::EVENT_NEW_ORDER)
117
+ $text = Mage::getModel('smsnotify/sms_template')->setOrder($object)->process($text);
118
+ elseif ($eventCode == Artio_SMSNotifier_Helper_Data::EVENT_NEW_INVOICE)
119
+ $text = Mage::getModel('smsnotify/sms_template')->setInvoice($object)->process($text);
120
+ elseif ($eventCode == Artio_SMSNotifier_Helper_Data::EVENT_NEW_SHIPMENT)
121
+ $text = Mage::getModel('smsnotify/sms_template')->setShipment($object)->process($text);
122
+
123
+ // prepare sms
124
+ $sms = Mage::getModel('smsnotify/sms');
125
+ $sms->setStoreId($object->getStoreId());
126
+ $sms->setText($text);
127
+ $sms->addCustomData($eventCode, $object);
128
+
129
+ // send to customer
130
+ if ($customerNumber)
131
+ {
132
+ $sms->setType(Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER);
133
+ $sms->setCountry($country);
134
+ $sms->setNumber($customerNumber);
135
+ $this->_getService()->send($sms);
136
+ }
137
+
138
+ // send to admin
139
+ if ($adminNumber)
140
+ {
141
+ $sms->setType(Artio_SMSNotifier_Model_Sms::TYPE_ADMIN);
142
+ $sms->setCountry('');
143
+ $sms->setNumber($adminNumber);
144
+ $this->_getService()->send($sms);
145
+ }
146
+ }
147
+ catch (Exception $e)
148
+ {
149
+ Mage::logException($e);
150
+ Mage::log(__CLASS__.":".__METHOD__.":".$e->getMessage(), Zend_Log::ERR);
151
+ }
152
+
153
+ Mage::unregister('_helper/smsnotify/data');
154
+
155
+ return $this;
156
+ }
157
+
158
+
159
+ /**
160
+ * Get standard configuration model.
161
+ *
162
+ * @return Artio_SMSNotifier_Helper_Model_Config
163
+ */
164
+ protected function _getConfig()
165
+ {
166
+ return Mage::getSingleton('smsnotify/config');
167
+ }
168
+
169
+
170
+ /**
171
+ * Get standard service.
172
+ *
173
+ * @return Artio_SMSNotifier_Model_Service
174
+ */
175
+ protected function _getService()
176
+ {
177
+ return Mage::getSingleton('smsnotify/service');
178
+ }
179
+
180
+ }
app/code/community/Artio/SMSNotifier/Model/Service.php ADDED
@@ -0,0 +1,226 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Include extern library
19
+ */
20
+ require_once Mage::getBaseDir().DS.'lib'.DS.'Artio'.DS.'SMSService'.DS.'smsservice.php';
21
+
22
+ /**
23
+ * SMS Model
24
+ *
25
+ * @category Artio
26
+ * @package Artio_SMSNotifier
27
+ * @author Artio Magento Team <info@artio.net>
28
+ */
29
+ class Artio_SMSNotifier_Model_Service
30
+ {
31
+
32
+
33
+ /**
34
+ * Send $sms.
35
+ *
36
+ * If $sms is not set or not instance of Artio_SMSNotifier_Model_SMS then
37
+ * method logs WARNING and returns false.
38
+ *
39
+ * If there is not set username, apikey, or number is not set or is invalid
40
+ * method generates the event 'smsnotifier_error' and returns false.
41
+ *
42
+ * If all is right method generates the event 'smsnotifier_before_sending'
43
+ * and tries to send SMS.
44
+ *
45
+ * If SMS was sent method generates the event 'smsnotifier_after_sending'
46
+ * and returns true, otherwise generates 'smsnotifier_error' and return false.
47
+ *
48
+ * @param Artio_SMSNotifier_Model_SMS $sms
49
+ * @return bool
50
+ */
51
+ public function send($sms)
52
+ {
53
+ if (!$sms || !($sms instanceof Artio_SMSNotifier_Model_SMS))
54
+ {
55
+ Mage::log(__CLASS__.":".__METHOD__.": SMS is not set or is not instance of Artio_SMSNotifier_Model_SMS.", Zend_Log::WARN);
56
+ return false;
57
+ }
58
+
59
+ $username = $this->getUsername();
60
+ $apikey = $this->getApikey();
61
+
62
+ if (!$username)
63
+ {
64
+ $sms->addCustomData('error_message', $this->_helper()->__('API Username is not set. Check it in the configuration, please.'));
65
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
66
+ return false;
67
+ }
68
+
69
+ if (!$apikey)
70
+ {
71
+ $sms->addCustomData('error_message', $this->_helper()->__('API Key is not set. Check it in the configuration, please.'));
72
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
73
+ return false;
74
+ }
75
+
76
+ if (!$sms->getNumber())
77
+ {
78
+ $sms->addCustomData('error_message', $this->_helper()->__('Number is not set.'));
79
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
80
+ return false;
81
+ }
82
+
83
+ if (!preg_match('/^[0-9]{1,16}$/', $sms->getNumber()))
84
+ {
85
+ $sms->addCustomData('error_message', $this->_helper()->__("Number '%s' is not valid.", $sms->getNumber()));
86
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
87
+ return false;
88
+ }
89
+
90
+ if (!$this->_getConfig()->isNumberAllowed($sms->getNumber(), $sms->getStoreId()))
91
+ {
92
+ $sms->addCustomData('error_message', $this->_helper()->__("It is forbidden to send SMS to number '%s'. If you think that it is bad then check your number filters definitions in the configuration of SMSNotifyForMagento, please.", $sms->getNumber()));
93
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
94
+ return false;
95
+ }
96
+
97
+ if (!$this->_getConfig()->isCountryAllowed($sms->getCountry(), $sms->getStoreId()))
98
+ {
99
+ $sms->addCustomData('error_message', $this->_helper()->__("It is forbidden to send SMS to country '%s'. If you think that it is bad then check your country filter definitions in the configuration of SMSNotifyForMagento, please.", $sms->getCountry()));
100
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
101
+ return false;
102
+ }
103
+
104
+ Mage::dispatchEvent('smsnotifier_before_sending', array('sms' => $sms));
105
+
106
+ $service = ASmsService::getInstance();
107
+ $result = $service->sendMessage($username, $apikey, $sms->getNumber(), $sms->getText());
108
+
109
+ if ($result)
110
+ {
111
+ $sms->addCustomData('error_message', null);
112
+ Mage::dispatchEvent('smsnotifier_after_sending', array('sms' => $sms));
113
+ return true;
114
+ }
115
+ else
116
+ {
117
+ $sms->addCustomData('error_message', $service->getError());
118
+ Mage::dispatchEvent('smsnotifier_error', array('sms' => $sms));
119
+ return false;
120
+ }
121
+ }
122
+
123
+
124
+ /**
125
+ * Determine whether Username and API key is valid or not.
126
+ *
127
+ * @return string
128
+ */
129
+ public function testCredentials()
130
+ {
131
+ $username = $this->getUsername();
132
+ $apikey = $this->getApikey();
133
+
134
+ if (!$username)
135
+ return $this->_helper()->__('API Username is not set.');
136
+
137
+ if (!$apikey)
138
+ return $this->_helper()->__('API Key is not set.');
139
+
140
+ $service = ASmsService::getInstance();
141
+ $result = $service->getCreditInfo($username, $apikey);
142
+
143
+ if (!$result)
144
+ return $this->_helper()->__('You have not configured API username or API key properly.');
145
+ else
146
+ return "";
147
+ }
148
+
149
+
150
+ /**
151
+ * Returns current credit info - available credit and estimated credit exhaustion in hours
152
+ *
153
+ * @return mixed Associative array with credit info on success or false on error.
154
+ * Array contains following keys: credit, exhaustion
155
+ */
156
+ public function getCreditInfo()
157
+ {
158
+ $username = $this->getUsername();
159
+ $apikey = $this->getApikey();
160
+
161
+ $service = ASmsService::getInstance();
162
+ $result = $service->getCreditInfo($username, $apikey);
163
+
164
+ return $result;
165
+ }
166
+
167
+
168
+ /**
169
+ * Loads and returns the array of available credit amounts for purchase and the purchase URL
170
+ *
171
+ * @return array Associative array of [creditValues] => Credit amounts available for purchase ([value] => text)
172
+ * [link] => Purchase URL
173
+ */
174
+ public function getCreditPurchaseInfo()
175
+ {
176
+ $username = $this->getUsername();
177
+ $apikey = $this->getApikey();
178
+
179
+ $service = ASmsService::getInstance();
180
+ $result = $service->getCreditPurchaseInfo($username, $apikey);
181
+
182
+ return $result;
183
+ }
184
+
185
+
186
+ /**
187
+ * @return string
188
+ */
189
+ public function getUsername()
190
+ {
191
+ return Mage::getStoreConfig('smsnotify/credentials/username');
192
+ }
193
+
194
+
195
+ /**
196
+ * @return string
197
+ */
198
+ public function getApikey()
199
+ {
200
+ return Mage::getStoreConfig('smsnotify/credentials/apikey');
201
+ }
202
+
203
+
204
+ /**
205
+ * Get standard config.
206
+ *
207
+ * @return Artio_SMSNotifier_Model_Config
208
+ */
209
+ protected function _getConfig()
210
+ {
211
+ return Mage::getSingleton('smsnotify/config');
212
+ }
213
+
214
+
215
+ /**
216
+ * Get standard helper.
217
+ *
218
+ * @return Artio_SMSNotifier_Helper_Data
219
+ */
220
+ protected function _helper()
221
+ {
222
+ return Mage::helper('smsnotify');
223
+ }
224
+
225
+
226
+ }
app/code/community/Artio/SMSNotifier/Model/Sms.php ADDED
@@ -0,0 +1,300 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * SMS Model
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_Sms extends Varien_Object
25
+ {
26
+
27
+ /**
28
+ * Max number length.
29
+ *
30
+ * @var int
31
+ */
32
+ const MAX_LENGTH_NUMBER = 16;
33
+
34
+
35
+ /**
36
+ * This flag means: SMS is send to an administrator.
37
+ *
38
+ * @var int
39
+ */
40
+ const TYPE_ADMIN = 1;
41
+
42
+
43
+ /**
44
+ * This flag means: SMS is send to a customer.
45
+ * @var int
46
+ */
47
+ const TYPE_CUSTOMER = 2;
48
+
49
+
50
+ /**
51
+ * Type of SMS.
52
+ * @see Artio_SMSNotifier_Model_Sms::TYPE_ADMIN
53
+ * @see Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER
54
+ */
55
+ protected $_type = self::TYPE_CUSTOMER;
56
+
57
+
58
+ /**
59
+ * Store id.
60
+ *
61
+ * @var int
62
+ */
63
+ protected $_store_id = 0;
64
+
65
+
66
+ /**
67
+ * Phone number where SMS will be sent.
68
+ *
69
+ * @var string
70
+ */
71
+ protected $_number = '';
72
+
73
+
74
+ /**
75
+ * ISO2 code of country.
76
+ * This field is optional not all SMS has to filled.
77
+ *
78
+ * @var string
79
+ */
80
+ protected $_country = '';
81
+
82
+
83
+ /**
84
+ * Fullmeaning text of SMS, thus without any replacement {{ ... }}.
85
+ *
86
+ * @var string
87
+ */
88
+ protected $_text = '';
89
+
90
+
91
+ /**
92
+ * A custom data. Here can be stored a related customer or a related order
93
+ * or whatever you want.
94
+ *
95
+ * @var Varien_Object
96
+ */
97
+ protected $_customData = null;
98
+
99
+
100
+ /**
101
+ * Set type. You can use TYPE_ADMIN or TYPE_CUSTOMER as $type.
102
+ * If you use other value method does nothing and log warning.
103
+ *
104
+ * Method returns $this for keep the influence interface.
105
+ *
106
+ * @param int $type TYPE_ADMIN | TYPE_CUSTOMER
107
+ */
108
+ public function setType($type)
109
+ {
110
+ if ($type != self::TYPE_ADMIN && $type != self::TYPE_CUSTOMER)
111
+ {
112
+ Mage::log(__CLASS__.":".__METHOD__.": $type is not allowed for type SMS.", Zend_Log::WARN);
113
+ }
114
+ else
115
+ {
116
+ $this->_type = $type;
117
+ }
118
+
119
+ return $this;
120
+ }
121
+
122
+
123
+ /**
124
+ * Determine whether SMS is send to a customer or not.
125
+ *
126
+ * @return bool TRUE when sms is send to a customer, otherwise false.
127
+ */
128
+ public function isCustomerSMS()
129
+ {
130
+ return ($this->getType() == self::TYPE_CUSTOMER);
131
+ }
132
+
133
+
134
+ /**
135
+ * Determine whether SMS is send to an administrator or not.
136
+ *
137
+ * @return bool TRUE when sms is send to an administrator, otherwise false.
138
+ */
139
+ public function isAdminSMS()
140
+ {
141
+ return ($this->getType() == self::TYPE_ADMIN);
142
+ }
143
+
144
+
145
+ /**
146
+ * Get current type of SMS.
147
+ *
148
+ * @return int
149
+ */
150
+ public function getType()
151
+ {
152
+ return $this->_type;
153
+ }
154
+
155
+
156
+ /**
157
+ * Set number where SMS will be sent.
158
+ *
159
+ * Number should be max 16 chars length and should
160
+ * contains only digits [0-9].
161
+ *
162
+ * @param string $number
163
+ * @return Artio_SMSNotifier_Model_Sms
164
+ */
165
+ public function setNumber($number)
166
+ {
167
+ $this->_number = $number;
168
+
169
+ return $this;
170
+ }
171
+
172
+
173
+ /**
174
+ * Set number where SMS will be sent.
175
+ *
176
+ * @return string
177
+ */
178
+ public function getNumber()
179
+ {
180
+ return $this->_number;
181
+ }
182
+
183
+
184
+ /**
185
+ * Set country where SMS will be sent.
186
+ *
187
+ * Country code should be ISO2
188
+ *
189
+ * @param string $country
190
+ * @return Artio_SMSNotifier_Model_Sms
191
+ */
192
+ public function setCountry($country)
193
+ {
194
+ $this->_country = $country;
195
+
196
+ return $this;
197
+ }
198
+
199
+
200
+ /**
201
+ * Get country where SMS will be sent.
202
+ *
203
+ * @return string
204
+ */
205
+ public function getCountry()
206
+ {
207
+ return $this->_country;
208
+ }
209
+
210
+
211
+ /**
212
+ * Set text of SMS.
213
+ *
214
+ * @param string $text
215
+ * @return Artio_SMSNotifier_Model_Sms
216
+ */
217
+ public function setText($text)
218
+ {
219
+ $this->_text = $text;
220
+
221
+ return $this;
222
+ }
223
+
224
+
225
+ /**
226
+ * Get text of SMS.
227
+ *
228
+ * @return string
229
+ */
230
+ public function getText()
231
+ {
232
+ return $this->_text;
233
+ }
234
+
235
+
236
+ /**
237
+ * Set store id.
238
+ *
239
+ * @param string $storeid
240
+ * @return Artio_SMSNotifier_Model_Sms
241
+ */
242
+ public function setStoreId($storeid)
243
+ {
244
+ $this->_store_id = $storeid;
245
+
246
+ return $this;
247
+ }
248
+
249
+
250
+ /**
251
+ * Get store id.
252
+ *
253
+ * @return string
254
+ */
255
+ public function getStoreId()
256
+ {
257
+ return $this->_store_id;
258
+ }
259
+
260
+
261
+ /**
262
+ * Add $data to customData as $key.
263
+ *
264
+ * If there is a data as $key, then data will
265
+ * be overwritten.
266
+ *
267
+ * Method returns $this for kepp the influence interface.
268
+ *
269
+ * @param string $key
270
+ * @param mixed $data
271
+ * @return Artio_SMSNotifier_Model_Sms
272
+ */
273
+ public function addCustomData($key, $data)
274
+ {
275
+ if (is_null($this->_customData))
276
+ $this->_customData = new Varien_Object();
277
+
278
+ $this->_customData->setData($key, $data);
279
+
280
+ return $this;
281
+ }
282
+
283
+
284
+ /**
285
+ * Get custom data.
286
+ *
287
+ * @return Varien_Object|null
288
+ */
289
+ public function getCustomData($key = null)
290
+ {
291
+ if ($key)
292
+ $data = $this->_customData->getData($key);
293
+ else
294
+ $data = $this->_customData->getData();
295
+
296
+ return $data;
297
+ }
298
+
299
+
300
+ }
app/code/community/Artio/SMSNotifier/Model/Sms/Observer.php ADDED
@@ -0,0 +1,201 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * SMS Observer
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_Sms_Observer
25
+ {
26
+
27
+
28
+ /**
29
+ * Event is invoked just before sending a message.
30
+ *
31
+ * @param Varien_Event_Observer $observer
32
+ * @return Artio_SMSNotifier_Model_SmsObserver
33
+ */
34
+ public function beforeSending(Varien_Event_Observer $observer)
35
+ {
36
+ return $this;
37
+ }
38
+
39
+
40
+ /**
41
+ * Event is invoked just after sending a message.
42
+ *
43
+ * @param Varien_Event_Observer $observer
44
+ * @return Artio_SMSNotifier_Model_SmsObserver
45
+ */
46
+ public function afterSending(Varien_Event_Observer $observer)
47
+ {
48
+ $event = $observer->getEvent();
49
+ $sms = $event->getData('sms');
50
+
51
+ if ($this->_isThereAnySaleObject($sms))
52
+ {
53
+ $this->_addCommentToSaleObject($sms);
54
+ }
55
+
56
+ if ($this->_getConfig()->isAllowedLogSended($sms->getStoreId()))
57
+ {
58
+ $this->_getLogger()->logSendedSMS($sms);
59
+ }
60
+
61
+ return $this;
62
+ }
63
+
64
+
65
+ /**
66
+ * Event is invoked when sending a message is broken.
67
+ *
68
+ * @param Varien_Event_Observer $observer
69
+ * @return Artio_SMSNotifier_Model_SmsObserver
70
+ */
71
+ public function onError(Varien_Event_Observer $observer)
72
+ {
73
+ $event = $observer->getEvent();
74
+ $sms = $event->getData('sms');
75
+
76
+ if ($this->_isThereAnySaleObject($sms))
77
+ {
78
+ $this->_addCommentToSaleObject($sms);
79
+ }
80
+
81
+ if ($this->_getConfig()->isAllowedLogNotSended($sms->getStoreId()))
82
+ {
83
+ $this->_getLogger()->logNotSendedSMS($sms, $sms->getCustomData('error_message'));
84
+ }
85
+
86
+ return $this;
87
+ }
88
+
89
+
90
+ /**
91
+ * Determine whether SMS holds any sale object.
92
+ *
93
+ * @param Artio_SMSNotify_Model_Sms $sms
94
+ * @return bool
95
+ */
96
+ protected function _isThereAnySaleObject($sms)
97
+ {
98
+ $possibleKeys = array(
99
+ Artio_SMSNotifier_Helper_Data::EVENT_NEW_ORDER,
100
+ Artio_SMSNotifier_Helper_Data::EVENT_NEW_INVOICE,
101
+ Artio_SMSNotifier_Helper_Data::EVENT_NEW_SHIPMENT
102
+ );
103
+
104
+ $data = $sms->getCustomData();
105
+
106
+ $keys = array_keys($data);
107
+
108
+ $intersect = array_intersect($possibleKeys, $keys);
109
+
110
+ return !empty($intersect);
111
+ }
112
+
113
+
114
+ /**
115
+ * Add comment about send or not send SMS.
116
+ *
117
+ * @param Artio_SMSNotify_Model_Sms $sms
118
+ * @return Artio_SMSNotifier_Model_Sms_Observer
119
+ */
120
+ protected function _addCommentToSaleObject($sms)
121
+ {
122
+ // get helper
123
+ $helper = Mage::helper('smsnotify');
124
+
125
+ // get comment text
126
+ $error = $sms->getCustomData('error_message');
127
+
128
+ $person = $sms->isCustomerSMS() ?
129
+ $helper->__('customer') :
130
+ $helper->__('administrator');
131
+
132
+ $message = $error ?
133
+ $helper->__('Sending SMS to %s fails (Reason: %s)', $person, $error) :
134
+ $helper->__('%s was notified by SMS (Number: %s; Text: %s)', ucfirst($person), $sms->getNumber(), $sms->getText());
135
+
136
+ $comment = array();
137
+
138
+ $comment[] = 'STATUS_SMS';
139
+ $comment[] = $sms->isCustomerSMS() ? $helper->__('Customer') : $helper->__('Administrator');
140
+ $comment[] = $error ? 0 : 1;
141
+ $comment[] = $message;
142
+
143
+ $comment = implode(';', $comment);
144
+
145
+ // add comment
146
+ $customData = $sms->getCustomData();
147
+
148
+ $orderKey = Artio_SMSNotifier_Helper_Data::EVENT_NEW_ORDER;
149
+ $invoiceKey = Artio_SMSNotifier_Helper_Data::EVENT_NEW_INVOICE;
150
+ $shipmentKey = Artio_SMSNotifier_Helper_Data::EVENT_NEW_SHIPMENT;
151
+
152
+ if (isset($customData[$orderKey]))
153
+ {
154
+ $order = $customData[$orderKey];
155
+
156
+ $order->addStatusHistoryComment($comment);
157
+ $order->save();
158
+ }
159
+
160
+ if (isset($customData[$invoiceKey]))
161
+ {
162
+ $invoice = $customData[$invoiceKey];
163
+
164
+ $invoice->addComment($comment);
165
+ $invoice->save();
166
+ }
167
+
168
+ if (isset($customData[$shipmentKey]))
169
+ {
170
+ $shipment = $customData[$shipmentKey];
171
+
172
+ $shipment->addComment($comment);
173
+ $shipment->save();
174
+ }
175
+
176
+ return $this;
177
+ }
178
+
179
+
180
+ /**
181
+ * Get SMS logger.
182
+ *
183
+ * @return Artio_SMSNotifier_Helper_SmsLog
184
+ */
185
+ protected function _getLogger()
186
+ {
187
+ return Mage::helper('smsnotify/sMSLog');
188
+ }
189
+
190
+
191
+ /**
192
+ * Get standard config.
193
+ *
194
+ * @return Artio_SMSNotify_Model_Config
195
+ */
196
+ protected function _getConfig()
197
+ {
198
+ return Mage::getSingleton('smsnotify/config');
199
+ }
200
+
201
+ }
app/code/community/Artio/SMSNotifier/Model/Sms/Template.php ADDED
@@ -0,0 +1,255 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * SMS Template
19
+ *
20
+ * @method setCustomer(Mage_Customer_Model_Customer $customer)
21
+ * @method Mage_Customer_Model_Customer getCustomer()
22
+ * @method setOrder(Mage_Sales_Model_Order $customer)
23
+ * @method Mage_Sales_Model_Order getOrder()
24
+ * @method setInvoice(Mage_Sales_Model_Order_Invoice $customer)
25
+ * @method Mage_Sales_Model_Order_Invoice getInvoice()
26
+ * @method setShipment(Mage_Sales_Model_Order_Shipment $customer)
27
+ * @method Mage_Sales_Model_Order_Shipment getShipment()
28
+ *
29
+ * @category Artio
30
+ * @package Artio_SMSNotifier
31
+ * @author Artio Magento Team <info@artio.net>
32
+ */
33
+ class Artio_SMSNotifier_Model_Sms_Template extends Varien_Object
34
+ {
35
+
36
+
37
+ const CUSTOMER_FIRSTNAME = '{{c_firstname}}';
38
+ const CUSTOMER_LASTNAME = '{{c_lastname}}';
39
+ const CUSTOMER_EMAIL = '{{c_email}}';
40
+
41
+
42
+ const SALE_FIRSTNAME = '{{firstname}}';
43
+ const SALE_LASTNAME = '{{lastname}}';
44
+ const SALE_EMAIL = '{{email}}';
45
+ const SALE_AMOUNT = '{{amount}}';
46
+ const SALE_ORDER_NR = '{{order}}';
47
+ const SALE_INVOICE_NR = '{{invoice}}';
48
+ const SALE_SHIPMENT_NR = '{{shipment}}';
49
+
50
+
51
+ /**
52
+ * Process message text. Method replaces the special marks {{ ... }}
53
+ * by the meaningful words (customer firstname, order number ...).
54
+ *
55
+ * If $text is not a string or is undefined method returns empty string.
56
+ *
57
+ * If $type is not Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER or
58
+ * Artio_SMSNotifier_Model_Sms::TYPE_ADMIN then argument will set
59
+ * to Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER.
60
+ *
61
+ * For more description about replaces see
62
+ * @see Artio_SMSNotifier_Model_Sms_Template::_processCustomerMarks()
63
+ * @see Artio_SMSNotifier_Model_Sms_Template::_processSaleMarks()
64
+ *
65
+ * @param string $text
66
+ * @param int $type Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER | Artio_SMSNotifier_Model_Sms::TYPE_ADMIN
67
+ * @return string
68
+ */
69
+ public function process($text, $type = Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER)
70
+ {
71
+ if (!$text || !is_string($text))
72
+ return "";
73
+
74
+ if (!in_array($type, array(Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER, Artio_SMSNotifier_Model_Sms::TYPE_ADMIN)))
75
+ $type = Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER;
76
+
77
+ $text = $this->_processCustomerMarks($text, $type);
78
+ $text = $this->_processSaleMarks($text);
79
+
80
+ return $text;
81
+ }
82
+
83
+
84
+ /**
85
+ * Method processes customer marks.
86
+ *
87
+ * @param string $text
88
+ * @param int $type Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER | Artio_SMSNotifier_Model_Sms::TYPE_ADMIN
89
+ * @return string
90
+ */
91
+ protected function _processCustomerMarks($text, $type = Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER)
92
+ {
93
+ $firstname = '';
94
+ $lastname = '';
95
+ $email = '';
96
+
97
+ if ($type == Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER)
98
+ {
99
+ if ($this->hasCustomer())
100
+ {
101
+ $firstname = $this->getCustomer()->getFirstname();
102
+ $lastname = $this->getCustomer()->getLastname();
103
+ $email = $this->getCustomer()->getEmail();
104
+ }
105
+ }
106
+ else
107
+ {
108
+ $firstname = 'admin';
109
+ $lastname = 'admin';
110
+ }
111
+
112
+ $text = str_replace(self::CUSTOMER_FIRSTNAME, $firstname, $text);
113
+ $text = str_replace(self::CUSTOMER_LASTNAME, $lastname, $text);
114
+ $text = str_replace(self::CUSTOMER_EMAIL, $email, $text);
115
+
116
+ return $text;
117
+ }
118
+
119
+
120
+ /**
121
+ * Method processes sale marks.
122
+ *
123
+ * @param string $text
124
+ * @return string
125
+ */
126
+ protected function _processSaleMarks($text)
127
+ {
128
+ $mainObject = null;
129
+
130
+ if ($this->hasShipment())
131
+ $mainObject = $this->getShipment();
132
+ elseif ($this->hasInvoice())
133
+ $mainObject = $this->getInvoice();
134
+ elseif ($this->hasOrder())
135
+ $mainObject = $this->getOrder();
136
+
137
+ $firstname = '';
138
+ $lastname = '';
139
+ $email = '';
140
+ $amount = '';
141
+ $order = '';
142
+ $invoice = '';
143
+ $shipment = '';
144
+
145
+ if ($mainObject)
146
+ {
147
+ $storeId = $mainObject->getStoreId();
148
+
149
+ $address = $this->_getConfig()->getUsedAddress($storeId);
150
+
151
+ if ($address == 'billing')
152
+ {
153
+ $primary = $mainObject->getBillingAddress();
154
+ $secondary = $mainObject->getShippingAddress();
155
+ }
156
+ else
157
+ {
158
+ $primary = $mainObject->getShippingAddress();
159
+ $secondary = $mainObject->getBillingAddress();
160
+ }
161
+
162
+ $firstname = $primary->getFirstname();
163
+ $lastname = $primary->getLastname();
164
+ $email = $primary->getEmail();
165
+
166
+ if (!$firstname)
167
+ $firstname = $secondary->getFirstname();
168
+ if (!$lastname)
169
+ $lastname = $secondary->getLastname();
170
+ if (!$email)
171
+ $email = $secondary->getEmail();
172
+ }
173
+
174
+ if ($this->hasOrder())
175
+ {
176
+ $order = $this->getOrder()->getIncrementId();
177
+
178
+ $amount = $this->_formatPrice($this->getOrder());
179
+ }
180
+
181
+ if ($this->hasInvoice())
182
+ {
183
+ $order = $this->getInvoice()->getOrder()->getIncrementId();
184
+ $invoice = $this->getInvoice()->getIncrementId();
185
+
186
+ $amount = $this->_formatPrice($this->getInvoice());
187
+ }
188
+
189
+ if ($this->hasShipment())
190
+ {
191
+ $order = $this->getShipment()->getOrder()->getIncrementId();
192
+ $shipment = $this->getShipment()->getIncrementId();
193
+ }
194
+
195
+ $text = str_replace(self::SALE_FIRSTNAME, $firstname, $text);
196
+ $text = str_replace(self::SALE_LASTNAME, $lastname, $text);
197
+ $text = str_replace(self::SALE_EMAIL, $email, $text);
198
+ $text = str_replace(self::SALE_AMOUNT, $amount, $text);
199
+ $text = str_replace(self::SALE_ORDER_NR, $order, $text);
200
+ $text = str_replace(self::SALE_INVOICE_NR, $invoice, $text);
201
+ $text = str_replace(self::SALE_SHIPMENT_NR, $shipment, $text);
202
+
203
+ return $text;
204
+ }
205
+
206
+
207
+ /**
208
+ *
209
+ * @param Mage_Core_Model_Abstract $object
210
+ * @return string
211
+ */
212
+ protected function _formatPrice($object)
213
+ {
214
+ return $this->_currencyByStore(
215
+ $object->getGrandTotal(),
216
+ $object->getStoreId());
217
+ }
218
+
219
+
220
+ /**
221
+ * Convert and format price value for specified store
222
+ *
223
+ * @param float $value
224
+ * @param int|Mage_Core_Model_Store $store
225
+ * @param bool $format
226
+ * @param bool $includeContainer
227
+ * @return mixed
228
+ */
229
+ protected function _currencyByStore($value, $store = null)
230
+ {
231
+ try {
232
+ if (!($store instanceof Mage_Core_Model_Store)) {
233
+ $store = Mage::app()->getStore($store);
234
+ }
235
+
236
+ $value = $store->convertPrice($value, $format = true, $includeContainer = false);
237
+ }
238
+ catch (Exception $e){
239
+ $value = $e->getMessage();
240
+ }
241
+
242
+ return $value;
243
+ }
244
+
245
+
246
+
247
+ /**
248
+ * @return Artio_SMSNotifier_Model_Config
249
+ */
250
+ protected function _getConfig()
251
+ {
252
+ return Mage::getSingleton('smsnotify/config');
253
+ }
254
+
255
+ }
app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Addresses.php ADDED
@@ -0,0 +1,42 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Gateway.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_System_Config_Source_Addresses
25
+ {
26
+
27
+
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ return array(
36
+ array('value' => 'billing', 'label' => Mage::helper('smsnotify')->__('Billing Address')),
37
+ array('value' => 'shipping', 'label' => Mage::helper('smsnotify')->__('Shipping Address'))
38
+ );
39
+ }
40
+
41
+
42
+ }
app/code/community/Artio/SMSNotifier/Model/System/Config/Source/CountryFilter.php ADDED
@@ -0,0 +1,43 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Country filter.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_System_Config_Source_CountryFilter
25
+ {
26
+
27
+
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ return array(
36
+ array('value' => 'local', 'label' => Mage::helper('smsnotify')->__('Only local country')),
37
+ array('value' => 'everywhere', 'label' => Mage::helper('smsnotify')->__('Everywhere')),
38
+ array('value' => 'specific', 'label' => Mage::helper('smsnotify')->__('Only specific countries'))
39
+ );
40
+ }
41
+
42
+
43
+ }
app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Gateway.php ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Gateway.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_System_Config_Source_Gateway
25
+ {
26
+
27
+
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ return array(
36
+ array('value' => 'artio', 'label' => 'ARTIO (http://www.artio.net/)')
37
+ );
38
+ }
39
+
40
+
41
+ }
app/code/community/Artio/SMSNotifier/Model/System/Config/Source/Log.php ADDED
@@ -0,0 +1,44 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Gateway.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_System_Config_Source_Log
25
+ {
26
+
27
+
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ return array(
36
+ array('value' => '0', 'label' => Mage::helper('smsnotify')->__('All')),
37
+ array('value' => '1', 'label' => Mage::helper('smsnotify')->__('Only not send')),
38
+ array('value' => '2', 'label' => Mage::helper('smsnotify')->__('Only send')),
39
+ array('value' => '3', 'label' => Mage::helper('smsnotify')->__('Nothing'))
40
+ );
41
+ }
42
+
43
+
44
+ }
app/code/community/Artio/SMSNotifier/Model/System/Config/Source/SendToAdmin.php ADDED
@@ -0,0 +1,72 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Gateway.
19
+ *
20
+ * @category Artio
21
+ * @package Artio_SMSNotifier
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Artio_SMSNotifier_Model_System_Config_Source_SendToAdmin
25
+ {
26
+
27
+
28
+ /**
29
+ * Options getter
30
+ *
31
+ * @return array
32
+ */
33
+ public function toOptionArray()
34
+ {
35
+ return array(
36
+ array('value' => '0', 'label' => Mage::helper('smsnotify')->__('No')),
37
+ array('value' => '1', 'label' => Mage::helper('smsnotify')->__('Primary number')),
38
+ array('value' => '2', 'label' => Mage::helper('smsnotify')->__('Secondary number'))
39
+ );
40
+ }
41
+
42
+
43
+ /**
44
+ * Options getter
45
+ *
46
+ * @return array
47
+ */
48
+ public function toOptions()
49
+ {
50
+ $config = Mage::getSingleton('smsnotify/config');
51
+
52
+ $options = array();
53
+
54
+ foreach ($this->toOptionArray() as $item)
55
+ $options[$item['value']] = $item['label'];
56
+
57
+ $primary = Mage::getStoreConfig("smsnotify/general/primary_admin");
58
+ $secondary = Mage::getStoreConfig("smsnotify/general/secondary_admin");
59
+
60
+ $prmary = $config->sanitizeNumber($primary);
61
+ $secondary = $config->sanitizeNumber($secondary);
62
+
63
+ if ($primary)
64
+ $options[1] = $options[1]." ($primary)";
65
+ if ($secondary)
66
+ $options[2] = $options[2]." ($secondary)";
67
+
68
+ return $options;
69
+ }
70
+
71
+
72
+ }
app/code/community/Artio/SMSNotifier/controllers/AdminhtmlController.php ADDED
@@ -0,0 +1,468 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio (http://www.artio.net)
14
+ * @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Controller
19
+ *
20
+ * @category Artio
21
+ * @package Artio_MTurbo
22
+ * @author Artio Magento Team (info@artio.net)
23
+ */
24
+ class Artio_SMSNotifier_AdminhtmlController extends Mage_Adminhtml_Controller_Action
25
+ {
26
+
27
+
28
+ /**
29
+ * Dispaly form for sending a message.
30
+ *
31
+ * If credentials are not configured properly then user
32
+ * will be redirect to configuration page.
33
+ */
34
+ public function indexAction()
35
+ {
36
+ if ($error = $this->_getService()->testCredentials())
37
+ {
38
+ $this->_getSession()->addError($error);
39
+ $this->_redirect('adminhtml/system_config/edit/section/smsnotify');
40
+ return;
41
+ }
42
+
43
+ $this->loadLayout();
44
+ $this->renderLayout();
45
+ }
46
+
47
+
48
+ /**
49
+ * Send SMS action.
50
+ *
51
+ * If $smsText is not defined then action terminates with warning message.
52
+ * If credentials (API username, API key) is not configured properly action
53
+ * terminates with warning message.
54
+ *
55
+ * If all is right then action tries to send SMS to all customer numbers
56
+ * and to administrator number when is required.
57
+ *
58
+ * There will be displayed the information messages to each SMS.
59
+ */
60
+ public function saveAction()
61
+ {
62
+ $customerNumbers = $this->getRequest()->getParam('customer_numbers');
63
+ $text = $this->getRequest()->getParam('sms_text');
64
+ $admin = $this->getRequest()->getParam('admin');
65
+
66
+ $helper = Mage::helper('smsnotify');
67
+ $storeId = Mage::app()->getStore()->getId();
68
+ $service = $this->_getService();
69
+
70
+ // check sms text, try to send message without text has no sense
71
+ if (!$text)
72
+ {
73
+ $this->_getSession()->addError($helper->__('Message text is not defined.'));
74
+ $this->_redirectReferer();
75
+ return;
76
+ }
77
+
78
+ // check credentials
79
+ if ($error = $service->testCredentials())
80
+ {
81
+ $this->_getSession()->addError($error);
82
+ $this->_redirectReferer();
83
+ return;
84
+ }
85
+
86
+ // send SMS to admin
87
+ $adminNumber = $this->_getConfig()->getAdminNumberByIndex($admin);
88
+ if ($adminNumber)
89
+ {
90
+ $adminSms = Mage::getModel('smsnotify/sms');
91
+ $adminSms->setType(Artio_SMSNotifier_Model_Sms::TYPE_ADMIN);
92
+ $adminSms->setStoreId($storeId);
93
+ $adminSms->setNumber($adminNumber);
94
+ $adminSms->setText($text);
95
+
96
+ if ($service->send($adminSms))
97
+ {
98
+ $this->_getSession()->addSuccess($helper->__("SMS to '%s' was sent.", $adminNumber));
99
+ }
100
+ else
101
+ {
102
+ $message = $adminSms->getCustomData('error_message');
103
+
104
+ if ($message)
105
+ $this->_getSession()->addError($helper->__("SMS to '%s' could not be sent. Reason: '%s'", $adminNumber, $message));
106
+ else
107
+ $this->_getSession()->addError($helper->__("SMS to '%s' could not be sent. Reason is unknown. For more information see log, please.", $adminNumber));
108
+ }
109
+ }
110
+
111
+ // convert text representation customer_numbers to arrays
112
+ $customerNumbers = $this->_parseCustomerNumbers($customerNumbers);
113
+ $customerIds = $this->_getCustomerIds($customerNumbers);
114
+
115
+ // load customer
116
+ $customers = Mage::getModel('customer/customer')
117
+ ->getCollection()
118
+ ->addAttributeToSelect('firstname')
119
+ ->addAttributeToSelect('lastname')
120
+ ->addAttributeToSelect('email')
121
+ ->addFieldToFilter('entity_id', array('in' => $customerIds))
122
+ ->load();
123
+
124
+ // send SMS to customers
125
+ foreach ($customerNumbers as $customerNumber)
126
+ {
127
+ $telephone = $customerNumber['telephone'];
128
+ $customerId = $customerNumber['customer_id'];
129
+
130
+ $customer = $customers->getItemById($customerId);
131
+
132
+ $smsTemplate = Mage::getModel('smsnotify/sms_template');
133
+ if ($customer)
134
+ $smsTemplate->setCustomer($customer);
135
+ $messageText = $smsTemplate->process($text);
136
+
137
+ $customerSms = Mage::getModel('smsnotify/sms');
138
+ $customerSms->setType(Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER);
139
+ $customerSms->setStoreId($storeId);
140
+ $customerSms->setNumber($telephone);
141
+ $customerSms->setText($messageText);
142
+
143
+ if ($service->send($customerSms))
144
+ {
145
+ $this->_getSession()->addSuccess($helper->__("SMS to '%s' was sent.", $telephone));
146
+ }
147
+ else
148
+ {
149
+ $message = $customerSms->getCustomData('error_message');
150
+
151
+ if ($message)
152
+ $this->_getSession()->addError($helper->__("SMS to '%s' could not be sent. Reason: '%s'", $telephone, $message));
153
+ else
154
+ $this->_getSession()->addError($helper->__("SMS to '%s' could not be sent. Reason is unknown. For more information see log, please.", $telephone));
155
+ }
156
+ }
157
+
158
+ $this->_redirectReferer();
159
+ }
160
+
161
+
162
+ /**
163
+ * Parse the text representation of customer numbers to array
164
+ *
165
+ * 123133,2;12312313,3;4533553 => array(
166
+ * array(
167
+ * 'telephone' => 123133
168
+ * 'customer_id => 2
169
+ * ),
170
+ * array(
171
+ * 'telephone' => 12312313
172
+ * 'customer_id => 3
173
+ * ),
174
+ * array(
175
+ * 'telephone' => 4533553
176
+ * 'customer_id => 0
177
+ * ),
178
+ *
179
+ * @param string $numbers
180
+ * @return array
181
+ */
182
+ protected function _parseCustomerNumbers($numbers)
183
+ {
184
+ $result = array();
185
+
186
+ $numbers = explode(';', $numbers);
187
+
188
+ foreach ($numbers as $number)
189
+ {
190
+ $item = array();
191
+
192
+ $parts = explode(',', $number);
193
+
194
+ $item['telephone'] = (isset($parts[0])) ? $parts[0] : '';
195
+ $item['customer_id'] = (isset($parts[1])) ? (int) $parts[1] : 0;
196
+
197
+ $result[] = $item;
198
+ }
199
+
200
+ return $result;
201
+ }
202
+
203
+
204
+ /**
205
+ * Extract column 'customer_id' from an array
206
+ * made by _parseCustomerNumbers
207
+ *
208
+ * @param array $items
209
+ * @return array
210
+ */
211
+ protected function _getCustomerIds($items)
212
+ {
213
+ $result = array();
214
+
215
+ foreach ($items as $item)
216
+ if ($item['customer_id'])
217
+ $result[] = (int) $item['customer_id'];
218
+
219
+ $result = array_unique($result);
220
+
221
+ return $result;
222
+ }
223
+
224
+
225
+ /**
226
+ * Get numbers by the name or the phone number.
227
+ *
228
+ * Method searchs the customer's by firstname, lastname
229
+ * or telephone.
230
+ */
231
+ public function getnumbersAction()
232
+ {
233
+ $query = $this->getRequest()->getParam('q');
234
+
235
+ $result = array();
236
+
237
+ if ($query)
238
+ {
239
+ $whereCond = "%".mysql_real_escape_string($query)."%";
240
+
241
+ $custTable = Mage::getModel('core/resource')->getTableName('customer/entity');
242
+
243
+ $customerAddressCollection = Mage::getModel('customer/address')
244
+ ->getCollection()
245
+ ->joinTable('customer/entity', 'entity_id=parent_id', array('email'), null, 'left')
246
+ ->joinAttribute('firstname', 'customer_address/firstname', 'entity_id', null, 'left')
247
+ ->joinAttribute('lastname', 'customer_address/lastname', 'entity_id', null, 'left')
248
+ ->joinAttribute('telephone', 'customer_address/telephone', 'entity_id', null, 'left')
249
+ ->joinAttribute('country', 'customer_address/country_id', 'entity_id', null, 'left')
250
+ ->joinAttribute('c_firstname', 'customer/firstname', 'parent_id', null, 'left')
251
+ ->joinAttribute('c_lastname', 'customer/lastname', 'parent_id', null, 'left')
252
+ ->addAttributeToSort('lastname')
253
+ ->setPageSize(20); // we want to get only first 20
254
+
255
+ $version = Mage::getVersionInfo();
256
+
257
+ if ($version['minor'] < 6) // magento 1.6.0.0 and higher use another alias table
258
+ {
259
+ $customerAddressCollection->getSelect()->where("
260
+ `_table_firstname`.`value` LIKE '$whereCond'
261
+ OR `_table_lastname`.`value` LIKE '$whereCond'
262
+ OR `_table_c_firstname`.`value` LIKE '$whereCond'
263
+ OR `_table_c_lastname`.`value` LIKE '$whereCond'
264
+ OR `email` LIKE '$whereCond'
265
+ ");
266
+ }
267
+ else
268
+ {
269
+ $customerAddressCollection->getSelect()->where("
270
+ `at_firstname`.`value` LIKE '$whereCond'
271
+ OR `at_lastname`.`value` LIKE '$whereCond'
272
+ OR `at_c_firstname`.`value` LIKE '$whereCond'
273
+ OR `at_c_lastname`.`value` LIKE '$whereCond'
274
+ OR `email` LIKE '$whereCond'
275
+ ");
276
+ }
277
+
278
+ foreach ($customerAddressCollection as $address)
279
+ $result[] = $this->_buildLiElement(
280
+ $address->getLastname(),
281
+ $address->getFirstname(),
282
+ $address->getTelephone(),
283
+ $address->getCountry(),
284
+ $address->getCustomerId());
285
+
286
+ }
287
+
288
+ // if user enters number then we have to suggest it
289
+ if (preg_match('/^[0-9]+$/', $query))
290
+ array_unshift($result, $this->_buildLiElement("", "", $query, ""));
291
+
292
+ $isEmpty = empty($result);
293
+
294
+ // autcompleter requires at least 1 child
295
+ array_unshift($result, $this->_buildEmptyLiElement($isEmpty));
296
+
297
+ $html = '<ul>'.implode(' ', $result).'</ul>';
298
+
299
+ $this->getResponse()->setHeader('Content-type', 'text/html');
300
+ $this->getResponse()->setBody($html);
301
+ }
302
+
303
+
304
+ /**
305
+ * @return string
306
+ */
307
+ protected function _buildEmptyLiElement($visible)
308
+ {
309
+ if ($visible)
310
+ return '<li class="not-allowed">'.Mage::helper('smsnotify')->__('No data found').'</li>';
311
+ else
312
+ return '<li style="display:none"></li>';
313
+ }
314
+
315
+
316
+ /**
317
+ * @param string $firstname
318
+ * @param string $lastname
319
+ * @param string $number
320
+ * @return string
321
+ */
322
+ protected function _buildLiElement($firstname, $lastname, $number, $country, $customerId = null)
323
+ {
324
+ if (!$number)
325
+ return '';
326
+
327
+ $config = $this->_getConfig();
328
+
329
+ $number = $config->sanitizeNumber($number);
330
+
331
+ $allowed = true;
332
+ $title = Mage::helper('smsnotify')->__('Add number to list');
333
+
334
+ if (strlen($number)>16)
335
+ {
336
+ $allowed = false;
337
+ $title = Mage::helper('smsnotify')->__('Telephone number is too long. Telephone number may be maximally 16 digits length.');
338
+ }
339
+ elseif (!$config->isNumberAllowed($number))
340
+ {
341
+ $allowed = false;
342
+ $title = Mage::helper('smsnotify')->__("It is forbidden to send SMS to number '%s'. If you think that it is bad then check your number filters definitions in the configuration of SMS Notifier, please.", $number);
343
+ }
344
+ elseif (!$config->isCountryAllowed($country))
345
+ {
346
+ $allowed = false;
347
+ $title = Mage::helper('smsnotify')->__("It is forbidden to send SMS to country '%s'. If you think that it is bad then check your country filter definitions in the configuration of SMS Notifier, please.", $country);
348
+ }
349
+
350
+ $class = $allowed ? '' : 'not-allowed';
351
+
352
+ $label = '';
353
+
354
+ if ($firstname && $lastname)
355
+ $label = $firstname." ".$lastname.", ".$number;
356
+ else if ($firstname && !$lastname)
357
+ $label = $firstname.", ".$number;
358
+ else if (!$firstname && $lastname)
359
+ $label = $lastname.", ".$number;
360
+ else
361
+ $label = $number;
362
+
363
+ $id = $customerId ? 'id="customer-'.$customerId.'"' : '';
364
+
365
+ return sprintf('<li class="%s" title="%s" %s >%s</li>', $class, $title, $id, $label);
366
+ }
367
+
368
+
369
+ /**
370
+ * Send SMS to order's customer.
371
+ */
372
+ public function smscommentAction()
373
+ {
374
+ $this->_initOrder();
375
+
376
+ $text = $this->getRequest()->getParam('sms_comment');
377
+
378
+ if ($text)
379
+ {
380
+ try
381
+ {
382
+ $event = Artio_SMSNotifier_Helper_Data::EVENT_NEW_ORDER;
383
+ $type = Artio_SMSNotifier_Model_Sms::TYPE_CUSTOMER;
384
+
385
+ $helper = Mage::helper('smsnotify');
386
+ $order = Mage::registry('sales_order');
387
+
388
+ $sms = Mage::getModel('smsnotify/sms');
389
+ $sms->setStoreId($order->getStoreId());
390
+ $sms->setType($type);
391
+ $sms->setCountry($helper->getCountryCode($event, $order));
392
+ $sms->setNumber($helper->getCustomerNumber($event, $order));
393
+ $sms->setText($text);
394
+ $sms->addCustomData($event, $order);
395
+
396
+ $this->_getService()->send($sms);
397
+ }
398
+ catch (Exception $e)
399
+ {
400
+ Mage::logException($e);
401
+ Mage::log(__CLASS__.":".__METHOD__.": SMS is not send!.", Zend_Log::ERR);
402
+ }
403
+
404
+ }
405
+
406
+ $this->getLayout()->getUpdate()->addHandle('adminhtml_sales_order_addcomment');
407
+
408
+ $this->loadLayout('empty');
409
+ $this->renderLayout();
410
+ }
411
+
412
+
413
+ /**
414
+ * Initialize order model instance
415
+ *
416
+ * @return Mage_Sales_Model_Order || false
417
+ */
418
+ protected function _initOrder()
419
+ {
420
+ $id = $this->getRequest()->getParam('order_id');
421
+ $order = Mage::getModel('sales/order')->load($id);
422
+
423
+ if (!$order->getId()) {
424
+ $this->_getSession()->addError($this->__('This order no longer exists.'));
425
+ $this->_redirect('*/*/');
426
+ $this->setFlag('', self::FLAG_NO_DISPATCH, true);
427
+ return false;
428
+ }
429
+ Mage::register('sales_order', $order);
430
+ Mage::register('current_order', $order);
431
+ return $order;
432
+ }
433
+
434
+
435
+ /**
436
+ * Get standard configuration model.
437
+ *
438
+ * @return Artio_SMSNotifier_Helper_Model_Config
439
+ */
440
+ protected function _getConfig()
441
+ {
442
+ return Mage::getSingleton('smsnotify/config');
443
+ }
444
+
445
+
446
+ /**
447
+ * Get standard service.
448
+ *
449
+ * @return Artio_SMSNotifyHelper_Model_Service
450
+ */
451
+ protected function _getService()
452
+ {
453
+ return Mage::getSingleton('smsnotify/service');
454
+ }
455
+
456
+
457
+ /**
458
+ * Get backend session.
459
+ *
460
+ * @return Mage_Adminhtml_Model_Session
461
+ */
462
+ protected function _getSession()
463
+ {
464
+ return Mage::getSingleton('adminhtml/session');
465
+ }
466
+
467
+
468
+ }
app/code/community/Artio/SMSNotifier/etc/adminhtml.xml ADDED
@@ -0,0 +1,41 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <!--
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+ -->
17
+ <adminhtml>
18
+ <menu>
19
+ <system>
20
+ <children>
21
+ <smsnotify translate="title" module="smsnotify">
22
+ <title>SMS Notifier</title>
23
+ <action>smsnotify</action>
24
+ <sort_order>16</sort_order>
25
+ <children>
26
+ <send>
27
+ <title>Send SMS</title>
28
+ <action>smsnotify/adminhtml</action>
29
+ <sort_order>10</sort_order>
30
+ </send>
31
+ <config>
32
+ <title>Configuration</title>
33
+ <action>adminhtml/system_config/edit/section/smsnotify</action>
34
+ <sort_order>20</sort_order>
35
+ </config>
36
+ </children>
37
+ </smsnotify>
38
+ </children>
39
+ </system>
40
+ </menu>
41
+ </adminhtml>
app/code/community/Artio/SMSNotifier/etc/config.xml ADDED
@@ -0,0 +1,166 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * SMS Notifier
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Academic Free License (AFL 3.0)
9
+ * It is available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ *
12
+ * @category Artio
13
+ * @package Artio_SMSNotifier
14
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
15
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
16
+ */
17
+ -->
18
+ <config>
19
+ <modules>
20
+ <Artio_SMSNotifier>
21
+ <version>1.0.0</version>
22
+ </Artio_SMSNotifier>
23
+ </modules>
24
+ <admin>
25
+ <routers>
26
+ <smsnotify>
27
+ <use>admin</use>
28
+ <args>
29
+ <module>Artio_SMSNotifier</module>
30
+ <frontName>smsnotify</frontName>
31
+ </args>
32
+ </smsnotify>
33
+ </routers>
34
+ </admin>
35
+ <global>
36
+ <blocks>
37
+ <smsnotify>
38
+ <class>Artio_SMSNotifier_Block</class>
39
+ </smsnotify>
40
+ </blocks>
41
+ <helpers>
42
+ <smsnotify>
43
+ <class>Artio_SMSNotifier_Helper</class>
44
+ </smsnotify>
45
+ </helpers>
46
+ <models>
47
+ <smsnotify>
48
+ <class>Artio_SMSNotifier_Model</class>
49
+ </smsnotify>
50
+ </models>
51
+ <events>
52
+ <model_save_before>
53
+ <observers>
54
+ <smsnotify>
55
+ <class>smsnotify/observer</class>
56
+ <method>beforeSaveAbstract</method>
57
+ </smsnotify>
58
+ </observers>
59
+ </model_save_before>
60
+ <model_save_after>
61
+ <observers>
62
+ <smsnotify>
63
+ <class>smsnotify/observer</class>
64
+ <method>afterSaveAbstract</method>
65
+ </smsnotify>
66
+ </observers>
67
+ </model_save_after>
68
+ <smsnotifier_error>
69
+ <observers>
70
+ <smsnotify>
71
+ <class>smsnotify/sms_observer</class>
72
+ <type>singleton</type>
73
+ <method>onError</method>
74
+ </smsnotify>
75
+ </observers>
76
+ </smsnotifier_error>
77
+ <smsnotifier_before_sending>
78
+ <observers>
79
+ <smsnotify>
80
+ <class>smsnotify/sms_observer</class>
81
+ <type>singleton</type>
82
+ <method>beforeSending</method>
83
+ </smsnotify>
84
+ </observers>
85
+ </smsnotifier_before_sending>
86
+ <smsnotifier_after_sending>
87
+ <observers>
88
+ <smsnotify>
89
+ <class>smsnotify/sms_observer</class>
90
+ <type>singleton</type>
91
+ <method>afterSending</method>
92
+ </smsnotify>
93
+ </observers>
94
+ </smsnotifier_after_sending>
95
+ </events>
96
+ </global>
97
+ <adminhtml>
98
+ <layout>
99
+ <updates>
100
+ <smsnotify>
101
+ <file>smsnotify.xml</file>
102
+ </smsnotify>
103
+ </updates>
104
+ </layout>
105
+ <acl>
106
+ <resources>
107
+ <admin>
108
+ <children>
109
+ <system>
110
+ <children>
111
+ <smsnotify translate="title" module="smsnotify">
112
+ <title>SMS Notifier</title>
113
+ <children>
114
+ <send translate="title" module="smsnotify">
115
+ <title>Sending SMS</title>
116
+ </send>
117
+ </children>
118
+ </smsnotify>
119
+ <config>
120
+ <children>
121
+ <smsnotify translate="title" module="smsnotify">
122
+ <title>SMS Notifier</title>
123
+ </smsnotify>
124
+ </children>
125
+ </config>
126
+ </children>
127
+ </system>
128
+ </children>
129
+ </admin>
130
+ </resources>
131
+ </acl>
132
+ </adminhtml>
133
+ <default>
134
+ <smsnotify>
135
+ <credentials>
136
+ <gateway>artio</gateway>
137
+ </credentials>
138
+ <general>
139
+ <min_length_with_prefix>9</min_length_with_prefix>
140
+ <used_addresses>billing</used_addresses>
141
+ <log>0</log>
142
+ </general>
143
+ <country_filter>
144
+ <type>everywhere</type>
145
+ </country_filter>
146
+ <new_order>
147
+ <enabled>0</enabled>
148
+ <to_customer>1</to_customer>
149
+ <to_admin>1</to_admin>
150
+ <text></text>
151
+ </new_order>
152
+ <new_invoice>
153
+ <enabled>0</enabled>
154
+ <to_customer>1</to_customer>
155
+ <to_admin>1</to_admin>
156
+ <text></text>
157
+ </new_invoice>
158
+ <new_shipment>
159
+ <enabled>0</enabled>
160
+ <to_customer>1</to_customer>
161
+ <to_admin>1</to_admin>
162
+ <text></text>
163
+ </new_shipment>
164
+ </smsnotify>
165
+ </default>
166
+ </config>
app/code/community/Artio/SMSNotifier/etc/system.xml ADDED
@@ -0,0 +1,346 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * SMS Notifier
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Academic Free License (AFL 3.0)
9
+ * It is available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ *
12
+ * @category Artio
13
+ * @package Artio_SMSNotifier
14
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
15
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
16
+ */
17
+ -->
18
+ <config>
19
+ <sections>
20
+ <smsnotify translate="label" module="smsnotify">
21
+ <label>SMS Notifier</label>
22
+ <tab>sales</tab>
23
+ <class>smsnotify-section</class>
24
+ <frontend_type>text</frontend_type>
25
+ <sort_order>1</sort_order>
26
+ <show_in_default>1</show_in_default>
27
+ <show_in_website>1</show_in_website>
28
+ <show_in_store>1</show_in_store>
29
+ <groups>
30
+ <credentials translate="label comment" module="smsnotify">
31
+ <label>Gateway Credentials</label>
32
+ <frontend_type>text</frontend_type>
33
+ <sort_order>20</sort_order>
34
+ <show_in_default>1</show_in_default>
35
+ <show_in_website>0</show_in_website>
36
+ <show_in_store>0</show_in_store>
37
+ <fields>
38
+ <gateway translate="label comment" module="smsnotify">
39
+ <label>Gateway</label>
40
+ <frontend_type>select</frontend_type>
41
+ <source_model>smsnotify/system_config_source_gateway</source_model>
42
+ <sort_order>10</sort_order>
43
+ <show_in_default>1</show_in_default>
44
+ <show_in_website>0</show_in_website>
45
+ <show_in_store>0</show_in_store>
46
+ </gateway>
47
+ <username translate="label comment" module="smsnotify">
48
+ <label>Username</label>
49
+ <frontend_type>text</frontend_type>
50
+ <sort_order>20</sort_order>
51
+ <show_in_default>1</show_in_default>
52
+ <show_in_website>0</show_in_website>
53
+ <show_in_store>0</show_in_store>
54
+ </username>
55
+ <apikey translate="label comment" module="smsnotify">
56
+ <label>API key</label>
57
+ <frontend_type>text</frontend_type>
58
+ <sort_order>30</sort_order>
59
+ <show_in_default>1</show_in_default>
60
+ <show_in_website>0</show_in_website>
61
+ <show_in_store>0</show_in_store>
62
+ </apikey>
63
+ <account_info translate="label comment" module="smsnotify">
64
+ <label></label>
65
+ <frontend_type>accountinfo</frontend_type>
66
+ <sort_order>40</sort_order>
67
+ <show_in_default>1</show_in_default>
68
+ <show_in_website>0</show_in_website>
69
+ <show_in_store>0</show_in_store>
70
+ </account_info>
71
+ </fields>
72
+ </credentials>
73
+ <general translate="label comment" module="smsnotify">
74
+ <label>General Settings</label>
75
+ <frontend_type>text</frontend_type>
76
+ <sort_order>30</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
+ <fields>
81
+ <primary_admin translate="label comment" module="smsnotify">
82
+ <label>Primary admin's number</label>
83
+ <frontend_type>text</frontend_type>
84
+ <validate>validate-digits validate-length maximum-length-16</validate>
85
+ <sort_order>5</sort_order>
86
+ <show_in_default>1</show_in_default>
87
+ <show_in_website>1</show_in_website>
88
+ <show_in_store>1</show_in_store>
89
+ </primary_admin>
90
+ <secondary_admin translate="label comment" module="smsnotify">
91
+ <label>Secondary admin's number</label>
92
+ <frontend_type>text</frontend_type>
93
+ <validate>validate-digits validate-length maximum-length-16</validate>
94
+ <sort_order>10</sort_order>
95
+ <show_in_default>1</show_in_default>
96
+ <show_in_website>1</show_in_website>
97
+ <show_in_store>1</show_in_store>
98
+ </secondary_admin>
99
+ <local_country translate="label comment" module="smsnotify">
100
+ <label>Local country</label>
101
+ <comment>The number in parentheses indicates the dial prefix code of the country.</comment>
102
+ <frontend_type>selectdynamic</frontend_type>
103
+ <frontend_class>country-codes</frontend_class>
104
+ <sort_order>20</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
+ </local_country>
109
+ <min_length_with_prefix translate="label comment" module="smsnotify">
110
+ <label>Add local country code to numbers with digits less than or equal to</label>
111
+ <comment>The customers can insert the phone number with dial prefix or without it to their address. This settings determines whether system have to add dial prefix automatically or not. If you choose for example 9 then there will be add dial prefix of your local country to all numbers with have 9 digits or less. The numbers with 10 digits or more will remain as they are.</comment>
112
+ <frontend_type>selectdynamic</frontend_type>
113
+ <frontend_class>max-number-for-prefix</frontend_class>
114
+ <sort_order>30</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
+ </min_length_with_prefix>
119
+ <used_addresses translate="label comment" module="smsnotify">
120
+ <label>Customer's phone numbers primarily get from</label>
121
+ <comment>If you choose billing address then SMS will be sent to numbers from a billing address and if phone number was not present there then would be used phone numbers from a shipping address and vice versa. If customer's phone number was not found then SMS would not be sent.</comment>
122
+ <frontend_type>select</frontend_type>
123
+ <source_model>smsnotify/system_config_source_addresses</source_model>
124
+ <sort_order>60</sort_order>
125
+ <show_in_default>1</show_in_default>
126
+ <show_in_website>1</show_in_website>
127
+ <show_in_store>1</show_in_store>
128
+ </used_addresses>
129
+ <log translate="label comment" module="smsnotify">
130
+ <label>Log SMS</label>
131
+ <comment>SMS messages would be writen to file 'var/log/smsnotify.log'. Note sending will not be logged when the Magento log is disabled.</comment>
132
+ <frontend_type>select</frontend_type>
133
+ <source_model>smsnotify/system_config_source_log</source_model>
134
+ <sort_order>70</sort_order>
135
+ <show_in_default>1</show_in_default>
136
+ <show_in_website>1</show_in_website>
137
+ <show_in_store>1</show_in_store>
138
+ </log>
139
+ </fields>
140
+ </general>
141
+ <country_filter translate="label comment" module="smsnotify">
142
+ <label>Country Filters</label>
143
+ <frontend_type>text</frontend_type>
144
+ <sort_order>35</sort_order>
145
+ <show_in_default>1</show_in_default>
146
+ <show_in_website>1</show_in_website>
147
+ <show_in_store>1</show_in_store>
148
+ <fields>
149
+ <type translate="label comment" module="smsnotify">
150
+ <label>Allow send message to</label>
151
+ <comment>Countries come from customer's address. Local country you choose above.</comment>
152
+ <frontend_type>select</frontend_type>
153
+ <source_model>smsnotify/system_config_source_countryFilter</source_model>
154
+ <sort_order>25</sort_order>
155
+ <show_in_default>1</show_in_default>
156
+ <show_in_website>1</show_in_website>
157
+ <show_in_store>1</show_in_store>
158
+ </type>
159
+ <specificcountry translate="label comment" module="smsnotify">
160
+ <label>Countries</label>
161
+ <frontend_type>multiselect</frontend_type>
162
+ <sort_order>26</sort_order>
163
+ <source_model>adminhtml/system_config_source_country</source_model>
164
+ <show_in_default>1</show_in_default>
165
+ <show_in_website>1</show_in_website>
166
+ <show_in_store>1</show_in_store>
167
+ <depends><type>specific</type></depends>
168
+ </specificcountry>
169
+ </fields>
170
+ </country_filter>
171
+ <filter translate="label comment" module="smsnotify">
172
+ <label>Number Filters</label>
173
+ <frontend_type>text</frontend_type>
174
+ <sort_order>40</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
+ <fields>
179
+ <exclude translate="label comment" module="smsnotify">
180
+ <label>Exclude numbers</label>
181
+ <comment>Here you can select number patterns/range which you do not wish send SMS to. If you want to send SMS to any number leave this table empty.</comment>
182
+ <frontend_type>numberfilters</frontend_type>
183
+ <sort_order>40</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
+ </exclude>
188
+ <include translate="label comment" module="smsnotify">
189
+ <label>Include numbers</label>
190
+ <comment>Here you can add the exceptions from "Exclude numbers" field.</comment>
191
+ <frontend_type>numberfilters</frontend_type>
192
+ <sort_order>50</sort_order>
193
+ <show_in_default>1</show_in_default>
194
+ <show_in_website>1</show_in_website>
195
+ <show_in_store>1</show_in_store>
196
+ </include>
197
+ </fields>
198
+ </filter>
199
+ <new_order translate="label comment" module="smsnotify">
200
+ <label>New Order</label>
201
+ <frontend_type>text</frontend_type>
202
+ <sort_order>50</sort_order>
203
+ <show_in_default>1</show_in_default>
204
+ <show_in_website>1</show_in_website>
205
+ <show_in_store>1</show_in_store>
206
+ <fields>
207
+ <enabled translate="label comment" module="smsnotify">
208
+ <label>Notify when new order is placed</label>
209
+ <frontend_type>select</frontend_type>
210
+ <source_model>adminhtml/system_config_source_yesno</source_model>
211
+ <sort_order>10</sort_order>
212
+ <show_in_default>1</show_in_default>
213
+ <show_in_website>1</show_in_website>
214
+ <show_in_store>1</show_in_store>
215
+ </enabled>
216
+ <to_customer translate="label comment" module="smsnotify">
217
+ <label>Notify customer</label>
218
+ <frontend_type>select</frontend_type>
219
+ <source_model>adminhtml/system_config_source_yesno</source_model>
220
+ <sort_order>20</sort_order>
221
+ <show_in_default>1</show_in_default>
222
+ <show_in_website>1</show_in_website>
223
+ <show_in_store>1</show_in_store>
224
+ <depends><enabled>1</enabled></depends>
225
+ </to_customer>
226
+ <to_admin translate="label comment" module="smsnotify">
227
+ <label>Notify admin</label>
228
+ <frontend_type>select</frontend_type>
229
+ <source_model>smsnotify/system_config_source_sendToAdmin</source_model>
230
+ <sort_order>30</sort_order>
231
+ <show_in_default>1</show_in_default>
232
+ <show_in_website>1</show_in_website>
233
+ <show_in_store>1</show_in_store>
234
+ <depends><enabled>1</enabled></depends>
235
+ </to_admin>
236
+ <sms_text translate="label comment" module="smsnotify">
237
+ <label>SMS text</label>
238
+ <frontend_type>smstextarea</frontend_type>
239
+ <sort_order>40</sort_order>
240
+ <show_in_default>1</show_in_default>
241
+ <show_in_website>1</show_in_website>
242
+ <show_in_store>1</show_in_store>
243
+ <depends><enabled>1</enabled></depends>
244
+ </sms_text>
245
+ </fields>
246
+ </new_order>
247
+ <new_invoice translate="label comment" module="smsnotify">
248
+ <label>New Invoice</label>
249
+ <frontend_type>text</frontend_type>
250
+ <sort_order>60</sort_order>
251
+ <show_in_default>1</show_in_default>
252
+ <show_in_website>1</show_in_website>
253
+ <show_in_store>1</show_in_store>
254
+ <fields>
255
+ <enabled translate="label comment" module="smsnotify">
256
+ <label>Notify when new invoice is created</label>
257
+ <frontend_type>select</frontend_type>
258
+ <source_model>adminhtml/system_config_source_yesno</source_model>
259
+ <sort_order>10</sort_order>
260
+ <show_in_default>1</show_in_default>
261
+ <show_in_website>1</show_in_website>
262
+ <show_in_store>1</show_in_store>
263
+ </enabled>
264
+ <to_customer translate="label comment" module="smsnotify">
265
+ <label>Notify customer</label>
266
+ <frontend_type>select</frontend_type>
267
+ <source_model>adminhtml/system_config_source_yesno</source_model>
268
+ <sort_order>20</sort_order>
269
+ <show_in_default>1</show_in_default>
270
+ <show_in_website>1</show_in_website>
271
+ <show_in_store>1</show_in_store>
272
+ <depends><enabled>1</enabled></depends>
273
+ </to_customer>
274
+ <to_admin translate="label comment" module="smsnotify">
275
+ <label>Notify admin</label>
276
+ <frontend_type>select</frontend_type>
277
+ <source_model>smsnotify/system_config_source_sendToAdmin</source_model>
278
+ <sort_order>30</sort_order>
279
+ <show_in_default>1</show_in_default>
280
+ <show_in_website>1</show_in_website>
281
+ <show_in_store>1</show_in_store>
282
+ <depends><enabled>1</enabled></depends>
283
+ </to_admin>
284
+ <sms_text translate="label comment" module="smsnotify">
285
+ <label>SMS text</label>
286
+ <frontend_type>smstextarea</frontend_type>
287
+ <sort_order>40</sort_order>
288
+ <show_in_default>1</show_in_default>
289
+ <show_in_website>1</show_in_website>
290
+ <show_in_store>1</show_in_store>
291
+ <depends><enabled>1</enabled></depends>
292
+ </sms_text>
293
+ </fields>
294
+ </new_invoice>
295
+ <new_shipment translate="label comment" module="smsnotify">
296
+ <label>New Shipment</label>
297
+ <frontend_type>text</frontend_type>
298
+ <sort_order>70</sort_order>
299
+ <show_in_default>1</show_in_default>
300
+ <show_in_website>1</show_in_website>
301
+ <show_in_store>1</show_in_store>
302
+ <fields>
303
+ <enabled translate="label comment" module="smsnotify">
304
+ <label>Notify when new shipment is created</label>
305
+ <frontend_type>select</frontend_type>
306
+ <source_model>adminhtml/system_config_source_yesno</source_model>
307
+ <sort_order>10</sort_order>
308
+ <show_in_default>1</show_in_default>
309
+ <show_in_website>1</show_in_website>
310
+ <show_in_store>1</show_in_store>
311
+ </enabled>
312
+ <to_customer translate="label comment" module="smsnotify">
313
+ <label>Notify customer</label>
314
+ <frontend_type>select</frontend_type>
315
+ <source_model>adminhtml/system_config_source_yesno</source_model>
316
+ <sort_order>20</sort_order>
317
+ <show_in_default>1</show_in_default>
318
+ <show_in_website>1</show_in_website>
319
+ <show_in_store>1</show_in_store>
320
+ <depends><enabled>1</enabled></depends>
321
+ </to_customer>
322
+ <to_admin translate="label comment" module="smsnotify">
323
+ <label>Notify admin</label>
324
+ <frontend_type>select</frontend_type>
325
+ <source_model>smsnotify/system_config_source_sendToAdmin</source_model>
326
+ <sort_order>30</sort_order>
327
+ <show_in_default>1</show_in_default>
328
+ <show_in_website>1</show_in_website>
329
+ <show_in_store>1</show_in_store>
330
+ <depends><enabled>1</enabled></depends>
331
+ </to_admin>
332
+ <sms_text translate="label comment" module="smsnotify">
333
+ <label>SMS text</label>
334
+ <frontend_type>smstextarea</frontend_type>
335
+ <sort_order>40</sort_order>
336
+ <show_in_default>1</show_in_default>
337
+ <show_in_website>1</show_in_website>
338
+ <show_in_store>1</show_in_store>
339
+ <depends><enabled>1</enabled></depends>
340
+ </sms_text>
341
+ </fields>
342
+ </new_shipment>
343
+ </groups>
344
+ </smsnotify>
345
+ </sections>
346
+ </config>
app/design/adminhtml/default/default/layout/smsnotify.xml ADDED
@@ -0,0 +1,98 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * SMS Notifier
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Academic Free License (AFL 3.0)
9
+ * It is available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ *
12
+ * @category Artio
13
+ * @package Artio_SMSNotifier
14
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
15
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
16
+ */
17
+ -->
18
+ <layout version="0.1.0">
19
+ <!--
20
+ Default layout, loads most of the pages
21
+ -->
22
+
23
+ <smsnotify_adminhtml_index>
24
+ <reference name="head">
25
+ <action method="addCss"><name>smsnotify.css</name></action>
26
+ </reference>
27
+ <reference name="content">
28
+ <block type="smsnotify/adminhtml_send" name="smsnotify" >
29
+ <block type="smsnotify/adminhtml_send_form" name="form" />
30
+ </block>
31
+ </reference>
32
+ </smsnotify_adminhtml_index>
33
+
34
+ <adminhtml_system_config_edit>
35
+ <reference name="head">
36
+ <action method="addCss"><name>smsnotify.css</name></action>
37
+ </reference>
38
+ <reference name="head">
39
+ <action method="addJs"><script>artio/numberfilters.js</script></action>
40
+ <action method="addCss"><name>smsnotify.css</name></action>
41
+ </reference>
42
+ </adminhtml_system_config_edit>
43
+
44
+ <adminhtml_sales_order_view>
45
+ <reference name="head">
46
+ <action method="addCss"><name>smsnotify.css</name></action>
47
+ </reference>
48
+ <reference name="order_history">
49
+ <action method="setTemplate"><template>smsnotify/order/view/history.phtml</template></action>
50
+ </reference>
51
+ </adminhtml_sales_order_view>
52
+
53
+ <adminhtml_sales_order_invoice_view>
54
+ <reference name="head">
55
+ <action method="addCss"><name>smsnotify.css</name></action>
56
+ </reference>
57
+ <reference name="order_comments">
58
+ <action method="setTemplate"><template>smsnotify/order/comments/view.phtml</template></action>
59
+ </reference>
60
+ </adminhtml_sales_order_invoice_view>
61
+
62
+ <adminhtml_sales_order_shipment_view>
63
+ <reference name="head">
64
+ <action method="addCss"><name>smsnotify.css</name></action>
65
+ </reference>
66
+ <reference name="order_comments">
67
+ <action method="setTemplate"><template>smsnotify/order/comments/view.phtml</template></action>
68
+ </reference>
69
+ </adminhtml_sales_order_shipment_view>
70
+
71
+ <adminhtml_sales_order_addcomment>
72
+ <reference name="head">
73
+ <action method="addCss"><name>smsnotify.css</name></action>
74
+ </reference>
75
+ <reference name="order_history">
76
+ <action method="setTemplate"><template>smsnotify/order/view/history.phtml</template></action>
77
+ </reference>
78
+ </adminhtml_sales_order_addcomment>
79
+
80
+ <adminhtml_sales_order_invoice_addcomment>
81
+ <reference name="head">
82
+ <action method="addCss"><name>smsnotify.css</name></action>
83
+ </reference>
84
+ <reference name="order_comments">
85
+ <action method="setTemplate"><template>smsnotify/order/comments/view.phtml</template></action>
86
+ </reference>
87
+ </adminhtml_sales_order_invoice_addcomment>
88
+
89
+ <adminhtml_sales_order_shipment_addcomment>
90
+ <reference name="head">
91
+ <action method="addCss"><name>smsnotify.css</name></action>
92
+ </reference>
93
+ <reference name="order_comments">
94
+ <action method="setTemplate"><template>smsnotify/order/comments/view.phtml</template></action>
95
+ </reference>
96
+ </adminhtml_sales_order_shipment_addcomment>
97
+
98
+ </layout>
app/design/adminhtml/default/default/template/smsnotify/order/comments/view.phtml ADDED
@@ -0,0 +1,97 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * Magento
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * that is bundled with this package in the file LICENSE_AFL.txt.
9
+ * It is also available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ * If you did not receive a copy of the license and are unable to
12
+ * obtain it through the world-wide-web, please send an email
13
+ * to license@magentocommerce.com so we can send you a copy immediately.
14
+ *
15
+ * DISCLAIMER
16
+ *
17
+ * Do not edit or add to this file if you wish to upgrade Magento to newer
18
+ * versions in the future. If you wish to customize Magento for your
19
+ * needs please refer to http://www.magentocommerce.com for more information.
20
+ *
21
+ * @category design
22
+ * @package default_default
23
+ * @copyright Copyright (c) 2012 Magento Inc. (http://www.magentocommerce.com)
24
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
25
+ */
26
+ ?>
27
+ <?php if ($_entity = $this->getEntity()): ?>
28
+ <div id="comments_block">
29
+ <span class="field-row">
30
+ <label class="normal" for="history_comment"><?php echo Mage::helper('sales')->__('Comment Text') ?></label>
31
+ <textarea name="comment[comment]" rows="3" cols="5" style="height:6em; width:99%;" id="history_comment"></textarea>
32
+ </span>
33
+ <div class="f-left">
34
+ <?php if ($this->canSendCommentEmail()): ?>
35
+ <input name="comment[is_customer_notified]" type="checkbox" id="history_notify" value="1" />
36
+ <label class="normal" for="history_notify"><?php echo Mage::helper('sales')->__('Notify Customer by Email') ?></label><br />
37
+ <?php endif; ?>
38
+ <input name="comment[is_visible_on_front]" type="checkbox" id="history_visible" value="1" /><label class="normal" for="history_visible"> <?php echo Mage::helper('sales')->__('Visible on Frontend') ?></label>
39
+ </div>
40
+ <div class="f-right">
41
+ <?php echo $this->getChildHtml('submit_button') ?>
42
+ </div>
43
+ <div class="clear"></div>
44
+ <ul class="note-list">
45
+ <?php foreach ($_entity->getCommentsCollection(true) as $_comment): ?>
46
+ <?php
47
+ $text = $_comment->getComment();
48
+
49
+ if ($text && strpos($text, Artio_SMSNotifier_Helper_Data::SMS_MARK) === 0)
50
+ {
51
+ $sms = true;
52
+ $parts = explode(';', $text);
53
+ $role = $parts[1];
54
+ $send = $parts[2];
55
+ $text = implode(';', array_slice($parts, 3));
56
+ }
57
+ ?>
58
+ <li <?php if (isset($sms)) echo 'class="mobil"' ?> >
59
+ <strong><?php echo $this->helper('core')->formatDate($_comment->getCreatedAtDate(), 'medium') ?></strong>
60
+ <?php echo $this->helper('core')->formatTime($_comment->getCreatedAtDate(), 'medium') ?><span class="separator">|</span><small>
61
+ <?php if (isset($role)): ?>
62
+ <?php echo $this->escapeHtml($role) ?>
63
+ <?php else: ?>
64
+ <?php echo $this->helper('sales')->__('Customer') ?>
65
+ <?php endif ?>
66
+ <strong class="subdue">
67
+ <?php if ($_comment->getIsCustomerNotified()): ?>
68
+ <?php echo $this->helper('sales')->__('Notified') ?>
69
+ <img src="<?php echo $this->getSkinUrl('images/ico_success.gif') ?>" width="16" height="16" alt="" />
70
+ <?php elseif (isset($send) && $send == 0): ?>
71
+ <?php echo $this->helper('sales')->__('Not Notified') ?>
72
+ <!--img style="position:relative;top:2px;" src="<?php // echo $this->getSkinUrl('images/ico_mobil.png') ?>" width="16" height="16" alt="" /-->
73
+ <img style="position:relative;top:2px;" src="<?php echo $this->getSkinUrl('images/error_msg_icon.gif') ?>" width="16" height="16" alt="" />
74
+ <?php elseif (isset($send) && $send == 1): ?>
75
+ <?php echo $this->helper('sales')->__('Notified') ?>
76
+ <!--img style="position:relative;top:2px;" src="<?php // echo $this->getSkinUrl('images/ico_mobil.png') ?>" width="16" height="16" alt="" /-->
77
+ <img src="<?php echo $this->getSkinUrl('images/ico_success.gif') ?>" width="16" height="16" alt="" />
78
+ <?php else: ?>
79
+ <?php echo $this->helper('sales')->__('Not Notified') ?>
80
+ <?php endif; ?>
81
+ </strong></small>
82
+ <br/>
83
+ <?php echo $this->escapeHtml($text, array('b','br','strong','i','u')) ?>
84
+ </li>
85
+ <?php endforeach; ?>
86
+ </ul>
87
+ <script type="text/javascript">
88
+ function submitComment() {
89
+ submitAndReloadArea($('comments_block').parentNode, '<?php echo $this->getSubmitUrl() ?>')
90
+ }
91
+
92
+ if ($('submit_comment_button')) {
93
+ $('submit_comment_button').observe('click', submitComment);
94
+ }
95
+ </script>
96
+ </div>
97
+ <?php endif; ?>
app/design/adminhtml/default/default/template/smsnotify/order/view/history.phtml ADDED
@@ -0,0 +1,196 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+ ?>
17
+ <?php
18
+
19
+ $suburl = Mage::helper("adminhtml")->getUrl('smsnotify/adminhtml/smscomment', array('order_id' => $this->getOrder()->getId()));
20
+ $onclick = "submitAndReloadArea($('order_history_block').parentNode, '".$suburl."')";
21
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button')->setData(array(
22
+ 'label' => Mage::helper('smsnotify')->__('Send SMS'),
23
+ 'class' => 'save',
24
+ 'onclick' => $onclick
25
+ ));
26
+ $this->setChild('sms_button', $button);
27
+
28
+ $this->unsetChild('submit_button');
29
+ $suburl = Mage::helper("adminhtml")->getUrl('adminhtml/sales_order/addComment', array('order_id' => $this->getOrder()->getId()));
30
+ $onclick = "submitAndReloadArea($('order_history_block').parentNode, '".$suburl."')";
31
+ $button = $this->getLayout()->createBlock('adminhtml/widget_button')->setData(array(
32
+ 'label' => Mage::helper('sales')->__('Submit Comment'),
33
+ 'class' => 'save',
34
+ 'onclick' => $onclick
35
+ ));
36
+ $this->setChild('submit_button', $button);
37
+
38
+ ?>
39
+ <div id="order_history_block">
40
+
41
+ <?php if ($this->canAddComment()):?>
42
+ <div id="history_form" class="order-history-form">
43
+ <div><?php echo Mage::helper('sales')->__('Add Order Comments') ?></div>
44
+ <span class="field-row status-field-row">
45
+ <label class="normal" for="history_status"><?php echo Mage::helper('sales')->__('Status') ?></label><br/>
46
+ <select name="history[status]" class="select" id="history_status">
47
+ <?php foreach ($this->getStatuses() as $_code=>$_label): ?>
48
+ <option value="<?php echo $_code ?>"<?php if($_code==$this->getOrder()->getStatus()): ?> selected="selected"<?php endif; ?>><?php echo $_label ?></option>
49
+ <?php endforeach; ?>
50
+ </select>
51
+ </span>
52
+
53
+ <div class="menu">
54
+ <div class="menu-item first" id="menu-item-comment" ><?php echo Mage::helper('sales')->__('Comment') ?></div>
55
+ <div class="menu-item" id="menu-item-sms"><?php echo Mage::helper('smsnotify')->__('SMS') ?></div>
56
+ </div>
57
+
58
+ <div class="clear"></div>
59
+
60
+ <div id="history-comment" class="history-form">
61
+ <span class="field-row">
62
+ <label class="normal" for="history_comment"><?php echo Mage::helper('sales')->__('Comment') ?></label>
63
+ <textarea name="history[comment]" rows="3" cols="5" style="height:6em; width:99%;" id="history_comment"></textarea>
64
+ </span>
65
+ <div class="f-left">
66
+ <?php if ($this->canSendCommentEmail()): ?>
67
+ <input name="history[is_customer_notified]" type="checkbox" id="history_notify" value="1" /><label class="normal" for="history_notify"> <?php echo Mage::helper('sales')->__('Notify Customer by Email') ?></label><br />
68
+ <?php endif; ?>
69
+ <input name="history[is_visible_on_front]" type="checkbox" id="history_visible" value="1" /><label class="normal" for="history_visible"> <?php echo Mage::helper('sales')->__('Visible on Frontend') ?></label>
70
+ </div>
71
+ <div class="f-right">
72
+ <?php echo $this->getChildHtml('submit_button') ?>
73
+ </div>
74
+ <div class="clear"></div>
75
+ </div>
76
+
77
+
78
+
79
+ <div id="history-sms" class="history-form">
80
+ <span class="field-row">
81
+ <?php $control = new Varien_Data_Form_Element_Smstextarea(array('html_id'=>'sms_comment', 'name'=>'sms_comment')) ?>
82
+ <?php echo $control->getElementHtml() ?>
83
+ </span>
84
+ <div class="f-right">
85
+ <?php echo $this->getChildHtml('sms_button') ?>
86
+ </div>
87
+ <div class="clear"></div>
88
+ </div>
89
+
90
+ <script type="text/javascript">
91
+ //<![CDATA[
92
+
93
+ if ((typeof(last_button_sms) == "undefined") || !last_button_sms)
94
+ {
95
+ $('menu-item-comment').addClassName('active');
96
+ $('history-sms').hide();
97
+ }
98
+ else
99
+ {
100
+ $('menu-item-sms').addClassName('active');
101
+ $('history-comment').hide();
102
+ }
103
+
104
+ $$('#history-comment button').first().observe('click', function(event) {
105
+ last_button_sms = false;
106
+ });
107
+
108
+ $$('#history-sms button').first().observe('click', function(event) {
109
+ last_button_sms = true;
110
+ });
111
+
112
+ $('menu-item-comment').observe('click', function(event) {
113
+ $('history-sms').hide();
114
+ $('menu-item-sms').removeClassName('active');
115
+ $('history-comment').show();
116
+ $('menu-item-comment').addClassName('active');
117
+ });
118
+ $('menu-item-sms').observe('click', function(event) {
119
+ $('history-comment').hide();
120
+ $('menu-item-comment').removeClassName('active');
121
+ $('history-sms').show();
122
+ $('menu-item-sms').addClassName('active');
123
+ });
124
+ sms_comment_smstextarea_reloading();
125
+ //]]>
126
+ </script>
127
+
128
+ <div class="clear"></div>
129
+ </div>
130
+ <div class="divider"></div>
131
+ <?php endif;?>
132
+
133
+
134
+ <ul class="note-list">
135
+ <?php foreach ($this->getOrder()->getStatusHistoryCollection(true) as $_item): ?>
136
+ <?php
137
+ $comment = $_item->getComment();
138
+
139
+ if ($comment && strpos($comment, Artio_SMSNotifier_Helper_Data::SMS_MARK) === 0)
140
+ {
141
+ $sms = true;
142
+ $parts = explode(';', $comment);
143
+ $role = $parts[1];
144
+ $send = $parts[2];
145
+ $comment = implode(';', array_slice($parts, 3));
146
+ }
147
+ else
148
+ {
149
+ unset($sms);
150
+ unset($parts);
151
+ unset($role);
152
+ unset($send);
153
+ }
154
+ ?>
155
+ <li <?php if (isset($sms)) echo 'class="mobil"' ?> >
156
+ <strong><?php echo $this->helper('core')->formatDate($_item->getCreatedAtDate(), 'medium') ?></strong>
157
+ <?php echo $this->helper('core')->formatTime($_item->getCreatedAtDate(), 'medium') ?>
158
+ <?php if ($_item->getStatusLabel()): ?>
159
+ <span class="separator">|</span><strong><?php echo $_item->getStatusLabel() ?></strong>
160
+ <?php endif ?>
161
+ <br/>
162
+ <small>
163
+ <?php if (isset($role)): ?>
164
+ <?php echo $this->escapeHtml($role) ?>
165
+ <?php else: ?>
166
+ <?php echo $this->helper('sales')->__('Customer') ?>
167
+ <?php endif ?>
168
+ <strong class="subdue">
169
+ <?php if ($this->isCustomerNotificationNotApplicable($_item)): ?>
170
+ <?php echo $this->helper('sales')->__('Notification Not Applicable') ?>
171
+ <?php elseif (isset($send) && $send == 0): ?>
172
+ <?php echo $this->helper('sales')->__('Not Notified') ?>
173
+ <!--<img style="position:relative;top:2px;" src="<?php // echo $this->getSkinUrl('images/ico_mobil.png') ?>" width="16" height="16" alt="" /-->
174
+ <img style="position:relative;top:2px;" src="<?php echo $this->getSkinUrl('images/error_msg_icon.gif') ?>" width="16" height="16" alt="" />
175
+ <?php elseif (isset($send) && $send == 1): ?>
176
+ <?php echo $this->helper('sales')->__('Notified') ?>
177
+ <!--img style="position:relative;top:2px;" src="<?php // echo $this->getSkinUrl('images/ico_mobil.png') ?>" width="16" height="16" alt="" /-->
178
+ <img src="<?php echo $this->getSkinUrl('images/ico_success.gif') ?>" width="16" height="16" alt="" />
179
+ <?php elseif ($_item->getIsCustomerNotified()): ?>
180
+ <?php echo $this->helper('sales')->__('Notified') ?>
181
+ <img src="<?php echo $this->getSkinUrl('images/ico_success.gif') ?>" width="16" height="16" alt="" />
182
+ <?php else: ?>
183
+ <?php echo $this->helper('sales')->__('Not Notified') ?>
184
+ <?php endif; ?>
185
+ </strong>
186
+ </small>
187
+ <?php if ($comment): ?>
188
+ <br/><?php echo $this->escapeHtml($comment, array('b','br','strong','i','u')) ?>
189
+ <?php endif; ?>
190
+ </li>
191
+ <?php endforeach; ?>
192
+ </ul>
193
+ <script type="text/javascript">
194
+ if($('order_status'))$('order_status').update('<?php echo $this->getOrder()->getStatusLabel() ?>');
195
+ </script>
196
+ </div>
app/etc/modules/Artio_SMSNotifyForMagento.xml ADDED
@@ -0,0 +1,29 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /**
4
+ * SMS Notifier
5
+ *
6
+ * NOTICE OF LICENSE
7
+ *
8
+ * This source file is subject to the Academic Free License (AFL 3.0)
9
+ * It is available through the world-wide-web at this URL:
10
+ * http://opensource.org/licenses/afl-3.0.php
11
+ *
12
+ * @category Artio
13
+ * @package Artio_SMSNotifier
14
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
15
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
16
+ */
17
+ -->
18
+ <config>
19
+ <modules>
20
+ <Artio_SMSNotifier>
21
+ <active>true</active>
22
+ <codePool>community</codePool>
23
+ </Artio_SMSNotifier>
24
+ <depends>
25
+ <Mage_Core />
26
+ <Mage_Sales />
27
+ </depends>
28
+ </modules>
29
+ </config>
js/artio/numberfilters.js ADDED
@@ -0,0 +1,1385 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * Setup select.
3
+ */
4
+ document.observe('dom:loaded', function(event) {
5
+ var select = $('smsnotify_general_local_country');
6
+ var hidden = $('smsnotify_general_local_country-hidden');
7
+
8
+ if (select && hidden)
9
+ {
10
+ select.childElements().each(function(option, index) {
11
+ if (option.value == hidden.value)
12
+ select.selectedIndex = index;
13
+ });
14
+ }
15
+
16
+ var select = $('smsnotify_general_min_length_with_prefix');
17
+ var hidden = $('smsnotify_general_min_length_with_prefix-hidden');
18
+
19
+ if (select && hidden)
20
+ {
21
+ select.childElements().each(function(option, index) {
22
+ if (option.value == hidden.value)
23
+ select.selectedIndex = index;
24
+ });
25
+ }
26
+ });
27
+
28
+
29
+ /**
30
+ * Number Filters Util
31
+ * Library of some useful functions which is missing
32
+ * in the standard JavaScript.
33
+ */
34
+ NFU = {
35
+
36
+
37
+ /**
38
+ * Function walks through all element's in the list and calls
39
+ * callback whith item and index as arguments.
40
+ *
41
+ * If list or callback is not specifie function
42
+ * does nothing.
43
+ */
44
+ each: function(list, callback)
45
+ {
46
+ if (!list || !callback)
47
+ return;
48
+
49
+ for (var i=0; i<list.length; i++)
50
+ callback(list[i], i);
51
+ },
52
+
53
+
54
+ /**
55
+ * Function returns first item of a list which satisfies a condition.
56
+ * Condition is a function which returns a bool value (true/false).
57
+ *
58
+ * If the condition is not defined function returns first
59
+ * item of array.
60
+ *
61
+ * If list is not specified or any child does not satisfy
62
+ * the condition then function returns null.
63
+ */
64
+ first: function(list, condition)
65
+ {
66
+ if (!list)
67
+ return null;
68
+
69
+ if (!condition)
70
+ condition = function() { return true; }
71
+
72
+ for (var i=0; i<list.length; i++)
73
+ if (condition(list[i]))
74
+ return list[i];
75
+
76
+ return null;
77
+ },
78
+
79
+
80
+ /**
81
+ * Function returns last item of a list which satisfies a condition.
82
+ *
83
+ * If the condition is not defined then function returns last
84
+ * item of array.
85
+ *
86
+ * If the list is not specified or any child does not satisfy
87
+ * the condition then function returns null.
88
+ */
89
+ last: function(list, condition)
90
+ {
91
+ if (!list)
92
+ return null;
93
+
94
+ if (!condition)
95
+ condition = function() { return true; }
96
+
97
+ var lastsatisfy = null;
98
+
99
+ for (var i=0; i<list.length; i++)
100
+ if (condition(list[i]))
101
+ lastsatisfy = list[i];
102
+
103
+ return lastsatisfy;
104
+ },
105
+
106
+
107
+ /**
108
+ * Function walk through all chars in a string and
109
+ * call a callback on each.
110
+ *
111
+ * You can walk forward (reverse = false) or
112
+ * backward (reverse = true).
113
+ *
114
+ * If string or the callback is not defined function
115
+ * does nothing.
116
+ */
117
+ eachChars: function(string, reverse, callback)
118
+ {
119
+ if (!string || !callback)
120
+ return;
121
+
122
+ var start = reverse ? string.length-1 : 0;
123
+ var end = reverse ? 0 : string.length;
124
+ var step = reverse ? -1 : +1;
125
+
126
+ for (i=start; i!=end; i=i+step) {
127
+ callback(string.charAt(i), i);
128
+ }
129
+ },
130
+
131
+
132
+ /**
133
+ * Function walks through all childs of an element
134
+ * with specified a tagNam and call a callable
135
+ * on each.
136
+ *
137
+ * Callable is a function.
138
+ *
139
+ * If tagName is not specified function walks
140
+ * through all chidls (include text nodes).
141
+ *
142
+ * If the element or the callable is not specified
143
+ * function does nothing.
144
+ */
145
+ eachChilds: function(element, tagName, callable)
146
+ {
147
+ if (!element || !callable)
148
+ return;
149
+
150
+ var childs = NFU.getChilds(element, tagName);
151
+ NFU.each(childs, callable);
152
+ },
153
+
154
+
155
+ /**
156
+ * Function get first element with tagName which
157
+ * satisfy a condition.
158
+ *
159
+ * If tagName is not specified function returns
160
+ * any first element which satisfy a condition.
161
+ *
162
+ * If the condition is not defined function returns
163
+ * first element withot testing.
164
+ *
165
+ * If element is not specified function does nothing.
166
+ */
167
+ firstChild: function(element, tagName, condition)
168
+ {
169
+ var childs = NFU.getChilds(element, tagName);
170
+ return NFU.first(childs, condition);
171
+ },
172
+
173
+
174
+ /**
175
+ * Function get last element with tagName which
176
+ * satisfy a condition.
177
+ *
178
+ * If tagName is not specified function returns
179
+ * any last element which satisfy a condition.
180
+ *
181
+ * If the condition is not defined function returns
182
+ * last element withot testing.
183
+ *
184
+ * If element is not specified function does nothing.
185
+ */
186
+ lastChild: function(element, tagName, condition)
187
+ {
188
+ var childs = NFU.getChilds(element, tagName);
189
+ return NFU.last(childs, condition);
190
+ },
191
+
192
+
193
+ /**
194
+ * Function get first parent with tagName.
195
+ *
196
+ * If element is not define or there is no
197
+ * parent with specified tagName function returns
198
+ * null.
199
+ *
200
+ * If tagName is not specified method retruns
201
+ * first parent no matter tagName.
202
+ */
203
+ firstParent: function(element, tagName)
204
+ {
205
+ if (!element)
206
+ return null;
207
+
208
+ var parent = element.parentNode;
209
+
210
+ while (parent && tagName && parent.tagName != tagName)
211
+ parent = parent.parentNode;
212
+
213
+ if (parent && tagName && parent.tagName == tagName)
214
+ return parent;
215
+ else
216
+ return null;
217
+ },
218
+
219
+
220
+ /**
221
+ * Function rerurns all element's childrens.
222
+ *
223
+ * Note searching is non-recursive there are returned only
224
+ * childrens in the first "generations".
225
+ *
226
+ * You can restrict visited childrens by tag name.
227
+ *
228
+ * If tag name is not specified function returns all
229
+ * childrens (e.g: text nodes)
230
+ *
231
+ * If element is not specifie function
232
+ * does nothing.
233
+ */
234
+ getChilds: function(element, tagName)
235
+ {
236
+ if (!element)
237
+ return;
238
+
239
+ var result = [];
240
+
241
+ for (var i=0; i<element.childNodes.length; i++)
242
+ {
243
+ if (!tagName || (element.childNodes[i].tagName == tagName))
244
+ {
245
+ result.push(element.childNodes[i]);
246
+ }
247
+ }
248
+
249
+ return result;
250
+ },
251
+
252
+
253
+ /**
254
+ * Function rerurns all element's childrens.
255
+ *
256
+ * Note searching is recursive (deep) there are returned all
257
+ * childrens.
258
+ *
259
+ * You can restrict visited childrens by tag name.
260
+ *
261
+ * If tag name is not specified function returns all
262
+ * childrens (e.g: text nodes)
263
+ *
264
+ * If element is not specifie function
265
+ * does nothing.
266
+ */
267
+ getChildsRecursively: function(element, tagName)
268
+ {
269
+ if (!element)
270
+ return;
271
+
272
+ var result = [];
273
+
274
+ for (var i=0; i<element.childNodes.length; i++)
275
+ {
276
+ if (!tagName || (element.childNodes[i].tagName == tagName))
277
+ {
278
+ result.push(element.childNodes[i]);
279
+ }
280
+
281
+ NFU.each(NFU.getChildsRecursively(element.childNodes[i], tagName), function(child) {
282
+ result.push(child);
283
+ });
284
+ }
285
+
286
+ return result;
287
+ },
288
+
289
+
290
+ /**
291
+ * Function returns all element which satisfy className
292
+ * and tagName.
293
+ *
294
+ * Argument className is mandatory, if missing function
295
+ * returns empty array.
296
+ *
297
+ * Argument tagName is optional.
298
+ */
299
+ getElementsByClassName: function(className, tagName)
300
+ {
301
+ if (!className)
302
+ return [];
303
+
304
+ if (!tagName)
305
+ tagName = '*';
306
+
307
+ var result = [];
308
+
309
+ var elements = document.getElementsByTagName(tagName);
310
+
311
+ for (var i=0; i<elements.length; i++)
312
+ if (NFU.hasClassName(elements[i], className))
313
+ result.push(elements[i]);
314
+
315
+ return result;
316
+ },
317
+
318
+
319
+ /**
320
+ * Function determines whether element's attribute
321
+ * "className" contains a className or not
322
+ *
323
+ * element - tested element
324
+ * className - tested className
325
+ *
326
+ * Function returns true when element's attribute "className"
327
+ * contains className, otherwise function returns false.
328
+ *
329
+ * If element or className is not defined function returns false.
330
+ */
331
+ hasClassName: function(element, className)
332
+ {
333
+ if (!element || !className)
334
+ return false;
335
+
336
+ var reg = new RegExp("(^|\\s)" + className + "(\\s|$)");
337
+
338
+ return reg.test(element.className);
339
+ },
340
+
341
+
342
+ /**
343
+ * Function remove a className from the class attribute
344
+ * of an element.
345
+ *
346
+ * If element or className is not specified function
347
+ * does nothing.
348
+ */
349
+ removeClassName: function(element, className)
350
+ {
351
+ if (!element || !className)
352
+ return;
353
+
354
+ element.className = element.className.replace(className, '');
355
+ },
356
+
357
+
358
+ /**
359
+ * Function add a className to an element.
360
+ *
361
+ * If element or className is not specified or element
362
+ * already has className function does nothing.
363
+ */
364
+ addClassName: function(element, className)
365
+ {
366
+ if (!element || !className)
367
+ return false;
368
+
369
+ if (!NFU.hasClassName(element, className))
370
+ element.className = element.className + " " + className;
371
+ }
372
+
373
+
374
+ };
375
+
376
+
377
+ /**
378
+ *
379
+ */
380
+ function FilterTable(id, filters)
381
+ {
382
+ /* this instance */
383
+ var self = this;
384
+
385
+
386
+ /* if of element TABLE represented this filters */
387
+ this.id = id;
388
+
389
+
390
+ /* instance of ancestor object */
391
+ this.filters = filters;
392
+
393
+
394
+ /* TABLE element represented this filters */
395
+ this.table = document.getElementById(id);
396
+ /* ROW element which is template for making another rows */
397
+ this.template_row = document.getElementById(id+'-template');
398
+ /* INPUT fields where are stored serialized values */
399
+ this.field = document.getElementById(id+'-field');
400
+ /* SELECT element with countries (you can switch the lists of filters by this) */
401
+ this.country_select = document.getElementById(this.id+'-country');
402
+
403
+
404
+ /**
405
+ * Internal data.
406
+ * Here are stored rows for all countries. This is important
407
+ * because there may be filters for not selected country.
408
+ *
409
+ * {
410
+ * country1 => [row1, row2, ...],
411
+ * country2 => [row1, row2, ...]
412
+ * ...
413
+ * }
414
+ */
415
+ this.data = {};
416
+
417
+
418
+ /**
419
+ * Add filter to table for a country. If the country
420
+ * is not specified function gets current displayed country.
421
+ *
422
+ * This function makes a TR element for filter and
423
+ * insert it to internal this.data.
424
+ *
425
+ * If there is displayed the country which is
426
+ * the inserted filter assigned for then the row
427
+ * is appended to table.
428
+ *
429
+ * Function does not validate filter.
430
+ * Function does not check the duplicity.
431
+ */
432
+ this.addFilter = function(filter, country)
433
+ {
434
+ // country is not specified, get current displayed
435
+ if (!country)
436
+ country = this.getCurrentCountry();
437
+
438
+ // create new row by template
439
+ var newrow = this.template_row.cloneNode(true);
440
+
441
+ // clear some attributes
442
+ newrow.id = "";
443
+ newrow.style.display = "";
444
+
445
+ // fill data
446
+ NFU.each(NFU.getChildsRecursively(newrow, 'SPAN'), function(span) {
447
+ if (NFU.hasClassName(span, 'value'))
448
+ span.innerHTML = filter;
449
+ if (NFU.hasClassName(span, 'prefix'))
450
+ span.innerHTML = self.filters.getDialingCode(country);
451
+ });
452
+
453
+ // assign new row to data
454
+ if (this.data[country])
455
+ this.data[country].push(newrow);
456
+ else
457
+ this.data[country] = [newrow];
458
+
459
+ // display row immediatly for current country
460
+ if (country == this.getCurrentCountry())
461
+ this.table.appendChild(newrow);
462
+
463
+ // update input field with serialized data
464
+ this.updateField();
465
+ };
466
+
467
+
468
+ /**
469
+ * Update existed row by a new filter value.
470
+ *
471
+ * Function expected exactly TR element (they
472
+ * are stored in this.data).
473
+ */
474
+ this.updateFilter = function(element, filter)
475
+ {
476
+ // search span 'value' and update them
477
+ NFU.each(NFU.getChildsRecursively(element, 'SPAN'), function(span) {
478
+ if (NFU.hasClassName(span, 'value'))
479
+ span.innerHTML = filter;
480
+ });
481
+
482
+ // update input field with serialized data
483
+ this.updateField();
484
+ };
485
+
486
+
487
+ /**
488
+ * Remove a filter specified by its TR tag or some of
489
+ * its children (row).
490
+ *
491
+ * If TR tag is not found function does nothing
492
+ */
493
+ this.removeFilter = function(row)
494
+ {
495
+ // search parent TR
496
+ if (row.tagName != 'TR')
497
+ row = NFU.firstParent(row, 'TR');
498
+ if (row.tagName != 'TR')
499
+ return;
500
+
501
+ // remove row from internal data
502
+ for (var country in this.data) {
503
+ var index = this.data[country].indexOf(row);
504
+ if (index != -1)
505
+ this.data[country].splice(index, 1);
506
+ }
507
+
508
+ // remove from table immediatly
509
+ row.parentNode.removeChild(row);
510
+ // update input field with serialized data
511
+ this.updateField();
512
+ };
513
+
514
+
515
+ /**
516
+ * Extract the filter value from a row.
517
+ *
518
+ * This function works for all instances same way.
519
+ */
520
+ this.getValueByRow = function(row)
521
+ {
522
+ var val = "";
523
+
524
+ // search value as HTML of SPAN 'value'
525
+ NFU.each(NFU.getChildsRecursively(row, 'SPAN'), function(span) {
526
+ if (NFU.hasClassName(span, 'value')) {
527
+ val = span.innerHTML;
528
+ }
529
+ });
530
+
531
+ return val;
532
+ };
533
+
534
+
535
+ /**
536
+ * Get current the displayed country.
537
+ * Value is get from this.country_select.
538
+ */
539
+ this.getCurrentCountry = function()
540
+ {
541
+ return this.country_select.options[this.country_select.selectedIndex].value;
542
+ };
543
+
544
+
545
+ /**
546
+ * Change country. This function is an event handler of
547
+ * event "change" of this.country_select.
548
+ *
549
+ * Function removes all rows from TABLE (not from this.data)
550
+ * and again add all rows for new country.
551
+ */
552
+ this.changeCountry = function()
553
+ {
554
+ // get current displayed country
555
+ var country = this.getCurrentCountry();
556
+ // remove all TR from table
557
+ this.removeAllRows();
558
+
559
+ // walk through internal data and add rows
560
+ // for the new displayed country
561
+ if (this.data[country]) {
562
+ NFU.each(this.data[country], function(row) {
563
+ self.addExistedRow(row);
564
+ });
565
+ }
566
+
567
+ // set class name for table
568
+ if (this.data[country])
569
+ NFU.removeClassName(this.filters.div, 'empty-filter');
570
+ else
571
+ NFU.addClassName(this.filters.div, 'empty-filter');
572
+ };
573
+
574
+
575
+ /**
576
+ * Function removes all TR elements from TABLE
577
+ * (except template row).
578
+ *
579
+ * Function removes only TR elements not rows
580
+ * from this.data.
581
+ */
582
+ this.removeAllRows = function()
583
+ {
584
+ NFU.eachChilds(this.table, 'TR', function(row) {
585
+ if (!NFU.hasClassName(row, this.id+'-template'))
586
+ row.parentNode.removeChild(row);
587
+ });
588
+ };
589
+
590
+
591
+ /**
592
+ * Function adds an existed row (TR) element
593
+ * to TABLE.
594
+ */
595
+ this.addExistedRow = function(row)
596
+ {
597
+ this.table.appendChild(row);
598
+ };
599
+
600
+
601
+ /**
602
+ * Function updates INPUT fields with serialized values
603
+ * from this.data values.
604
+ *
605
+ * Function also adds className 'has-filter' to OPTIONs of this.country_select
606
+ * whih have some filters and removes this className from OPTIONs without filters.
607
+ *
608
+ * Filters will be sorted so that countries with filters preceeds the countries
609
+ * without filters.
610
+ *
611
+ * Format:
612
+ *
613
+ * COUNTRY_CODE1,DIAL1,FILTER1;COUNTRY_CODE2,DIAL2,FILTER2;COUNTRY_CODE3,DIAL3,FILTER3 ...
614
+ */
615
+ this.updateField = function()
616
+ {
617
+ var vals = [];
618
+
619
+ // get values for each country
620
+ for (var country in this.data) {
621
+ NFU.each(this.data[country], function(row) {
622
+ vals.push(country+','+self.getValueByRow(row));
623
+ });
624
+ }
625
+
626
+ // set serialized values
627
+ this.field.value = vals.join(';');
628
+
629
+ // remember selected countries
630
+ var selected = '';
631
+
632
+ NFU.eachChilds(this.country_select, 'OPTION', function(option)
633
+ {
634
+ if (option.selected)
635
+ selected = option.value;
636
+ });
637
+
638
+ var with_filters = [];
639
+ var without_filters = [];
640
+
641
+ // remove filters
642
+ NFU.eachChilds(this.country_select, 'OPTION', function(option)
643
+ {
644
+ if (self.data[option.value] && self.data[option.value].length > 0)
645
+ with_filters.push(option);
646
+ else
647
+ without_filters.push(option);
648
+
649
+ self.country_select.removeChild(option);
650
+ });
651
+
652
+ // sort both lists
653
+ var sort_func = function sort(i1, i2) {
654
+ return i1.innerHTML < i2.innerHTML ? -1 : i1.innerHTML > i2.innerHTML
655
+ };
656
+
657
+ with_filters.sort(sort_func);
658
+ without_filters.sort(sort_func);
659
+
660
+ // append countries with filters
661
+ NFU.each(with_filters, function(option) {
662
+ NFU.addClassName(option, 'has-filter');
663
+ if (option.value == selected)
664
+ option.selected = true;
665
+ self.country_select.appendChild(option);
666
+ });
667
+
668
+ // append countries without filters
669
+ NFU.each(without_filters, function(option) {
670
+ NFU.removeClassName(option, 'has-filter');
671
+ self.country_select.appendChild(option);
672
+ });
673
+
674
+ // select
675
+ NFU.eachChilds(this.country_select, 'OPTION', function(option, index) {
676
+ if (option.value == selected)
677
+ self.country_select.selectedIndex = index;
678
+ });
679
+
680
+ // set class name for table
681
+ if (this.field.value)
682
+ NFU.removeClassName(this.filters.div, 'empty-filter');
683
+ else
684
+ NFU.addClassName(this.filters.div, 'empty-filter');
685
+ };
686
+
687
+
688
+ /**
689
+ * Function get value from this.field and parses it
690
+ * and fills the filter rows by this.
691
+ *
692
+ * Format:
693
+ *
694
+ * COUNTRY_CODE1,DIAL1,FILTER1;COUNTRY_CODE2,DIAL2,FILTER2;COUNTRY_CODE3,DIAL3,FILTER3 ...
695
+ */
696
+ this.loadValue = function()
697
+ {
698
+ // get value
699
+ var val = this.field.value;
700
+
701
+ // set class name for table
702
+ if (val)
703
+ NFU.removeClassName(this.filters.div, 'empty-filter');
704
+ else
705
+ NFU.addClassName(this.filters.div, 'empty-filter');
706
+
707
+ // if there is no value does nothing
708
+ if (!val)
709
+ return;
710
+
711
+ // clear internal data
712
+ this.data = {};
713
+ // remove all TR elements
714
+ this.removeAllRows();
715
+
716
+ // validator for filter pattern
717
+ var validator = new RegExp('^[0-9\?]{0,15}[0-9\?*](-[0-9\?]{0,15}[0-9\?*])?$');
718
+
719
+ var vals = val.split(';');
720
+
721
+ // walk through all rows
722
+ NFU.each(vals, function(val) {
723
+
724
+ // split to parts
725
+ var parts = val.split(',');
726
+
727
+ // if number of parts does not corespond skip row
728
+ if (parts.length != 3)
729
+ return;
730
+
731
+ // extract values
732
+ var country = parts[0];
733
+ var dial = parts[1];
734
+ var filter = parts[2];
735
+
736
+ // test filter
737
+ if (!validator.test(filter))
738
+ return;
739
+
740
+ // all is right, add filter
741
+ self.addFilter(filter, country+','+dial);
742
+ });
743
+ };
744
+ };
745
+
746
+
747
+ /**
748
+ *
749
+ */
750
+ function FilterDialog(id, filters) {
751
+
752
+ /* this instance */
753
+ var self = this;
754
+
755
+
756
+ /* if of element TABLE represented this filters */
757
+ this.id = id;
758
+
759
+
760
+ /* instance of ancestor object */
761
+ this.filters = filters;
762
+
763
+ /* DIV dialog */
764
+ this.div = document.getElementById(id);
765
+ /* DIV with digits in first row (pattern, left side of interval) */
766
+ this.digits1 = document.getElementById(this.id+'-digits-1');
767
+ /* DIV with digits in second row (right side of interval) */
768
+ this.digits2 = document.getElementById(this.id+'-digits-2');
769
+ /* INPUT radio for PATTERN */
770
+ this.type1 = document.getElementById(this.id+'-type-1');
771
+ /* INPUT radio for RANGE */
772
+ this.type2 = document.getElementById(this.id+'-type-2');
773
+
774
+
775
+ /**
776
+ * Set a fliter value to dialog.
777
+ *
778
+ * Function setup radiobuttons and set digits.
779
+ *
780
+ * If filter is not specified then there will be used
781
+ * '*' value.
782
+ */
783
+ this.setValue = function(filter)
784
+ {
785
+ if (!filter)
786
+ filter = '*';
787
+
788
+ this.clear();
789
+
790
+ // parse filter value
791
+ var parts = filter.split('-');
792
+ var isRange = parts.length == 2;
793
+
794
+ this.setType(isRange);
795
+ this.setDigits(this.digits1, parts[0]);
796
+
797
+ if (isRange)
798
+ this.setDigits(this.digits2, parts[1]);
799
+ };
800
+
801
+
802
+ /**
803
+ * Clear dialog (analogy set to '*').
804
+ */
805
+ this.clear = function()
806
+ {
807
+ this.setType(false);
808
+ this.setDigits(this.digits1, '*');
809
+ this.setDigits(this.digits2, '*');
810
+ };
811
+
812
+
813
+ /**
814
+ * Set filter type (RANGE or PATTERN).
815
+ *
816
+ * Function set radion buttons and show/hide
817
+ * the div with second digits (right side of inteval).
818
+ */
819
+ this.setType = function(isRange)
820
+ {
821
+ if (isRange) {
822
+ this.type1.checked = "";
823
+ this.type2.checked = "checked";
824
+ this.digits2.style.display = 'block';
825
+ } else {
826
+ this.type1.checked = "checked";
827
+ this.type2.checked = "";
828
+ this.digits2.style.display = 'none';
829
+ }
830
+ };
831
+
832
+
833
+ /**
834
+ * Set digits.
835
+ */
836
+ this.setDigits = function(digits, value)
837
+ {
838
+ // set first digit to '*', it also removes
839
+ // all followed digits
840
+ var firstSelect = NFU.firstChild(digits, 'SELECT');
841
+ firstSelect.selectedIndex = 0;
842
+ self.selectDigit(firstSelect);
843
+
844
+ // now walk through filter value and select
845
+ // correspond digits
846
+ NFU.eachChars(value, false, function(char) {
847
+ lastSelect = NFU.lastChild(digits, 'SELECT');
848
+ // 0 - *, 1-10 - digits [0-9], 11 - ?
849
+ lastSelect.selectedIndex = (char == '?') ? 11 : new Number(char)+1;
850
+ self.selectDigit(lastSelect);
851
+ });
852
+ };
853
+
854
+
855
+ /**
856
+ * Select single digit. Elem is SELECT represented
857
+ * the position for the digit.
858
+ */
859
+ this.selectDigit = function(elem)
860
+ {
861
+ // get parent element for adding/removing digits
862
+ var parent = elem.parentNode;
863
+ // count of digits helps to determine whether
864
+ // selected digits is last or not
865
+ var count_select = NFU.getChilds(parent, 'SELECT').length;
866
+
867
+ // get last child and last select
868
+ // last child may be a text node i.e last child != last select
869
+ var lastChild = NFU.lastChild(parent);
870
+ var lastSelect = NFU.lastChild(parent, 'SELECT');
871
+
872
+ // user choose '*' and there is a digit (SELECT)
873
+ // so we have to remove all followed digits (SELECTs)
874
+ if (elem.value == '*' && count_select > 0) {
875
+ while (lastChild && lastChild != elem) {
876
+ parent.removeChild(lastChild);
877
+ lastChild = NFU.lastChild(parent);
878
+ }
879
+ // user choose a digit or ? for non-last select
880
+ // (there is max 16 digits because phone numbers)
881
+ // so we have to add next digits
882
+ } else if (elem == lastSelect && count_select < 16) {
883
+ var select = document.createElement('SELECT');
884
+ this.filters.initOptions(select, this.filters.digits, '*');
885
+ select.onclick = function() { self.selectDigit(select); };
886
+ parent.appendChild(select);
887
+ }
888
+ };
889
+
890
+
891
+ /**
892
+ * Get completely value.
893
+ */
894
+ this.getValue = function()
895
+ {
896
+ // is selected range or pattern
897
+ var isRange = this.type2.checked;
898
+
899
+ // build serialize digits
900
+ var val1 = "";
901
+ var val2 = "";
902
+
903
+ NFU.eachChilds(this.digits1, 'SELECT', function(select) {
904
+ NFU.eachChilds(select, 'OPTION', function(option) {
905
+ if (option.selected)
906
+ val1 += option.innerHTML;
907
+ });
908
+ });
909
+
910
+ if (isRange)
911
+ {
912
+ NFU.eachChilds(this.digits2, 'SELECT', function(select) {
913
+ NFU.eachChilds(select, 'OPTION', function(option) {
914
+ if (option.selected)
915
+ val2 += option.innerHTML;
916
+ });
917
+ });
918
+ }
919
+
920
+ // validate interval
921
+ if (isRange)
922
+ {
923
+ // first remove '*' from text
924
+ // then chang '?' to '0' for left side and to '9' for right side
925
+ var vval1 = val1.replace('*', '').replace('?', '0');
926
+ var vval2 = val2.replace('*', '').replace('?', '9');
927
+
928
+ // provide that both values have same sizes
929
+ if (vval1.length > vval2.length)
930
+ while (vval1.length > vval2.length)
931
+ vval2 = vval2 + '9';
932
+
933
+ if (vval2.length > vval1.length)
934
+ while (vval2.length > vval1.length)
935
+ vval1 = vval1 + '0';
936
+
937
+ // cast to number
938
+ var num1 = new Number(vval1);
939
+ var num2 = new Number(vval2);
940
+
941
+ // test
942
+ if (num1 >= num2)
943
+ {
944
+ alert('Inccorect inteval. Left side ('+val1+') is greater than right side ('+val2+')');
945
+ return false;
946
+ }
947
+ }
948
+
949
+ return isRange ? val1 + '-' + val2 : val1;
950
+ };
951
+
952
+
953
+ /**
954
+ * Function shows dialog.
955
+ */
956
+ this.show = function() {
957
+ this.div.style.display = 'block';
958
+ };
959
+
960
+
961
+ /**
962
+ * Function hides dialog
963
+ */
964
+ this.hide = function() {
965
+ this.div.style.display = 'none';
966
+ };
967
+
968
+ };
969
+
970
+
971
+ /**
972
+ */
973
+ function NumberFilters(id)
974
+ {
975
+ /* this instance */
976
+ var self = this;
977
+
978
+
979
+ /* prefix id */
980
+ this.prefix_id = id;
981
+
982
+ /* */
983
+ this.div = document.getElementById(id);
984
+
985
+ /* TABLE with include filters */
986
+ this.filterTable = new FilterTable(id+'-filterTable', this);
987
+ /* TABLE with exclude filters */
988
+ //this.exclude = new FilterTable(id+'-exclude', this);
989
+ /* DIALOG for set/edit filter */
990
+ this.dialog = new FilterDialog(id+'-dialog', this);
991
+
992
+ /* filter table current edited in dialog */
993
+ this.openFilter = null;
994
+ /* filter table row current edited in dialog */
995
+ this.openRow = null;
996
+
997
+
998
+ /**
999
+ *
1000
+ */
1001
+ this.openDialog = function(filterTable, row)
1002
+ {
1003
+ if (row)
1004
+ row = NFU.firstParent(row, 'TR');
1005
+
1006
+ this.openFilter = filterTable;
1007
+ this.openRow = row;
1008
+
1009
+ var value = row ? filterTable.getValueByRow(row) : '*';
1010
+
1011
+ this.dialog.setValue(value);
1012
+ this.dialog.show();
1013
+ };
1014
+
1015
+
1016
+ /**
1017
+ * Save dialog. User confirms his choice.
1018
+ */
1019
+ this.saveDialog = function()
1020
+ {
1021
+ var value = this.dialog.getValue();
1022
+
1023
+ if (!value)
1024
+ return;
1025
+
1026
+ if (this.openRow)
1027
+ this.openFilter.updateFilter(this.openRow, value);
1028
+ else
1029
+ this.openFilter.addFilter(value);
1030
+
1031
+ this.openRow = null;
1032
+ this.openFilter = null;
1033
+
1034
+ this.dialog.hide();
1035
+ };
1036
+
1037
+
1038
+ /**
1039
+ * Close dialog without saving.
1040
+ * This does only hide the dialog.
1041
+ */
1042
+ this.closeDialog = function()
1043
+ {
1044
+ this.dialog.hide();
1045
+ };
1046
+
1047
+
1048
+ /**
1049
+ * Load values froh hidden INPUTs to filter table.
1050
+ */
1051
+ this.loadValues = function()
1052
+ {
1053
+ this.filterTable.loadValue();
1054
+
1055
+ this.filterTable.country_select.selectedIndex = 0;
1056
+ this.filterTable.changeCountry();
1057
+
1058
+ //this.include.loadValue();
1059
+ //this.exclude.loadValue();
1060
+ };
1061
+
1062
+
1063
+ /**
1064
+ * Init SELECT from sources.
1065
+ */
1066
+ this.initSelects = function(className, sources, defaultValue, label_callback)
1067
+ {
1068
+ var self = this;
1069
+ var selects = NFU.getElementsByClassName(className, 'SELECT');
1070
+
1071
+ NFU.each(selects, function(select) {
1072
+ if (select.options.length == 0) {
1073
+ self.initOptions(select, sources, defaultValue, label_callback);
1074
+ }
1075
+ });
1076
+ };
1077
+
1078
+
1079
+ /**
1080
+ *
1081
+ */
1082
+ this.initOptions = function(select, sources, defaultValue, label_callback)
1083
+ {
1084
+ NFU.each(sources, function(source) {
1085
+ var parts = source.split(':');
1086
+ var index = parts[0];
1087
+ var value = parts[1];
1088
+ var label = (label_callback) ? label_callback(index, value) : value;
1089
+
1090
+ var option = new Option(label, index);
1091
+ if (defaultValue == index)
1092
+ option.selected = true;
1093
+ select.options[select.options.length] = option;
1094
+ });
1095
+ };
1096
+
1097
+
1098
+ /**
1099
+ * Function returns dialing codes for a country.
1100
+ */
1101
+ this.getDialingCode = function(country)
1102
+ {
1103
+ var parts = country.split(',');
1104
+ return parts[1];
1105
+ };
1106
+
1107
+
1108
+ this.country_codes = [
1109
+ 'AFG,93:Afghanistan',
1110
+ 'ALB,355:Albania',
1111
+ 'DZA,213:Algeria',
1112
+ 'ASM,1684:American Samoa',
1113
+ 'AND,376:Andorra',
1114
+ 'AGO,244:Angola',
1115
+ 'AIA,1264:Anguilla',
1116
+ 'ATA,672:Antarctica',
1117
+ 'ATG,1268:Antigua and Barbuda',
1118
+ 'ARG,54:Argentina',
1119
+ 'ARM,374:Armenia',
1120
+ 'ABW,297:Aruba',
1121
+ 'AUS,61:Australia',
1122
+ 'AUT,43:Austria',
1123
+ 'AZE,994:Azerbaijan',
1124
+ 'BHS,1242:Bahamas',
1125
+ 'BHR,973:Bahrain',
1126
+ 'BGD,880:Bangladesh',
1127
+ 'BRB,1246:Barbados',
1128
+ 'BLR,375:Belarus',
1129
+ 'BEL,32:Belgium',
1130
+ 'BLZ,501:Belize',
1131
+ 'BEN,229:Benin',
1132
+ 'BMU,1441:Bermuda',
1133
+ 'BTN,975:Bhutan',
1134
+ 'BOL,591:Bolivia',
1135
+ 'BIH,387:Bosnia and Herzegovina',
1136
+ 'BWA,267:Botswana',
1137
+ 'BRA,55:Brazil',
1138
+ 'VGB,1284:British Virgin Islands',
1139
+ 'BRN,673:Brunei',
1140
+ 'BGR,359:Bulgaria',
1141
+ 'BFA,226:Burkina Faso',
1142
+ 'MMR,95:Burma (Myanmar)',
1143
+ 'BDI,257:Burundi',
1144
+ 'KHM,855:Cambodia',
1145
+ 'CMR,237:Cameroon',
1146
+ 'CAN,1:Canada',
1147
+ 'CPV,238:Cape Verde',
1148
+ 'CYM,1345:Cayman Islands',
1149
+ 'CAF,236:Central African Republic',
1150
+ 'TCD,235:Chad',
1151
+ 'CHL,56:Chile',
1152
+ 'CHN,86:China',
1153
+ 'CXR,61:Christmas Island',
1154
+ 'CCK,61:Cocos (Keeling) Islands',
1155
+ 'COL,57:Colombia',
1156
+ 'COM,269:Comoros',
1157
+ 'COK,682:Cook Islands',
1158
+ 'CRC,506:Costa Rica',
1159
+ 'HRV,385:Croatia',
1160
+ 'CUB,53:Cuba',
1161
+ 'CYP,357:Cyprus',
1162
+ 'CZE,420:Czech Republic',
1163
+ 'COD,243:Democratic Republic of the Congo',
1164
+ 'DNK,45:Denmark',
1165
+ 'DJI,253:Djibouti',
1166
+ 'DMA,1767:Dominica',
1167
+ 'DOM,1809:Dominican Republic',
1168
+ 'ECU,593:Ecuador',
1169
+ 'EGY,20:Egypt',
1170
+ 'SLV,503:El Salvador',
1171
+ 'GNQ,240:Equatorial Guinea',
1172
+ 'ERI,291:Eritrea',
1173
+ 'EST,372:Estonia',
1174
+ 'ETH,251:Ethiopia',
1175
+ 'FLK,500:Falkland Islands',
1176
+ 'FRO,298:Faroe Islands',
1177
+ 'FJI,679:Fiji',
1178
+ 'FIN,358:Finland',
1179
+ 'FRA,33:France',
1180
+ 'PYF,689:French Polynesia',
1181
+ 'GAB,241:Gabon',
1182
+ 'GMB,220:Gambia',
1183
+ 'GEO,995:Georgia',
1184
+ 'DEU,49:Germany',
1185
+ 'GHA,233:Ghana',
1186
+ 'GIB,350:Gibraltar',
1187
+ 'GRC,30:Greece',
1188
+ 'GRL,299:Greenland',
1189
+ 'GRD,1473:Grenada',
1190
+ 'GUM,1671:Guam',
1191
+ 'GTM,502:Guatemala',
1192
+ 'GIN,224:Guinea',
1193
+ 'GNB,245:Guinea-Bissau',
1194
+ 'GUY,592:Guyana',
1195
+ 'HTI,509:Haiti',
1196
+ 'VAT,39:Holy See (Vatican City)',
1197
+ 'HND,504:Honduras',
1198
+ 'HKG,852:Hong Kong',
1199
+ 'HUN,36:Hungary',
1200
+ 'IS,354:Iceland',
1201
+ 'IND,91:India',
1202
+ 'IDN,62:Indonesia',
1203
+ 'IRN,98:Iran',
1204
+ 'IRQ,964:Iraq',
1205
+ 'IRL,353:Ireland',
1206
+ 'IMN,44:Isle of Man',
1207
+ 'ISR,972:Israel',
1208
+ 'ITA,39:Italy',
1209
+ 'CIV,225:Ivory Coast',
1210
+ 'JAM,1876:Jamaica',
1211
+ 'JPN,81:Japan',
1212
+ 'JOR,962:Jordan',
1213
+ 'KAZ,7:Kazakhstan',
1214
+ 'KEN,254:Kenya',
1215
+ 'KIR,686:Kiribati',
1216
+ 'KWT,965:Kuwait',
1217
+ 'KGZ,996:Kyrgyzstan',
1218
+ 'LAO,856:Laos',
1219
+ 'LVA,371:Latvia',
1220
+ 'LBN,961:Lebanon',
1221
+ 'LSO,266:Lesotho',
1222
+ 'LBR,231:Liberia',
1223
+ 'LBY,218:Libya',
1224
+ 'LIE,423:Liechtenstein',
1225
+ 'LTU,370:Lithuania',
1226
+ 'LUX,352:Luxembourg',
1227
+ 'MAC,853:Macau',
1228
+ 'MKD,389:Macedonia',
1229
+ 'MDG,261:Madagascar',
1230
+ 'MWI,265:Malawi',
1231
+ 'MYS,60:Malaysia',
1232
+ 'MDV,960:Maldives',
1233
+ 'MLI,223:Mali',
1234
+ 'MLT,356:Malta',
1235
+ 'MHL,692:Marshall Islands',
1236
+ 'MRT,222:Mauritania',
1237
+ 'MUS,230:Mauritius',
1238
+ 'MYT,262:Mayotte',
1239
+ 'MEX,52:Mexico',
1240
+ 'FSM,691:Micronesia',
1241
+ 'MDA,373:Moldova',
1242
+ 'MCO,377:Monaco',
1243
+ 'MNG,976:Mongolia',
1244
+ 'MNE,382:Montenegro',
1245
+ 'MSR,1664:Montserrat',
1246
+ 'MAR,212:Morocco',
1247
+ 'MOZ,258:Mozambique',
1248
+ 'NAM,264:Namibia',
1249
+ 'NRU,674:Nauru',
1250
+ 'NPL,977:Nepal',
1251
+ 'NLD,31:Netherlands',
1252
+ 'ANT,599:Netherlands Antilles',
1253
+ 'NCL,687:New Caledonia',
1254
+ 'NZL,64:New Zealand',
1255
+ 'NIC,505:Nicaragua',
1256
+ 'NER,227:Niger',
1257
+ 'NGA,234:Nigeria',
1258
+ 'NIU,683:Niue',
1259
+ 'NFK,672:Norfolk Island',
1260
+ 'PRK,850:North Korea',
1261
+ 'MNP,1670:Northern Mariana Islands',
1262
+ 'NOR,47:Norway',
1263
+ 'OMN,968:Oman',
1264
+ 'PAK,92:Pakistan',
1265
+ 'PLW,680:Palau',
1266
+ 'PAN,507:Panama',
1267
+ 'PNG,675:Papua New Guinea',
1268
+ 'PRY,595:Paraguay',
1269
+ 'PER,51:Peru',
1270
+ 'PHL,63:Philippines',
1271
+ 'PCN,870:Pitcairn Islands',
1272
+ 'POL,48:Poland',
1273
+ 'PRT,351:Portugal',
1274
+ 'PRI,1:Puerto Rico',
1275
+ 'QAT,974:Qatar',
1276
+ 'COG,242:Republic of the Congo',
1277
+ 'ROU,40:Romania',
1278
+ 'RUS,7:Russia',
1279
+ 'RWA,250:Rwanda',
1280
+ 'BLM,590:Saint Barthelemy',
1281
+ 'SHN,290:Saint Helena',
1282
+ 'KNA,1869:Saint Kitts and Nevis',
1283
+ 'LCA,1758:Saint Lucia',
1284
+ 'MAF,1599:Saint Martin',
1285
+ 'SPM,508:Saint Pierre and Miquelon',
1286
+ 'VCT,1784:Saint Vincent and the Grenadines',
1287
+ 'WSM,685:Samoa',
1288
+ 'SMR,378:San Marino',
1289
+ 'STP,239:Sao Tome and Principe',
1290
+ 'SAU,966:Saudi Arabia',
1291
+ 'SEN,221:Senegal',
1292
+ 'SRB,381:Serbia',
1293
+ 'SYC,248:Seychelles',
1294
+ 'SLE,232:Sierra Leone',
1295
+ 'SGP,65:Singapore',
1296
+ 'SVK,421:Slovakia',
1297
+ 'SVN,386:Slovenia',
1298
+ 'SLB,677:Solomon Islands',
1299
+ 'SOM,252:Somalia',
1300
+ 'ZAF,27:South Africa',
1301
+ 'KOR,82:South Korea',
1302
+ 'ESP,34:Spain',
1303
+ 'LKA,94:Sri Lanka',
1304
+ 'SDN,249:Sudan',
1305
+ 'SUR,597:Suriname',
1306
+ 'SWZ,268:Swaziland',
1307
+ 'SWE,46:Sweden',
1308
+ 'CHE,41:Switzerland',
1309
+ 'SYR,963:Syria',
1310
+ 'TWN,886:Taiwan',
1311
+ 'TJK,992:Tajikistan',
1312
+ 'TZA,255:Tanzania',
1313
+ 'THA,66:Thailand',
1314
+ 'TLS,670:Timor-Leste',
1315
+ 'TGO,228:Togo',
1316
+ 'TKL,690:Tokelau',
1317
+ 'TON,676:Tonga',
1318
+ 'TTO,1868:Trinidad and Tobago',
1319
+ 'TUN,216:Tunisia',
1320
+ 'TUR,90:Turkey',
1321
+ 'TKM,993:Turkmenistan',
1322
+ 'TCA,1649:Turks and Caicos Islands',
1323
+ 'TUV,688:Tuvalu',
1324
+ 'UGA,256:Uganda',
1325
+ 'UKR,380:Ukraine',
1326
+ 'ARE,971:United Arab Emirates',
1327
+ 'GBR,44:United Kingdom',
1328
+ 'USA,1:United States',
1329
+ 'URY,598:Uruguay',
1330
+ 'VIR,1340:US Virgin Islands',
1331
+ 'UZB,998:Uzbekistan',
1332
+ 'VUT,678:Vanuatu',
1333
+ 'VEN,58:Venezuela',
1334
+ 'VNM,84:Vietnam',
1335
+ 'WLF,681:Wallis and Futuna',
1336
+ 'YEM,967:Yemen',
1337
+ 'ZMB,260:Zambia',
1338
+ 'ZWE,263:Zimbabwe'
1339
+ ];
1340
+
1341
+ this.max_digits_without_prefix = [
1342
+ "0:0",
1343
+ "1:1",
1344
+ "2:2",
1345
+ "3:3",
1346
+ "4:4",
1347
+ "5:5",
1348
+ "6:6",
1349
+ "7:7",
1350
+ "8:8",
1351
+ "9:9",
1352
+ "10:10",
1353
+ "11:11",
1354
+ "12:12",
1355
+ "13:13",
1356
+ "14:14",
1357
+ "15:15"
1358
+ ];
1359
+
1360
+ this.digits = [
1361
+ "*:*", // any digit (a number of)
1362
+ "0:0",
1363
+ "1:1",
1364
+ "2:2",
1365
+ "3:3",
1366
+ "4:4",
1367
+ "5:5",
1368
+ "6:6",
1369
+ "7:7",
1370
+ "8:8",
1371
+ "9:9",
1372
+ "?:?" // any digit (single)
1373
+ ];
1374
+
1375
+
1376
+ // intialize procedure
1377
+ this.initSelects('max-number-for-prefix', this.max_digits_without_prefix, 9);
1378
+ this.initSelects('digits', this.digits, '*');
1379
+ this.initSelects('country-codes', this.country_codes, null, function(code, country_name) {
1380
+ return country_name + " ("+self.getDialingCode(code)+")";
1381
+ });
1382
+
1383
+ this.loadValues();
1384
+
1385
+ };
lib/Artio/SMSService/httphelper.php ADDED
@@ -0,0 +1,243 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * ARTIO SMS Services
4
+ *
5
+ * @package ARTIO SMS Services
6
+ * @author ARTIO http://www.artio.net
7
+ * @copyright Copyright (C) 2013 ARTIO s.r.o.
8
+ * @license GNU/GPLv3 http://www.artio.net/license/gnu-general-public-license
9
+ */
10
+
11
+
12
+ /**
13
+ * Allows simple HTTP requests calls without any external dependencies like cURL.
14
+ * However, OpenSSL must be still installed for HTTPS requests.
15
+ */
16
+ class AHttpHelper
17
+ {
18
+ private $errors = array();
19
+
20
+ private static $instance = null;
21
+
22
+ /**
23
+ * Private constructor for singleton pattern
24
+ */
25
+ private function __construct()
26
+ { }
27
+
28
+ /**
29
+ * Returns a singleton instance of AHttpHelper class
30
+ */
31
+ public static function getInstance()
32
+ {
33
+ if (is_null(self::$instance)) {
34
+ self::$instance = new AHttpHelper();
35
+ }
36
+
37
+ return self::$instance;
38
+ }
39
+
40
+ /**
41
+ * Adds error to the list of errors
42
+ */
43
+ protected function setError($error)
44
+ {
45
+ $this->errors[] = $error;
46
+ }
47
+
48
+ /**
49
+ * Returns the last error message
50
+ */
51
+ public function getError()
52
+ {
53
+ return end($this->errors);
54
+ }
55
+
56
+ /**
57
+ * Returns all the errors concatenated with the $newline string
58
+ */
59
+ public function getErrors($newline = "\n")
60
+ {
61
+ return implode($newline, $this->errors);
62
+ }
63
+
64
+ /**
65
+ * Sends HTTP request
66
+ *
67
+ * @param string $url Target URL
68
+ * @param mixed $data Data for the POST request - associative array or query string with URL encoded values
69
+ * @param string $method Method to use - 'POST' or 'GET'
70
+ * @param array $headers Additional headers to send with the request (associative array)
71
+ * @return mixed Response object on success or false on error. Response object has the following properties:
72
+ * code - HTTP response code
73
+ * header - header part of the HTTP response
74
+ * content - data part of the HTTP response
75
+ */
76
+ public function sendRequest($url, $data = '', $method = 'POST', $headers = array())
77
+ {
78
+ $method = strtoupper($method);
79
+
80
+ // Convert data array to query string
81
+ if (is_array($data)) {
82
+ // format --> test1=a&test2=b
83
+ $_data = array();
84
+ foreach ($data as $key => $val) {
85
+ $_data[] = $key . '=' . urlencode($val);
86
+ }
87
+ $data = implode('&', $_data);
88
+ }
89
+ else if (!is_string($data)) {
90
+ $this->setError('Unsupported data - only associative array or string is supported');
91
+ return false;
92
+ }
93
+
94
+ // Check data
95
+ if (($method == 'GET') && !empty($data)) {
96
+ $this->setError('No data allowed for GET requests');
97
+ return false;
98
+ }
99
+
100
+ // Content type
101
+ if (!empty($data)) {
102
+ if (!isset($headers['Content-Type'])) {
103
+ $headers['Content-Type'] = 'application/x-www-form-urlencoded';
104
+ }
105
+ }
106
+
107
+ // Parse the given URL
108
+ $url = parse_url($url);
109
+ if (!isset($url['scheme'])) {
110
+ $this->setError('No protocol in the URL');
111
+ return false;
112
+ }
113
+
114
+ // Extract host and path
115
+ if (!isset($url['host'])) {
116
+ $this->setError('No host in the URL');
117
+ return false;
118
+ }
119
+
120
+ $host = $url['host'];
121
+ $path = isset($url['path']) ? $url['path'] : '/';
122
+
123
+ // Prepare host and port to connect to
124
+ $connhost = $host;
125
+ $port = 80;
126
+
127
+ // Workaround for some PHP versions, where fsockopen can't connect to
128
+ // 'localhost' string on Windows servers
129
+ if ($connhost == 'localhost') {
130
+ $connhost = gethostbyname('localhost');
131
+ }
132
+
133
+ // Handle scheme
134
+ if ($url['scheme'] == 'https') {
135
+ $connhost = 'ssl://'.$connhost;
136
+ $port = 443;
137
+ }
138
+ else if ($url['scheme'] != 'http') {
139
+ $this->setError('Unsupported protocol: '.$url['scheme']);
140
+ return false;
141
+ }
142
+
143
+ // Open a socket connection
144
+ $errno = null;
145
+ $errstr = null;
146
+ $fp = @fsockopen($connhost, $port, $errno, $errstr, 5);
147
+ if (!is_resource($fp) || ($fp === false)) {
148
+ $this->setError('Could not connect to host: '.$connhost.':'.$port);
149
+ return false;
150
+ }
151
+
152
+ // Handle query string from URL
153
+ $query = '';
154
+ if (isset($url['query'])) {
155
+ $query = '?'.$url['query'];
156
+ }
157
+
158
+ // Prepare the request
159
+ $req = "{$method} {$path}{$query} HTTP/1.1\r\n";
160
+ $req .= "Host: {$host}\r\n";
161
+ if ($method == 'POST') {
162
+ $req .= "Content-Length: ".strlen($data)."\r\n";
163
+ }
164
+ if (is_array($headers)) {
165
+ foreach ($headers as $key => $val) {
166
+ $header = $key.': '.trim($val)."\r\n";
167
+ $req .= $header;
168
+ }
169
+ }
170
+ $req .= "Connection: close\r\n\r\n";
171
+ if (!empty($data)) {
172
+ $req .= $data;
173
+ }
174
+
175
+ // Check the fputs, sometimes fsockopen doesn't fail, but fputs doesn't work
176
+ if (!@fputs($fp, $req)) {
177
+ @fclose($fp);
178
+ $this->setError('Could not send data to host: '.$connhost.':'.$port);
179
+ return false;
180
+ }
181
+
182
+ $result = '';
183
+ while(!feof($fp)) {
184
+ // receive the results of the request
185
+ $result .= fgets($fp, 1024);
186
+ }
187
+
188
+ // close the socket connection:
189
+ fclose($fp);
190
+
191
+ // split the result header from the content
192
+ $result = explode("\r\n\r\n", $result, 2);
193
+
194
+ $header = isset($result[0]) ? $result[0] : '';
195
+ $content = isset($result[1]) ? $result[1] : '';
196
+
197
+ // Build response object
198
+ $response = new stdClass();
199
+ $response->header = $header;
200
+ $response->content = $content;
201
+
202
+ // Get the response code from header
203
+ $headerLines = explode("\n", $response->header);
204
+ $header1 = explode(' ', trim($headerLines[0]));
205
+ $code = intval($header1[1]);
206
+ $response->code = $code;
207
+
208
+ // Handle chunked transfer if needed
209
+ if (strpos(strtolower($response->header), 'transfer-encoding: chunked') !== false) {
210
+ $parsed = '';
211
+ $left = $response->content;
212
+
213
+ while (true) {
214
+ $pos = strpos($left, "\r\n");
215
+ if ($pos === false) {
216
+ return $response;
217
+ }
218
+
219
+ $chunksize = substr($left, 0, $pos);
220
+ $pos += strlen("\r\n");
221
+ $left = substr($left, $pos);
222
+
223
+ $pos = strpos($chunksize, ';');
224
+ if ($pos !== false) {
225
+ $chunksize = substr($chunksize, 0, $pos);
226
+ }
227
+ $chunksize = hexdec($chunksize);
228
+
229
+ if ($chunksize == 0) {
230
+ break;
231
+ }
232
+
233
+ $parsed .= substr($left, 0, $chunksize);
234
+ $left = substr($left, $chunksize + strlen("\r\n"));
235
+ }
236
+
237
+ $response->content = $parsed;
238
+ }
239
+
240
+ // Return the response object
241
+ return $response;
242
+ }
243
+ }
lib/Artio/SMSService/smsservice.php ADDED
@@ -0,0 +1,272 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*<BUILD_TAG>*/
3
+
4
+ // no direct access
5
+ require_once 'httphelper.php';
6
+
7
+ /**
8
+ * Allows simple access to ARTIO SMS Services API
9
+ */
10
+ class ASmsService
11
+ {
12
+ /**
13
+ * ARTIO SMS Service API URL
14
+ */
15
+ private static $serviceUrl = 'http://www.artio.net/index.php?option=com_artiosms&controller=api';
16
+
17
+ private $errors = array();
18
+
19
+ private static $instance = null;
20
+
21
+ /**
22
+ * Private constructor for singleton pattern
23
+ */
24
+ private function __construct()
25
+ { }
26
+
27
+ /**
28
+ * Returns a singleton instance of ASmsService class
29
+ */
30
+ public static function getInstance()
31
+ {
32
+ if (is_null(self::$instance)) {
33
+ self::$instance = new ASmsService();
34
+ }
35
+
36
+ return self::$instance;
37
+ }
38
+
39
+ /**
40
+ * Adds error to the list of errors
41
+ */
42
+ protected function setError($error)
43
+ {
44
+ $this->errors[] = $error;
45
+ }
46
+
47
+ /**
48
+ * Returns the last error message
49
+ */
50
+ public function getError()
51
+ {
52
+ return end($this->errors);
53
+ }
54
+
55
+ /**
56
+ * Returns all the errors concatenated with the $newline string
57
+ */
58
+ public function getErrors($newline = "\n")
59
+ {
60
+ return implode($newline, $this->errors);
61
+ }
62
+
63
+ /**
64
+ * Returns current credit info - available credit and estimated credit exhaustion in hours
65
+ *
66
+ * @param string $username SMS Service API username
67
+ * @param string $apiKey SMS Service API key
68
+ * @return mixed Associative array with credit info on success or false on error.
69
+ * Array contains following keys: credit, exhaustion
70
+ */
71
+ public function getCreditInfo($username, $apiKey)
72
+ {
73
+ if (empty($username) || empty($apiKey)) {
74
+ $this->setError('Username or API key not set.');
75
+ return false;
76
+ }
77
+
78
+ // Prepare request
79
+ $data = array(
80
+ 'task' => 'get_credit_info',
81
+ 'username' => $username,
82
+ 'api_key' => $apiKey
83
+ );
84
+
85
+ // Send request
86
+ $http = AHttpHelper::getInstance();
87
+ $out = $http->sendRequest(self::$serviceUrl, $data);
88
+ if (!$out) {
89
+ $this->setError('Could not send the HTTP request');
90
+ return false;
91
+ }
92
+
93
+ // Parse the data
94
+ $data = json_decode($out->content);
95
+ if (!$data) {
96
+ $this->setError('Wrong response from server');
97
+ return false;
98
+ }
99
+
100
+ // Check response
101
+ if (!$data->success) {
102
+ $this->setError($data->err.': '.$data->msg);
103
+ return false;
104
+ }
105
+
106
+ // Return the credit
107
+ $result = array(
108
+ 'credit' => (float)$data->credit,
109
+ 'exhaustion' => (int)$data->exhaustion
110
+ );
111
+
112
+ return $result;
113
+ }
114
+
115
+ /**
116
+ * Sends an SMS message from user's account
117
+ *
118
+ * @param string $username SMS Service API username
119
+ * @param string $apiKey SMS Service API key
120
+ * @param string $to Recipient phone number in international format, max 16 characters, no spaces and no leading plus or zeroes
121
+ * @param string $text Text of the message (will be split to several messages if longer than 160 characters,
122
+ * some characters are counted as two: ^, {, }, \, [, ], ~, |, €, newline char)
123
+ * @param string $allowUnicode Whether Unicode SMS is allowed. If enabled, SMS with special characters will be sent as Unicode,
124
+ * limit is 70 characters. If disabled, Unicode characters will be replaced with ASCII or removed
125
+ * if replacement is not possible. If enabled and SMS doesn't contain any special characters,
126
+ * SMS will be sent normally (160 chars limit).
127
+ * @return bool True on success or false on error
128
+ */
129
+ public function sendMessage($username, $apiKey, $to, $text, $allowUnicode = false)
130
+ {
131
+ if (empty($username) || empty($apiKey) || empty($to) || empty($text)) {
132
+ $this->setError('Some parameters not set.');
133
+ return false;
134
+ }
135
+
136
+ // Fix the phone number
137
+ $to = ltrim($to, '+0');
138
+ $to = str_replace(' ', '', $to);
139
+
140
+ // Validate the phone number
141
+ if ((strlen($to) > 16)) {
142
+ $this->setError('Incorrect recipient phone number format.');
143
+ return false;
144
+ }
145
+
146
+ // Prepare request
147
+ $data = array(
148
+ 'task' => 'send_sms',
149
+ 'username' => $username,
150
+ 'api_key' => $apiKey,
151
+ 'to' => $to,
152
+ 'text' => $text,
153
+ 'allowUnicode' => ($allowUnicode ? '1' : '0')
154
+ );
155
+
156
+ // Send request
157
+ $http = AHttpHelper::getInstance();
158
+ $out = $http->sendRequest(self::$serviceUrl, $data);
159
+ if (!$out) {
160
+ $this->setError('Could not send the HTTP request');
161
+ return false;
162
+ }
163
+
164
+ // Parse the data
165
+ $data = json_decode($out->content);
166
+ if (!$data) {
167
+ $this->setError('Wrong response from server');
168
+ return false;
169
+ }
170
+
171
+ // Check response
172
+ if (!$data->success) {
173
+ $this->setError($data->err.': '.$data->msg);
174
+ return false;
175
+ }
176
+
177
+ // Message sent successfully
178
+ return true;
179
+ }
180
+
181
+ /**
182
+ * Sends an SMS message from user's account to his own phone number (set in SMS Services)
183
+ *
184
+ * @param string $username SMS Service API username
185
+ * @param string $apiKey SMS Service API key
186
+ * @param string $text Text of the message (will be split to several messages if longer than 160 characters,
187
+ * some characters are counted as two: ^, {, }, \, [, ], ~, |, €, newline char)
188
+ * @return bool True on success or false on error
189
+ */
190
+ public function sendOwnMessage($username, $apiKey, $text)
191
+ {
192
+ if (empty($username) || empty($apiKey) || empty($text)) {
193
+ $this->setError('Some parameters not set.');
194
+ return false;
195
+ }
196
+
197
+ // Prepare request
198
+ $data = array(
199
+ 'task' => 'send_own_sms',
200
+ 'username' => $username,
201
+ 'api_key' => $apiKey,
202
+ 'text' => $text
203
+ );
204
+
205
+ // Send request
206
+ $http = AHttpHelper::getInstance();
207
+ $out = $http->sendRequest(self::$serviceUrl, $data);
208
+ if (!$out) {
209
+ $this->setError('Could not send the HTTP request');
210
+ return false;
211
+ }
212
+
213
+ // Parse the data
214
+ $data = json_decode($out->content);
215
+ if (!$data) {
216
+ $this->setError('Wrong response from server');
217
+ return false;
218
+ }
219
+
220
+ // Check response
221
+ if (!$data->success) {
222
+ $this->setError($data->err.': '.$data->msg);
223
+ return false;
224
+ }
225
+
226
+ // Message sent successfully
227
+ return true;
228
+ }
229
+
230
+ /**
231
+ * Loads and returns the array of available credit amounts for purchase and the purchase URL
232
+ *
233
+ * @return array Associative array of [creditValues] => Credit amounts available for purchase ([value] => text)
234
+ * [link] => Purchase URL
235
+ */
236
+ public function getCreditPurchaseInfo()
237
+ {
238
+ // Prepare request
239
+ $data = array(
240
+ 'task' => 'get_credit_purchase_info'
241
+ );
242
+
243
+ // Send request
244
+ $http = AHttpHelper::getInstance();
245
+ $out = $http->sendRequest(self::$serviceUrl, $data);
246
+ if (!$out) {
247
+ $this->setError('Could not send the HTTP request');
248
+ return false;
249
+ }
250
+
251
+ // Parse the data
252
+ $data = json_decode($out->content);
253
+ if (!$data) {
254
+ $this->setError('Wrong response from server');
255
+ return false;
256
+ }
257
+
258
+ // Check response
259
+ if (!$data->success) {
260
+ $this->setError($data->err.': '.$data->msg);
261
+ return false;
262
+ }
263
+
264
+ // Return credit values
265
+ $result = array(
266
+ 'creditValues' => $data->creditValues,
267
+ 'link' => $data->link
268
+ );
269
+
270
+ return $result;
271
+ }
272
+ }
lib/Varien/Data/Form/Element/Accountinfo.php ADDED
@@ -0,0 +1,138 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+
17
+ /**
18
+ *
19
+ *
20
+ * @category Varien
21
+ * @package Varien_Data
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Varien_Data_Form_Element_Accountinfo extends Varien_Data_Form_Element_Abstract
25
+ {
26
+ public function __construct($attributes=array())
27
+ {
28
+ parent::__construct($attributes);
29
+ }
30
+
31
+ public function getHtml()
32
+ {
33
+ $helper = Mage::helper('smsnotify');
34
+ $service = Mage::getSingleton('smsnotify/service');
35
+
36
+ $statusError = $service->testCredentials();
37
+
38
+ if (!$statusError)
39
+ {
40
+ $info = $service->getCreditInfo();
41
+ $purchase = $service->getCreditPurchaseInfo();
42
+ $username = $service->getUsername();
43
+ $apikey = $service->getApikey();
44
+
45
+ $creditLabel = $helper->__('Your credit');
46
+ $exhaustionLabel = $helper->__('Estimated credit exhaustion');
47
+ $purchaseLabel = $helper->__('Purchase');
48
+ $purchaseText = $helper->__('Purchase credit now');
49
+
50
+ $credit = $info['credit'];
51
+ $exhaus = $info['exhaustion'] ? $info['exhaustion'].' h' : $helper->__('No data for computation');
52
+
53
+ $opts = $purchase['creditValues'];
54
+ $link = $purchase['link'];
55
+
56
+ $html = "";
57
+ $html .= "<tr><td></td><td colspan=\"1\"><span class=\"smscredit\">$creditLabel:&nbsp;<b>$credit</b></span></td></tr>";
58
+ $html .= "<tr><td></td><td colspan=\"1\"><span class=\"exhaus\">$exhaustionLabel:&nbsp;<b>$exhaus</b></span></td></tr>";
59
+ $html .= "<tr><td></td><td colspan=\"1\">";
60
+ $html .= "$purchaseText<br />";
61
+ $html .= "<select id=\"smscreditamount\">";
62
+
63
+ foreach ($opts as $k=>$v)
64
+ $html .= "<option value=\"".$k."\">".$v."</option>";
65
+
66
+ $html .= "</select>";
67
+ $html .= "<button id=\"smspurchasebutton\" type=\"button\">$purchaseLabel</button>";
68
+ $html .= "</td></tr>";
69
+
70
+ $html .= $this->getJavascript($link, $username, $apikey);
71
+ }
72
+ else
73
+ {
74
+ $statusError = $helper->__('Connection failed.').' '.$statusError;
75
+
76
+ $html = "<tr><td></td><td colspan=\"1\"><div class=\"error\">$statusError</div></td></tr>";
77
+ }
78
+
79
+ return $html;
80
+ }
81
+
82
+
83
+ /**
84
+ * Get Javascript code for wokring this controls.
85
+ *
86
+ * @return string
87
+ */
88
+ public function getJavascript($url, $username, $apikey)
89
+ {
90
+ $html = "";
91
+
92
+ $html .= "<script type=\"text/javascript\">";
93
+ $html .= "//<![CDATA[";
94
+
95
+ $html .= "
96
+ document.observe('dom:loaded', function(event) {
97
+
98
+ var f = document.createElement(\"form\");
99
+ f.setAttribute('method','post');
100
+ f.setAttribute('action','$url');
101
+ f.setAttribute('target', '_blank');
102
+ f.setAttribute('style','display:none');
103
+
104
+ var i = document.createElement('input');
105
+ i.setAttribute('type','hidden');
106
+ i.setAttribute('name','credit');
107
+ i.setAttribute('id','creditValues');
108
+
109
+ var u = document.createElement('input');
110
+ u.setAttribute('type','hidden');
111
+ u.setAttribute('name','username');
112
+ u.setAttribute('value','$username');
113
+
114
+ var a = document.createElement('input');
115
+ a.setAttribute('type','hidden');
116
+ a.setAttribute('name','api_key');
117
+ a.setAttribute('value','$apikey');
118
+
119
+ f.appendChild(i);
120
+ f.appendChild(u);
121
+ f.appendChild(a);
122
+
123
+ document.getElementsByTagName('body')[0].appendChild(f);
124
+
125
+ $('smspurchasebutton').observe('click', function(event) {
126
+ $('creditValues').value = $('smscreditamount').value;
127
+ f.submit();
128
+ });
129
+ });
130
+ ";
131
+
132
+ $html .= "//]]>";
133
+ $html .= "</script>";
134
+
135
+ return $html;
136
+ }
137
+
138
+ }
lib/Varien/Data/Form/Element/Numberfilters.php ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Form text element
19
+ *
20
+ * @category Varien
21
+ * @package Varien_Data
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Varien_Data_Form_Element_Numberfilters extends Varien_Data_Form_Element_Abstract
25
+ {
26
+
27
+ /**
28
+ *
29
+ */
30
+ public function __construct($attributes=array())
31
+ {
32
+ parent::__construct($attributes);
33
+ $this->setType('text');
34
+ $this->setExtType('textfield');
35
+ }
36
+
37
+
38
+ /**
39
+ * Get element HTML
40
+ * @return string
41
+ */
42
+ public function getElementHtml()
43
+ {
44
+ $h = Mage::helper('smsnotify');
45
+
46
+ $name = $this->getName();
47
+ $id = $this->getHtmlId();
48
+ $value = $this->getValue();
49
+
50
+ $html = "
51
+ <div id=\"$id\">
52
+ <div>
53
+ <select class=\"country-codes\" id=\"$id-filterTable-country\" onchange=\"$id.filterTable.changeCountry()\"></select>
54
+ <div class=\"numberfilters-table-wrapper\">
55
+ <table class=\"border\" cellpadding=\"0\" cellspacing=\"0\">
56
+ <tbody id=\"$id-filterTable\">
57
+ <tr id=\"$id-filterTable-template\" style=\"display:none\">
58
+ <td class=\"first\"><span class=\"prefix\"></span></td>
59
+ <td><span class=\"value\" onclick=\"$id.openDialog($id.filterTable, this)\">*</span>
60
+ <td class=\"last\"><button type=\"button\" class=\"delete\" onclick=\"$id.filterTable.removeFilter(this);\"><span></span></button>
61
+ </tr>
62
+ </tbody>
63
+ </table>
64
+ </div>
65
+ <button class=\"add-button\" type=\"button\" onclick=\"$id.openDialog($id.filterTable);\">".$h->__('Add filter')."</button>
66
+ <input type=\"hidden\" id=\"$id-filterTable-field\" name=\"$name\" value=\"$value\" />
67
+ </div>
68
+ </div>
69
+ <div class=\"numberfilters-dialog-wrapper\">
70
+ <div id=\"$id-dialog\" class=\"numberfilters-dialog\" style=\"display:none\">
71
+ <div class=\"entry-edit-head\">
72
+ <a href=\"javascript:void(0)\" onclick=\"$id.closeDialog()\" class=\"close-button\"></a>
73
+ <a href=\"javascript:void(0)\">".$h->__('Build filter')."</a>
74
+ </div>
75
+ <div class=\"numberfilters-dialog-inner box\">
76
+ <ul>
77
+ <li>
78
+ <input type=\"radio\" class=\"radio\" name=\"$id-type\" id=\"$id-dialog-type-2\" onclick=\"$id.dialog.setType(true)\" checked=\"checked\" value=\"2\" />".$h->__('Range')."
79
+ <input type=\"radio\" class=\"radio radio-right\" name=\"$id-type\" id=\"$id-dialog-type-1\" onclick=\"$id.dialog.setType(false)\" value=\"1\" />".$h->__('Pattern')."
80
+ </li>
81
+ <li>
82
+ <div id=\"$id-dialog-digits-1\">
83
+ <select class=\"digits\" onchange=\"$id.dialog.selectDigit(this)\"></select>
84
+ </div>
85
+ <div id=\"$id-dialog-digits-2\">
86
+ <select class=\"digits\" onchange=\"$id.dialog.selectDigit(this)\"></select>
87
+ </div>
88
+ </li>
89
+ <li>
90
+ <button class=\"right\" type=\"button\" onclick=\"$id.saveDialog()\">".$h->__('Close')."</button>
91
+ <button type=\"button\" onclick=\"$id.saveDialog()\">".$h->__('Ok')."</button>
92
+ </li>
93
+ </ul>
94
+ </div>
95
+ </div>
96
+ </div>
97
+ </div>
98
+ <script type=\"text/javascript\">
99
+ if (typeof(NumberFilters) != 'undefined')
100
+ {
101
+ var $id = new NumberFilters('$id');
102
+ new Draggable('$id-dialog');
103
+ }
104
+ </script>";
105
+
106
+ return $html;
107
+ }
108
+
109
+ }
lib/Varien/Data/Form/Element/Selectdynamic.php ADDED
@@ -0,0 +1,36 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Form text element
19
+ *
20
+ * @category Varien
21
+ * @package Varien_Data
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Varien_Data_Form_Element_SelectDynamic extends Varien_Data_Form_Element_Select
25
+ {
26
+
27
+ public function getAfterElementHtml()
28
+ {
29
+ $html = parent::getAfterElementHtml();
30
+
31
+ $html .= '<input type="hidden" id="'.$this->getHtmlId().'-hidden" value="'.$this->getValue().'" />';
32
+
33
+ return $html;
34
+ }
35
+
36
+ }
lib/Varien/Data/Form/Element/Smstextarea.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * SMS Notifier
4
+ *
5
+ * NOTICE OF LICENSE
6
+ *
7
+ * This source file is subject to the Academic Free License (AFL 3.0)
8
+ * It is available through the world-wide-web at this URL:
9
+ * http://opensource.org/licenses/afl-3.0.php
10
+ *
11
+ * @category Artio
12
+ * @package Artio_SMSNotifier
13
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
14
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
15
+ */
16
+
17
+ /**
18
+ * Form text element
19
+ *
20
+ * @category Varien
21
+ * @package Varien_Data
22
+ * @author Artio Magento Team <info@artio.net>
23
+ */
24
+ class Varien_Data_Form_Element_Smstextarea extends Varien_Data_Form_Element_Textarea
25
+ {
26
+ public function __construct($attributes=array())
27
+ {
28
+ parent::__construct($attributes);
29
+ $this->setType('textarea');
30
+ $this->setExtType('textarea');
31
+ $this->setRows(2);
32
+ $this->setCols(15);
33
+ }
34
+
35
+
36
+ /**
37
+ *
38
+ * @return string
39
+ */
40
+ public function getHtmlId()
41
+ {
42
+ $form = $this->getForm();
43
+
44
+ if ($form)
45
+ return $form->getHtmlIdPrefix() . $this->getData('html_id') . $form->getHtmlIdSuffix();
46
+ else
47
+ return $this->getData('html_id');
48
+ }
49
+
50
+
51
+ /**
52
+ *
53
+ * @return string
54
+ */
55
+ public function getName()
56
+ {
57
+ $form = $this->getForm();
58
+
59
+ if ($form && $suffix = $this->getForm()->getFieldNameSuffix())
60
+ $name = $this->getForm()->addSuffixToName($name, $suffix);
61
+ else
62
+ $name = $this->getData('name');
63
+
64
+ return $name;
65
+ }
66
+
67
+ public function getHtmlAttributes()
68
+ {
69
+ return array('title', 'class', 'style', 'onclick', 'onchange', 'rows', 'cols', 'readonly', 'disabled', 'onkeyup', 'tabindex');
70
+ }
71
+
72
+ public function getElementHtml()
73
+ {
74
+ $helper = Mage::helper('smsnotify');
75
+
76
+ $id = $this->getHtmlId();
77
+ $remain = $this->getHtmlId().'-remain';
78
+ $chars = $this->getHtmlId().'-chars';
79
+ $messages = $this->getHtmlId().'-messages';
80
+
81
+ $this->addClass('textarea');
82
+ $html = '';
83
+
84
+ $html .= '<span class="'.$id.'-static-value">'.$helper->__('Remain <b><span class="%s"></span></b> characters to new message.', $remain).'</span>';
85
+ $html .= '<span class="'.$id.'-dynamic-value">'.$helper->__('Remain about <b><span class="%s"></span></b> characters to new message.', $remain).'</span>';
86
+ $html .= '<br />';
87
+ $html .= '<p class="button-bar">';
88
+ $html .= '<span>'.$helper->__('Variables:').'</span>';
89
+ if ($id == 'sms_text')
90
+ {
91
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer firstname to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::CUSTOMER_FIRSTNAME.'</span>'.$helper->__('Customer Firstname').'</a>';
92
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer lastname to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::CUSTOMER_LASTNAME.'</span>'.$helper->__('Customer Lastname').'</a>';
93
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer email to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::CUSTOMER_EMAIL.'</span>'.$helper->__('Customer Email').'</a>';
94
+ }
95
+ else
96
+ {
97
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer firstname to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_FIRSTNAME.'</span>'.$helper->__('Customer Firstname').'</a>';
98
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer lastname to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_LASTNAME.'</span>'.$helper->__('Customer Lastname').'</a>';
99
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button" title="'.$helper->__('Append customer email to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_EMAIL.'</span>'.$helper->__('Customer Email').'</a>';
100
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button amount" title="'.$helper->__('Append total amount to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_AMOUNT.'</span>'.$helper->__('Amount').'</a>';
101
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button invoice" title="'.$helper->__('Append invoice increment id to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_INVOICE_NR.'</span>'.$helper->__('Invoice Nr.').'</a>';
102
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button shipment" title="'.$helper->__('Append shipment increment id to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_SHIPMENT_NR.'</span>'.$helper->__('Shipment Nr.').'</a>';
103
+ $html .= '<a href="javascript:void(0)" class="'.$id.'-variable-button order" title="'.$helper->__('Append order increment id to message').'" type="button"><span class="text">'.Artio_SMSNotifier_Model_Sms_Template::SALE_ORDER_NR.'</span>'.$helper->__('Order Nr.').'</a>';
104
+ }
105
+ //$html .= '<button class="'.$id.'-variable-button" title="'.$helper->__('Append customer firstname to message').'" type="button"><span class="text">{{firstname}}</span>'.$helper->__('Customer Firstname').'</button>';
106
+ //$html .= '<button class="'.$id.'-variable-button" title="'.$helper->__('Append customer lastname to message').'" type="button"><span class="text">{{lastname}}</span>'.$helper->__('Customer Lastname').'</button>';
107
+ //$html .= '<button class="'.$id.'-variable-button" title="'.$helper->__('Append customer email to message').'" type="button"><span class="text">{{email}}</span>'.$helper->__('Customer Email').'</button>';
108
+ $html .= '</p>';
109
+ $html .= '<textarea id="'.$id.'" name="'.$this->getName().'" '.$this->serialize($this->getHtmlAttributes()).' >';
110
+ $html .= $this->getEscapedValue();
111
+ $html .= "</textarea>";
112
+ $html .= '<span class="'.$id.'-static-value">'.$helper->__('You have written <b><span class="%s"></span></b> character(s).', $chars).'</span> ';
113
+ $html .= '<span class="'.$id.'-dynamic-value">'.$helper->__('You have written about <b><span class="%s"></span></b> character(s).', $chars).'</span> ';
114
+ $html .= '<span class="'.$id.'-static-value">'.$helper->__('Text will be sended as <b><span class="%s"></span></b> message(s).', $messages).'</span>';
115
+ $html .= '<span class="'.$id.'-dynamic-value">'.$helper->__('Text will be sended perhaps as <b><span class="%s"></span></b> message(s).', $messages).'</span>';
116
+ $html .= '<br class="'.$id.'-dynamic-value" /><span class="'.$id.'-dynamic-value">'.$helper->__('Keep in mind that if you use variables then the values on counters above are only estimates. Really length of message depends on values of those variables. The texts which are longer than <b>160</b> chars will be splitted to more messages.').'</span>';
117
+ $html .= '<br />';
118
+ $html .= '<span><i>'.$helper->__('Note some special chars (ex.: ^, {, }, \, [, ], ~, |, €, newline char) may cost 2 chars.').'</i></span>';
119
+ $html .= $this->getAfterElementHtml();
120
+
121
+ $html .= "
122
+ <script type=\"text/javascript\">
123
+ //<![CDATA[
124
+
125
+ function ${id}_smstextarea_reloading() {
126
+
127
+ var regex = new RegExp('{{[^}]*}}');
128
+
129
+ var recompute = function(event) {
130
+ var count = 0;
131
+ var value = $('$id').value;
132
+ var ch2 = '^{}[]~|€';
133
+
134
+ var hide = function(el) { el.hide(); };
135
+ var show = function(el) { el.show(); };
136
+
137
+ if (regex.test(value)) {
138
+ $$('.${id}-static-value').each(hide);
139
+ $$('.${id}-dynamic-value').each(show);
140
+ } else {
141
+ $$('.${id}-static-value').each(show);
142
+ $$('.${id}-dynamic-value').each(hide);
143
+ }
144
+
145
+ for (var i=0; i<value.length; i++) {
146
+ var ch = value.charAt(i);
147
+ var chc = value.charCodeAt(i);
148
+ if (chc == 10 || chc == 92 || ch2.indexOf(ch) > -1)
149
+ count = count+2;
150
+ else
151
+ count++;
152
+ }
153
+
154
+ $$('.$chars').each(function(el) { el.innerHTML = count; });
155
+ $$('.$messages').each(function(el) { el.innerHTML = Math.floor((count-1) / 160 + 1) });
156
+ $$('.$remain').each(function(el) { el.innerHTML = 160 - (count % 160); });
157
+ };
158
+
159
+ $('$id').observe('change', recompute);
160
+ $('$id').observe('keyup', recompute);
161
+ recompute(null);
162
+
163
+ $$('.${id}-variable-button').each(function(button) {
164
+ button.observe('click', function(event) {
165
+ var val = button.select('span.text').first().innerHTML;
166
+ $('$id').value = $('$id').value + val;
167
+ recompute(event);
168
+ });
169
+ });
170
+
171
+ $$('.${id}-variable-button').last().addClassName('last');
172
+ }
173
+
174
+ document.observe('dom:loaded', function(event) {
175
+ ${id}_smstextarea_reloading();
176
+ });
177
+ //]]>
178
+ </script>
179
+ ";
180
+
181
+ return $html;
182
+ }
183
+ }
package.xml ADDED
@@ -0,0 +1,19 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <package>
3
+ <name>SMSNotifier</name>
4
+ <version>1.0.0</version>
5
+ <stability>stable</stability>
6
+ <license uri="http://www.artio.net/general/legal-documents">Copyright 2013, ARTIO s.r.o. All rights reserved.</license>
7
+ <channel>community</channel>
8
+ <extends/>
9
+ <summary>SMS Notifier</summary>
10
+ <description>Magento tool to send SMS messages on different events. Let customers know about their order status change.</description>
11
+ <notes>Visit product homepage at:
12
+ http://www.artio.net/e-shop/magento-extensions/magento-sms-notifier</notes>
13
+ <authors><author><name>Luk&#xE1;&#x161; Bialo&#x148;</name><user>auto-converted</user><email>lukas.bialon@artio.net</email></author><author><name>Ji&#x159;&#xED; Chmiel</name><user>auto-converted</user><email>jiri.chmiel@artio.net</email></author></authors>
14
+ <date>2013-08-30</date>
15
+ <time>16:25:03</time>
16
+ <contents><target name="magedesign"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="layout"><file name="smsnotify.xml" hash="cb8f765f6a7df728764119b3c87f2308"/></dir><dir name="template"><dir name="smsnotify"><dir name="order"><dir name="view"><file name="history.phtml" hash="9fd5457941b5060da17515447fda18e0"/></dir><dir name="comments"><file name="view.phtml" hash="86154a1c4129198fa576e921fbbb2941"/></dir></dir></dir></dir></dir></dir></dir></target><target name="magecommunity"><dir name="Artio"><dir name="SMSNotifier"><dir name="controllers"><file name="AdminhtmlController.php" hash="8f3109bcc56b1355e7623cfdee183200"/></dir><dir name="Model"><dir name="Sms"><file name="Template.php" hash="64b5b81c69552307af66b3c209a15bc4"/><file name="Observer.php" hash="c628c7295e8ead74d8616e475f194d0c"/></dir><dir name="System"><dir name="Config"><dir name="Source"><file name="CountryFilter.php" hash="cface077f87945702f0f88a1dad54f4c"/><file name="Log.php" hash="c1663898225e6ef2fc73a5b9782b8b75"/><file name="Gateway.php" hash="d450d78264a43dd10f71f218c45d9a5c"/><file name="SendToAdmin.php" hash="30a23357c183f0aa8c098653178dbcd3"/><file name="Addresses.php" hash="506541d6d422a7a4a2e361766c3c2a7b"/></dir></dir></dir><file name="Sms.php" hash="063984eb94351f9aedc0d1eca8d0a09e"/><file name="Service.php" hash="93c0f34a24c119808d70ac140021c568"/><file name="Config.php" hash="ae17bff200f74875ab16e6d12c8dd120"/><file name="Observer.php" hash="790f88d23ba35b832d32458d0afd098b"/></dir><dir name="Block"><dir name="Adminhtml"><dir name="Send"><file name="Form.php" hash="2e6010c3cfa73d728e87558d9f54269a"/></dir><dir name="Data"><dir name="Form"><dir name="Element"><file name="CustomerNumbers.php" hash="5a9c081e4c28efa2db91f41618502a4b"/></dir></dir></dir><file name="Send.php" hash="56cb701ea7ae77b039f566f24d3d2944"/></dir></dir><dir name="etc"><file name="adminhtml.xml" hash="12b4f6eaf98b3ec8bf6c0e1d0fb54d88"/><file name="system.xml" hash="8ca07c1fef801e7af49c8636a83c5453"/><file name="config.xml" hash="76c19693fc13e0e09250f44233823168"/></dir><dir name="Helper"><file name="Data.php" hash="2ea5d0ff331938c387a0b0ae3c2726d4"/><file name="SMSLog.php" hash="e889508e6eea7a5577429d206ac55a6e"/></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Artio_SMSNotifyForMagento.xml" hash="7389e8a15b874b39a1b6a22800939b32"/></dir></target><target name="mage"><dir name="js"><dir name="artio"><file name="numberfilters.js" hash="e93f1c0ac0a0c160574524465571a9b2"/></dir></dir></target><target name="mageskin"><dir name="adminhtml"><dir name="default"><dir name="default"><dir name="images"><file name="entry_edit_head_arrow_x.gif" hash="3c49e7bbb6de956a903e6a018ca78477"/><file name="ico_mobil.png" hash="f69f028a51e391f1762bbfe150db8dd9"/></dir><file name="smsnotify.css" hash="31db226a9f2818a324e53d5fb549a6e2"/></dir></dir></dir></target><target name="magelib"><dir name="Varien"><dir name="Data"><dir name="Form"><dir name="Element"><file name="Numberfilters.php" hash="3a0837438a7ecb3b782560fe6a57596e"/><file name="Selectdynamic.php" hash="b525c625719d6489c09d87eb5a7025df"/><file name="Smstextarea.php" hash="ca482cf592bb6527c337b2d8cd1a0dad"/><file name="Accountinfo.php" hash="e3c6c03d33875c4e01c0427e18abcd65"/></dir></dir></dir></dir><dir name="Artio"><dir name="SMSService"><file name="smsservice.php" hash="49bcb6edd9f6fb4253867420d5e8b01b"/><file name="httphelper.php" hash="dea608b37e266a8e0ce1fee336d7a36c"/></dir></dir></target></contents>
17
+ <compatible/>
18
+ <dependencies/>
19
+ </package>
skin/adminhtml/default/default/images/entry_edit_head_arrow_x.gif ADDED
Binary file
skin/adminhtml/default/default/images/ico_mobil.png ADDED
Binary file
skin/adminhtml/default/default/smsnotify.css ADDED
@@ -0,0 +1,109 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /**
2
+ * SMS Notifier
3
+ *
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the Academic Free License (AFL 3.0)
7
+ * It is available through the world-wide-web at this URL:
8
+ * http://opensource.org/licenses/afl-3.0.php
9
+ *
10
+ * @category Artio
11
+ * @package Artio_SMSNotifier
12
+ * @copyright Copyright (c) 2013 Artio s.r.o (http://www.artio.net/)
13
+ * @license http://opensource.org/licenses/afl-3.0.php Academic Free License (AFL 3.0)
14
+ */
15
+
16
+ /** SYSTEM CONFIGURATION FILTER ============================================ */
17
+
18
+ table.border { width:100%; background:#fff; border-collapse:collapse; }
19
+ table.border td { padding:0 3px; vertical-align:middle; border:1px solid #eee; }
20
+ table.border td.last { text-align:right; width:36px; }
21
+ table.border td.first { text-align:right; width:40px; }
22
+
23
+ span.prefix { font-weight:bold; color:#888; }
24
+ span.value { font-weight:bold; font-weight: bold; display: block; width: 100%; cursor: pointer; }
25
+ span.value:hover { background: #e7efef; }
26
+
27
+ .numberfilters-dialog-wrapper { position:relative; }
28
+ .numberfilters-dialog { position:absolute; left:0; top:0; margin-left:-120px; margin-top:-60px; }
29
+ .numberfilters-dialog-inner { background:#e7efef; border:1px solid #dadada; }
30
+ .numberfilters-dialog .entry-edit-head { margin:0 20px; }
31
+ .numberfilters-dialog .entry-edit-head a { text-decoration:none; }
32
+ .numberfilters-dialog .entry-edit-head a.close-button { display:block; float:right; width:19px; height:18px; background:url(images/entry_edit_head_arrow_x.gif) no-repeat left top; }
33
+ .numberfilters-dialog-inner { margin:0 20px 20px; width:610px; opacity:1.0; }
34
+ .numberfilters-dialog-inner select { width:33px !important; margin:0 5px 10px 0; }
35
+ .numberfilters-dialog-inner input.radio { margin-right:5px; }
36
+ .numberfilters-dialog-inner input.radio-right { margin-left:10px; }
37
+ .numberfilters-dialog-inner ul li { margin-bottom:10px; }
38
+ .empty-filter .numberfilters-table-wrapper { border:0; margin:10px 0 0; }
39
+ .numberfilters-table-wrapper { margin:10px 0px 5px; border:1px solid; width:280px; border-color: #aaa #c8c8c8 #c8c8c8 #aaa; }
40
+
41
+ button.add-button { padding:2px 15px; }
42
+ option.has-filter { background:#ccc; }
43
+ button.delete span { background-position-x:3px; }
44
+
45
+ /** SEND SMS =============================================================== */
46
+
47
+ div#sendsms_fieldset td.value { width:280px; }
48
+
49
+ #table-numbers { width:100%; border-color:#aaa #c8c8c8 #c8c8c8 #aaa; border-width:1px; border-style:solid; }
50
+ #table-numbers.empty-table { display:none; }
51
+ #table-numbers td { background:#fff; }
52
+ #table-numbers td.last { width:20px; }
53
+
54
+ #customer_numbers { margin-bottom:2px; }
55
+
56
+ #search_autocomplete { background: #fff; border: 1px solid #aaa; width: 278px !important; }
57
+ #search_autocomplete.empty-list { display:none; }
58
+ #search_autocomplete ul li { cursor: pointer; font-weight: bold; padding: 0px 5px; font-size: 11px; border-bottom:1px dotted #eee; }
59
+ #search_autocomplete ul li.not-allowed { font-weight: normal; font-style: italic; color: #aaa; }
60
+ #search_autocomplete ul li:hover { background:#eee; }
61
+ #search_autocomplete ul li.not-allowed:hover { backgound:#fff; }
62
+
63
+ /** TextArea ================================================================== */
64
+
65
+ .button-bar { margin:0; }
66
+ .button-bar a { margin:5px 0 5px 5px; text-decoration:none; border-right:1px solid #ea7601; padding-right:5px; }
67
+ .button-bar a.last { border:0; }
68
+ .button-bar a:hover { text-decoration:underline; }
69
+ .button-bar a span { display:none; }
70
+
71
+ /** System Config ============================================================= */
72
+
73
+ .smsnotify-section span { background: url(images/ico_mobil.png) no-repeat 1px 4px !important; }
74
+ a.smsnotify-section.active span { background: #fff url(images/ico_mobil.png) no-repeat 1px 4px !important; }
75
+
76
+ #smsnotify_new_order td.value,
77
+ #smsnotify_new_invoice td.value,
78
+ #smsnotify_new_shipment td.value { width:600px; }
79
+ #smsnotify_new_order td.value textarea,
80
+ #smsnotify_new_invoice td.value textarea,
81
+ #smsnotify_new_shipment td.value textarea { width:590px; }
82
+
83
+ #smsnotify_new_order .button-bar a.invoice,
84
+ #smsnotify_new_order .button-bar a.shipment,
85
+ #smsnotify_new_invoice .button-bar a.shipment,
86
+ #smsnotify_new_shipment .button-bar a.invoice,
87
+ #smsnotify_new_shipment .button-bar a.amount { display:none; }
88
+
89
+ /** Credit info config ========================================================= */
90
+
91
+ span.smscredit { display:block; width:290px; border-top:1px solid #ccc; margin-top:10px; padding-top:5px; }
92
+ span.exhaus { display:block; width:290px; border-bottom:1px solid #ccc; margin-bottom:10px; padding-bottom:5px; }
93
+ #smspurchasebutton { margin-left:10px; }
94
+ div.error { padding:0 5px; }
95
+
96
+ /** History ===================================================================== */
97
+
98
+ .menu-item { background:#6f8992; color:white; cursor:pointer; float:left; margin-left:5px; width:80px; border:1px solid #ddd; position:relative; top:1px; text-align:center; }
99
+ .menu-item.active { background:#fafafa; color:black; border-bottom:0; top:2px; }
100
+ .menu-item.first { margin:0; }
101
+
102
+ #history-sms textarea { height:6em; width:99%; }
103
+ #history-sms .button-bar { display:none; }
104
+
105
+ .history-form { border:1px solid #ddd; padding:10px; /*background:#fcfac9*/ }
106
+
107
+ .status-field-row { margin-bottom:15px; }
108
+
109
+ .note-list li.mobil { background:url(images/ico_mobil.png) no-repeat 0 4px; }