SalesTax_Connector - Version 3.1.4

Version Notes

Simplify sales and use tax calculation, compliance, and management in the cloud!

Download this release

Release Info

Developer Magento Core Team
Extension SalesTax_Connector
Version 3.1.4
Comparing to
See all releases


Code changes from version 3.1.3 to 3.1.4

app/code/local/Harapartners/ConnectorHub/Helper/Connector/Core.php ADDED
@@ -0,0 +1,183 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ abstract class Harapartners_ConnectorHub_Helper_Connector_Core extends Mage_Core_Helper_Abstract {
14
+
15
+ const REQUEST_ACTION_AUTHENTICATION = 'authentication';
16
+
17
+ const REQUEST_SERVICE_MODE_TEST = 0;
18
+ const REQUEST_SERVICE_MODE_SANDBOX = 10;
19
+ const REQUEST_SERVICE_MODE_BETA = 50;
20
+ const REQUEST_SERVICE_MODE_PRODUCTION = 100;
21
+
22
+ const RESPONSE_STATUS_FAIL = 0;
23
+ const RESPONSE_STATUS_SUCCESS = 100;
24
+ const RESPONSE_STATUS_REAUTH = 200;
25
+
26
+ const DEFAULT_CURLOPT_TIMEOUT = 60;
27
+
28
+ protected $_serviceType = null;
29
+
30
+ protected function _processRequest($request){
31
+ // -------------- Prepare additional request meta -------------- //
32
+ $adminEmail = "";
33
+ if(!!Mage::getSingleton('admin/session')->getUser()){
34
+ $adminEmail = Mage::getSingleton('admin/session')->getUser()->getEmail();
35
+ }
36
+ $request['meta'] = array_merge($request['meta'], array(
37
+ 'service_type' => $this->getServiceType(),
38
+ 'service_mode' => $this->getServiceMode(),
39
+ 'auth_token' => $this->getToken('auth_token'),
40
+ 'site_url' => Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB),
41
+ 'account_name' => $adminEmail,
42
+ 'platform' => 'magento',
43
+ 'version' => Mage::getVersion()
44
+ ));
45
+
46
+ if(isset($request['data'])){
47
+ $request['enc_data'] = $this->encryptRequestData($request['data']);
48
+ unset($request['data']);
49
+ }
50
+
51
+ // -------------- Make request -------------- //
52
+ $requestUrl = $this->_getConnectorHubUrl();
53
+ $requestPostData = array('params' => base64_encode(json_encode($request)));
54
+ $requestCh = curl_init();
55
+ curl_setopt($requestCh, CURLOPT_URL, $requestUrl);
56
+ curl_setopt($requestCh, CURLOPT_POST, 1);
57
+ curl_setopt($requestCh, CURLOPT_POSTFIELDS, $requestPostData);
58
+ curl_setopt($requestCh, CURLOPT_SSL_VERIFYPEER, $this->_getCurlSslVerifyPeer());
59
+ curl_setopt($requestCh, CURLOPT_RETURNTRANSFER, 1);
60
+ curl_setopt($requestCh, CURLOPT_TIMEOUT, self::DEFAULT_CURLOPT_TIMEOUT);
61
+ $curlRawResponse = curl_exec($requestCh);
62
+ $response = json_decode(base64_decode($curlRawResponse));
63
+ curl_close($requestCh);
64
+
65
+ // -------------- Process response -------------- //
66
+ if(!$response){
67
+ if($curlRawResponse){
68
+ throw new Exception('Internal Error on Server.');
69
+ }
70
+ throw new Exception('Connection failed.');
71
+ }
72
+ //For now treat reauth the same as fail, the notification will prompt the admin user to update their credentials
73
+ switch($response->meta->status){
74
+ case self::RESPONSE_STATUS_FAIL:
75
+ case self::RESPONSE_STATUS_REAUTH:
76
+ throw new Exception($response->meta->message);
77
+ break;
78
+ case self::RESPONSE_STATUS_SUCCESS:
79
+ break;
80
+ default:
81
+ break;
82
+ }
83
+ if(!!$response->enc_data){
84
+ $dataToken = $this->getToken('data_token');
85
+ $decData = Mage::helper('connectorhub/mcrypt')->init($dataToken)->decrypt(base64_decode($response->enc_data));
86
+ $response->data = json_decode($decData);
87
+ }
88
+
89
+ return $response;
90
+ }
91
+
92
+ public function authenticationRequest($credentials){
93
+ //For authentication request, directly send the data, rather than encrypted data with token
94
+ $request = array(
95
+ 'meta' => array(
96
+ 'action' => self::REQUEST_ACTION_AUTHENTICATION,
97
+ 'credentials' => $credentials
98
+ )
99
+ );
100
+ $response = $this->_processRequest($request);
101
+
102
+ //service_mode can be '0'
103
+ if(is_null($response->meta->service_mode) || !$response->meta->auth_token || !$response->meta->data_token){
104
+ throw new Exception('Authentication failed.');
105
+ }
106
+
107
+ $this->saveTokens($response);
108
+ return $response;
109
+ }
110
+
111
+
112
+ // ======================= Essential overrides ======================= //
113
+ abstract public function getServiceMode();
114
+
115
+ abstract protected function _getConnectorHubUrl();
116
+
117
+ abstract protected function _getConfigDataBasePath($key);
118
+
119
+ abstract protected function _prepareCredentials();
120
+
121
+
122
+ // ====================== Utilities/Helpers ====================== //
123
+ public function getServiceType(){
124
+ return $this->_serviceType;
125
+ }
126
+
127
+ public function getToken($tokenName, $serviceMode = null){
128
+ if(!$serviceMode){
129
+ $serviceMode = $this->getServiceMode();
130
+ }
131
+
132
+ //Load from DB, no cache
133
+ $coreConfigData = Mage::getModel('core/config_data')->load($this->_getConfigDataBasePath('tokens'), 'path');
134
+ $existingToken = json_decode($coreConfigData->getValue(), 1);
135
+ if(isset($existingToken[$serviceMode][$tokenName])){
136
+ return $existingToken[$serviceMode][$tokenName];
137
+ }
138
+ return null;
139
+ }
140
+
141
+ public function saveTokens($response){
142
+ //Save to DB, no cache
143
+ $coreConfigData = Mage::getModel('core/config_data')->load($this->_getConfigDataBasePath('tokens'), 'path');
144
+ //In case the first time save
145
+ $coreConfigData->setpath($this->_getConfigDataBasePath('tokens'));
146
+
147
+ $existingToken = json_decode($coreConfigData->getValue(), 1);
148
+ $existingToken[$response->meta->service_mode] = array(
149
+ 'auth_token' => $response->meta->auth_token,
150
+ 'data_token' => $response->meta->data_token
151
+ );
152
+ $coreConfigData->setValue(json_encode($existingToken));
153
+ $coreConfigData->save();
154
+ return;
155
+ }
156
+
157
+ public function encryptRequestData($requestData){
158
+ //For authentication request, directly send the data, rather than encrypted data with token
159
+ $authToken = $this->getToken('auth_token');
160
+ $dataToken = $this->getToken('data_token');
161
+ $encData = Mage::helper('connectorhub/mcrypt')->init($dataToken)->encrypt(json_encode($requestData));
162
+ return base64_encode($encData);
163
+ }
164
+
165
+ protected function _getCurlSslVerifyPeer(){
166
+ $sslVerifyPeer = 0;
167
+ try{
168
+ $secureUrlScheme = parse_url(Mage::getUrl('', array('_secure'=>true)), PHP_URL_SCHEME);
169
+ if(strcasecmp($secureUrlScheme, "https") == 0){
170
+ $sslVerifyPeer = 1;
171
+ }
172
+ }catch(Exception $e){
173
+ $sslVerifyPeer = 0;
174
+ }
175
+ return $sslVerifyPeer;
176
+ }
177
+
178
+ protected function _getConnectorHubRootUrl(){
179
+ return Mage::getBaseUrl(Mage_Core_Model_Store::URL_TYPE_WEB) . "ConnectorHub/";
180
+ // return "https://connectorhub.harapartners.com/";
181
+ }
182
+
183
+ }
app/code/local/Harapartners/ConnectorHub/Helper/Mcrypt.php ADDED
@@ -0,0 +1,87 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_ConnectorHub_Helper_Mcrypt extends Harapartners_ConnectorHub_Helper_Object {
14
+
15
+ public function init($key)
16
+ {
17
+ if (!$this->getCipher()) {
18
+ $this->setCipher(MCRYPT_BLOWFISH);
19
+ }
20
+
21
+ if (!$this->getMode()) {
22
+ $this->setMode(MCRYPT_MODE_ECB);
23
+ }
24
+
25
+ $this->setHandler(mcrypt_module_open($this->getCipher(), '', $this->getMode(), ''));
26
+
27
+ if (!$this->getInitVector()) {
28
+ if (MCRYPT_MODE_CBC == $this->getMode()) {
29
+ $this->setInitVector(substr(
30
+ md5(mcrypt_create_iv (mcrypt_enc_get_iv_size($this->getHandler()), MCRYPT_RAND)),
31
+ - mcrypt_enc_get_iv_size($this->getHandler())
32
+ ));
33
+ } else {
34
+ $this->setInitVector(mcrypt_create_iv (mcrypt_enc_get_iv_size($this->getHandler()), MCRYPT_RAND));
35
+ }
36
+ }
37
+
38
+ $maxKeySize = mcrypt_enc_get_key_size($this->getHandler());
39
+
40
+ if (strlen($key) > $maxKeySize) { // strlen() intentionally, to count bytes, rather than characters
41
+ $this->setHandler(null);
42
+ throw new Exception('Maximum key size must be smaller '.$maxKeySize);
43
+ }
44
+
45
+ mcrypt_generic_init($this->getHandler(), $key, $this->getInitVector());
46
+
47
+ return $this;
48
+ }
49
+
50
+ public function encrypt($data)
51
+ {
52
+ if (!$this->getHandler()) {
53
+ throw new Exception('Crypt module is not initialized.');
54
+ }
55
+ if (strlen($data) == 0) {
56
+ return $data;
57
+ }
58
+ return mcrypt_generic($this->getHandler(), $data);
59
+ }
60
+
61
+ public function decrypt($data)
62
+ {
63
+ if (!$this->getHandler()) {
64
+ throw new Exception('Crypt module is not initialized.');
65
+ }
66
+ if (strlen($data) == 0) {
67
+ return $data;
68
+ }
69
+ //Encrypt-Decrypt may append "\0", such padding characters must be removed
70
+ return rtrim(mdecrypt_generic($this->getHandler(), $data), "\0");
71
+ }
72
+
73
+
74
+ public function __destruct()
75
+ {
76
+ if ($this->getHandler()) {
77
+ $this->_reset();
78
+ }
79
+ }
80
+
81
+ protected function _reset()
82
+ {
83
+ mcrypt_generic_deinit($this->getHandler());
84
+ mcrypt_module_close($this->getHandler());
85
+ }
86
+
87
+ }
app/code/local/Harapartners/ConnectorHub/Helper/Object.php ADDED
@@ -0,0 +1,161 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_ConnectorHub_Helper_Object {
14
+
15
+ protected $_data = array();
16
+ protected $_hasDataChanges = false;
17
+ protected $_syncFieldsMap = array();
18
+ static protected $_underscoreCache = array();
19
+
20
+ public function __call($method, $args){
21
+ switch (substr($method, 0, 3)) {
22
+ case 'get' :
23
+ //Varien_Profiler::start('GETTER: '.get_class($this).'::'.$method);
24
+ $key = $this->_underscore(substr($method,3));
25
+ $data = $this->getData($key, isset($args[0]) ? $args[0] : null);
26
+ //Varien_Profiler::stop('GETTER: '.get_class($this).'::'.$method);
27
+ return $data;
28
+
29
+ case 'set' :
30
+ //Varien_Profiler::start('SETTER: '.get_class($this).'::'.$method);
31
+ $key = $this->_underscore(substr($method,3));
32
+ $result = $this->setData($key, isset($args[0]) ? $args[0] : null);
33
+ //Varien_Profiler::stop('SETTER: '.get_class($this).'::'.$method);
34
+ return $result;
35
+
36
+ case 'uns' :
37
+ //Varien_Profiler::start('UNS: '.get_class($this).'::'.$method);
38
+ $key = $this->_underscore(substr($method,3));
39
+ $result = $this->unsetData($key);
40
+ //Varien_Profiler::stop('UNS: '.get_class($this).'::'.$method);
41
+ return $result;
42
+
43
+ case 'has' :
44
+ //Varien_Profiler::start('HAS: '.get_class($this).'::'.$method);
45
+ $key = $this->_underscore(substr($method,3));
46
+ //Varien_Profiler::stop('HAS: '.get_class($this).'::'.$method);
47
+ return isset($this->_data[$key]);
48
+ }
49
+ throw new Exception("Invalid method ".get_class($this)."::".$method."(".print_r($args,1).")");
50
+ }
51
+
52
+ public function addData(array $arr) {
53
+ foreach($arr as $index=>$value) {
54
+ $this->setData($index, $value);
55
+ }
56
+ return $this;
57
+ }
58
+
59
+ public function getData($key='', $index=null) {
60
+ if (''===$key) {
61
+ return $this->_data;
62
+ }
63
+
64
+ $default = null;
65
+
66
+ // accept a/b/c as ['a']['b']['c']
67
+ if (strpos($key,'/')) {
68
+ $keyArr = explode('/', $key);
69
+ $data = $this->_data;
70
+ foreach ($keyArr as $i=>$k) {
71
+ if ($k==='') {
72
+ return $default;
73
+ }
74
+ if (is_array($data)) {
75
+ if (!isset($data[$k])) {
76
+ return $default;
77
+ }
78
+ $data = $data[$k];
79
+ } else {
80
+ return $default;
81
+ }
82
+ }
83
+ return $data;
84
+ }
85
+
86
+ // legacy functionality for $index
87
+ if (isset($this->_data[$key])) {
88
+ if (is_null($index)) {
89
+ return $this->_data[$key];
90
+ }
91
+
92
+ $value = $this->_data[$key];
93
+ if (is_array($value)) {
94
+ //if (isset($value[$index]) && (!empty($value[$index]) || strlen($value[$index]) > 0)) {
95
+ /**
96
+ * If we have any data, even if it empty - we should use it, anyway
97
+ */
98
+ if (isset($value[$index])) {
99
+ return $value[$index];
100
+ }
101
+ return null;
102
+ } elseif (is_string($value)) {
103
+ $arr = explode("\n", $value);
104
+ return (isset($arr[$index]) && (!empty($arr[$index]) || strlen($arr[$index]) > 0)) ? $arr[$index] : null;
105
+ }
106
+ return $default;
107
+ }
108
+ return $default;
109
+ }
110
+
111
+ public function setData($key, $value=null) {
112
+ $this->_hasDataChanges = true;
113
+ if(is_array($key)) {
114
+ $this->_data = $key;
115
+ $this->_addFullNames();
116
+ } else {
117
+ $this->_data[$key] = $value;
118
+ if (isset($this->_syncFieldsMap[$key])) {
119
+ $fullFieldName = $this->_syncFieldsMap[$key];
120
+ $this->_data[$fullFieldName] = $value;
121
+ }
122
+ }
123
+ return $this;
124
+ }
125
+
126
+ public function unsetData($key=null) {
127
+ $this->_hasDataChanges = true;
128
+ if (is_null($key)) {
129
+ $this->_data = array();
130
+ } else {
131
+ unset($this->_data[$key]);
132
+ if (isset($this->_syncFieldsMap[$key])) {
133
+ $fullFieldName = $this->_syncFieldsMap[$key];
134
+ unset($this->_data[$fullFieldName]);
135
+ }
136
+ }
137
+ return $this;
138
+ }
139
+
140
+ protected function _addFullNames() {
141
+ $existedShortKeys = array_intersect($this->_syncFieldsMap, array_keys($this->_data));
142
+ if (!empty($existedShortKeys)) {
143
+ foreach ($existedShortKeys as $key) {
144
+ $fullFieldName = array_search($key, $this->_syncFieldsMap);
145
+ $this->_data[$fullFieldName] = $this->_data[$key];
146
+ }
147
+ }
148
+ }
149
+
150
+ protected function _underscore($name){
151
+ if (isset(self::$_underscoreCache[$name])) {
152
+ return self::$_underscoreCache[$name];
153
+ }
154
+ #Varien_Profiler::start('underscore');
155
+ $result = strtolower(preg_replace('/(.)([A-Z])/', "$1_$2", $name));
156
+ #Varien_Profiler::stop('underscore');
157
+ self::$_underscoreCache[$name] = $result;
158
+ return $result;
159
+ }
160
+
161
+ }
app/code/local/Harapartners/ConnectorHub/Model/Rewrite/Paypal/Api/Nvp.php ADDED
@@ -0,0 +1,39 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ *
13
+ */
14
+ class Harapartners_ConnectorHub_Model_Rewrite_Paypal_Api_Nvp extends Mage_Paypal_Model_Api_Nvp {
15
+
16
+ public function getButtonSourceEc(){
17
+ return $this->getBuildNotationCode();
18
+ }
19
+
20
+ public function getButtonSourceDp(){
21
+ return $this->getBuildNotationCode();
22
+ }
23
+
24
+ //Important build code update, for Mage_Paypal 1.4 -
25
+ public function getBuildNotationCode($countryCode = null){
26
+ if($this->_isModuleActive('Enterprise_Enterprise')){
27
+ return 'Hara_SI_MagentoEE_PPA';
28
+ }else{
29
+ return 'Hara_SI_MagentoCE_PPA';
30
+ }
31
+ }
32
+
33
+ private function _isModuleActive($code) {
34
+ $module = Mage::getConfig()->getNode("modules/$code");
35
+ $model = Mage::getConfig()->getNode("global/models/$code");
36
+ return $module && $module->is('active') || $model;
37
+ }
38
+
39
+ }
app/code/local/Harapartners/ConnectorHub/Model/Rewrite/Paypal/Config.php ADDED
@@ -0,0 +1,58 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ *
13
+ */
14
+ class Harapartners_ConnectorHub_Model_Rewrite_Paypal_Config extends Mage_Paypal_Model_Config {
15
+
16
+ protected $_isStagingMode = null;
17
+
18
+ /* Compatibility for Staging server SSL verification */
19
+ public function __get($key){
20
+ if(strcmp($key, 'verifyPeer') == 0 || strcmp($key, 'verify_peer') == 0){
21
+ if($this->_isStagingMode === null){
22
+ $this->_isStagingMode = 0;
23
+ try{
24
+ $curlResource = curl_init("https://www.paypal.com/");
25
+ curl_setopt($curlResource, CURLOPT_TIMEOUT, 3);
26
+ curl_setopt($curlResource, CURLOPT_RETURNTRANSFER, false);
27
+ curl_setopt($curlResource, CURLOPT_SSL_VERIFYPEER, true);
28
+ curl_exec($curlResource);
29
+ $curlError = curl_error($curlResource);
30
+ curl_close($curlResource);
31
+ if(!!$curlError){
32
+ $this->_isStagingMode = 1;
33
+ }
34
+ }catch (Exception $ex){
35
+ $this->_isStagingMode = 1;
36
+ }
37
+ }
38
+ if($this->_isStagingMode == 1){
39
+ return 0;
40
+ }
41
+ }
42
+ return parent::__get($key);
43
+ }
44
+
45
+ public function getBuildNotationCode($countryCode = null){
46
+ if($this->_isModuleActive('Enterprise_Enterprise')){
47
+ return 'Hara_SI_MagentoEE_PPA';
48
+ }else{
49
+ return 'Hara_SI_MagentoCE_PPA';
50
+ }
51
+ }
52
+ private function _isModuleActive($code) {
53
+ $module = Mage::getConfig()->getNode("modules/$code");
54
+ $model = Mage::getConfig()->getNode("global/models/$code");
55
+ return $module && $module->is('active') || $model;
56
+ }
57
+
58
+ }
app/code/local/Harapartners/ConnectorHub/etc/config.xml ADDED
@@ -0,0 +1,54 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+ -->
15
+ <config>
16
+ <modules>
17
+ <Harapartners_ConnectorHub>
18
+ <version>1.0.0</version>
19
+ </Harapartners_ConnectorHub>
20
+ </modules>
21
+ <global>
22
+ <models>
23
+ <connectorhub>
24
+ <class>Harapartners_ConnectorHub_Model</class>
25
+ </connectorhub>
26
+ <paypal>
27
+ <rewrite>
28
+ <!-- /* Compatibility for Staging server SSL verification */ -->
29
+ <config>Harapartners_ConnectorHub_Model_Rewrite_Paypal_Config</config>
30
+ <api_nvp>Harapartners_ConnectorHub_Model_Rewrite_Paypal_Api_Nvp</api_nvp>
31
+ </rewrite>
32
+ </paypal>
33
+ </models>
34
+ <helpers>
35
+ <connectorhub>
36
+ <class>Harapartners_ConnectorHub_Helper</class>
37
+ </connectorhub>
38
+ </helpers>
39
+ </global>
40
+ <default>
41
+ <connectorhub>
42
+ <connectorhub>
43
+ <url>https://www.connectorhub.com/</url>
44
+ </connectorhub>
45
+ </connectorhub>
46
+ <paypal>
47
+ <!-- /* Compatibility for Staging server SSL verification */ -->
48
+ <wpp>
49
+ <button_source_ec>Hara_SI_MagentoCE_PPA</button_source_ec>
50
+ <button_source_dp>Hara_SI_MagentoCE_PPA</button_source_dp>
51
+ </wpp>
52
+ </paypal>
53
+ </default>
54
+ </config>
app/code/local/Harapartners/SpeedTax/Block/Adminhtml/System/Config/Form/Field/Authentication.php ADDED
@@ -0,0 +1,77 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+
14
+ class Harapartners_SpeedTax_Block_Adminhtml_System_Config_Form_Field_Authentication extends Mage_Adminhtml_Block_System_Config_Form_Field {
15
+
16
+ protected function _toHtml() {
17
+ $htmlId = $this->getHtmlId();
18
+ $ajaxUrl = $this->getAjaxUrl();
19
+ $buttonLabel = $this->escapeHtml($this->getButtonLabel());
20
+
21
+ $htmlContent = <<< HTML_CONTENT
22
+ <script type="text/javascript">
23
+ function ajaxLogin() {
24
+ var elem = $('$htmlId');
25
+
26
+ params = {
27
+ username: $('speedtax_speedtax_username').value,
28
+ password: $('speedtax_speedtax_password').value,
29
+ company_code: $('speedtax_speedtax_company_code').value,
30
+ is_test_mode: $('speedtax_speedtax_is_test_mode').value
31
+ };
32
+
33
+ new Ajax.Request('$ajaxUrl', {
34
+ parameters: params,
35
+ onSuccess: function(response) {
36
+ result = 'Login failed!';
37
+ try {
38
+ response = JSON.parse(response.responseText);
39
+ result = response.message;
40
+ if (response.status == 1) {
41
+ elem.removeClassName('fail').addClassName('success');
42
+ } else {
43
+ elem.removeClassName('success').addClassName('fail');
44
+ }
45
+ } catch (e) {
46
+ elem.removeClassName('success').addClassName('fail');
47
+ }
48
+ $('ajax_login_result').update(result);
49
+ }
50
+ });
51
+ }
52
+ </script>
53
+ <button onclick="javascript:ajaxLogin(); return false;" class="scalable" type="button" id="$htmlId">
54
+ <span><span><span id="ajax_login_result">$buttonLabel</span></span></span>
55
+ </button>
56
+ HTML_CONTENT;
57
+
58
+ return $htmlContent;
59
+ }
60
+
61
+ public function render(Varien_Data_Form_Element_Abstract $element){
62
+ $element->unsScope()->unsCanUseWebsiteValue()->unsCanUseDefaultValue();
63
+ return parent::render($element);
64
+ }
65
+
66
+ protected function _getElementHtml(Varien_Data_Form_Element_Abstract $element){
67
+ $originalData = $element->getOriginalData();
68
+ $this->addData(array(
69
+ 'button_label' => Mage::helper('speedtax')->__($originalData['button_label']),
70
+ 'html_id' => $element->getHtmlId(),
71
+ 'ajax_url' => Mage::getSingleton('adminhtml/url')->getUrl('speedtax_adminhtml/system_config_ajax/authentication')
72
+ ));
73
+
74
+ return $this->_toHtml();
75
+ }
76
+
77
+ }
app/code/local/Harapartners/SpeedTax/Helper/Connector/Data.php ADDED
@@ -0,0 +1,240 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_SpeedTax_Helper_Connector_Data extends Mage_Core_Helper_Abstract {
14
+
15
+ const TAX_SHIPPING_LINEITEM_TAX_CLASS = 'TAX_SHIPPING';
16
+ const TAX_SHIPPING_LINEITEM_REFERNCE_NAME = 'TAX_SHIPPING';
17
+
18
+ protected $_productTaxClassNoneTaxableId = 0; //Magento default
19
+ // protected $_allowedCountryIds = array('US', 'CA');
20
+
21
+ protected $_shipFromAddress = null;
22
+ protected $_shipToAddress = null;
23
+
24
+ // ========================== Main entry points ========================== //
25
+ public function prepareSpeedTaxInvoiceByMageQuoteAddress(Mage_Sales_Model_Quote_Address $mageQuoteAddress) {
26
+ $sptxInvoice = new stdClass();
27
+ $sptxInvoice->lineItems = array();
28
+ $sptxInvoice->customerIdentifier = Mage::getStoreConfig ( 'speedtax/speedtax/username' );
29
+
30
+ foreach ( $mageQuoteAddress->getAllItems () as $mageQuoteItem ) {
31
+ if(!!$mageQuoteItem->getParentItemId()){
32
+ continue;
33
+ }
34
+ //Multiple shipping checkout, $mageQuoteItem is instance of Mage_Sales_Model_Quote_Address_Item, not a sub-class of Mage_Sales_Model_Quote_Item
35
+ //Many product related fields must be obtained from the product object directly
36
+ if($mageQuoteItem->getProduct()->getTaxClassId() == $this->_productTaxClassNoneTaxableId){
37
+ continue;
38
+ }
39
+ if($mageQuoteItem->getRowTotal() - $mageQuoteItem->getDiscountAmount() <= 0){
40
+ continue;
41
+ }
42
+
43
+ $lineItem = new stdClass();
44
+ $lineItem->productCode = $this->_getProductCode($mageQuoteItem);
45
+ $lineItem->customReference = $mageQuoteItem->getId();
46
+ $lineItem->quantity = $mageQuoteItem->getQty();
47
+ $lineItem->shipFromAddress = $this->_getShipFromAddress();
48
+ $lineItem->shipToAddress = $this->_getShippingToAddress($mageQuoteAddress); //Note, address type is validated at the entry point 'queryQuoteAddress'
49
+
50
+ //Price of row total, not unit price
51
+ $lineItemPrice = new stdClass();
52
+ $lineItemPrice->decimalValue = $mageQuoteItem->getRowTotal() - $mageQuoteItem->getDiscountAmount();
53
+ $lineItem->salesAmount = $lineItemPrice;
54
+
55
+ $lineItem->lineItemNumber = count( $sptxInvoice->lineItems );
56
+ $sptxInvoice->lineItems[] = $lineItem;
57
+ }
58
+
59
+ // ----- Other line items ----- //
60
+ //If global store config specifies: "tax_shipping", then create shipping cost line item. Note this is different from "Tax_Shipping" tax class of a product
61
+ $shipingAmount = $mageQuoteAddress->getShippingAmount();
62
+ if(!!Mage::getStoreConfig("speedtax/speedtax/tax_shipping") && $shipingAmount > 0.0){
63
+ $shippingLineItem = $this->_generateLineItemFromShippingCost($mageQuoteAddress, $shipingAmount);
64
+ $shippingLineItem->lineItemNumber = count( $sptxInvoice->lineItems );
65
+ $sptxInvoice->lineItems[] = $shippingLineItem;
66
+ }
67
+
68
+ $sptxInvoice->invoiceDate = date('Y-m-d H:i:s');
69
+ return $sptxInvoice;
70
+ }
71
+
72
+ public function prepareSpeedTaxInvoiceByMageOrderInvoice(Mage_Sales_Model_Order_Invoice $mageOrderInvoice) {
73
+ //Clear the invoice number so that the request is just a query
74
+ $mageOrderAddress = $mageOrderInvoice->getShippingAddress();
75
+ $sptxInvoice = new stdClass();
76
+
77
+ //Important to keep unique, invoice should already be attached to the order, count starts from 1
78
+ $sptxInvoice->invoiceNumber =
79
+ $mageOrderInvoice->getOrder()->getIncrementId()
80
+ . '-INV-' . ($mageOrderInvoice->getOrder()->getInvoiceCollection()->count());
81
+ $sptxInvoice->customerIdentifier = Mage::getStoreConfig ( 'speedtax/speedtax/username' );
82
+
83
+ foreach ( $mageOrderInvoice->getAllItems() as $mageItem ) {
84
+ if(!$mageItem->getTaxAmount() || $mageItem->getTaxAmount() <= 0.0){
85
+ continue;
86
+ }
87
+ $lineItem = new stdClass();
88
+ $lineItem->productCode = $this->_getProductCode($mageItem);
89
+ $lineItem->customReference = $mageItem->getOrderItemId(); //This is during invoice creation, no ID available
90
+ $lineItem->quantity = $mageItem->getQty();
91
+ $lineItem->shipFromAddress = $this->_getShipFromAddress();
92
+ $lineItem->shipToAddress = $this->_getShippingToAddress($mageOrderAddress); //Note, address type is validated at the entry point 'queryQuoteAddress'
93
+
94
+ //Price of row total, not unit price
95
+ $lineItemPrice = new stdClass();
96
+ $lineItemPrice->decimalValue = $mageItem->getRowTotal() - $mageItem->getDiscountAmount();
97
+ $lineItem->salesAmount = $lineItemPrice;
98
+
99
+ $lineItem->lineItemNumber = count( $sptxInvoice->lineItems );
100
+ $sptxInvoice->lineItems[] = $lineItem;
101
+ }
102
+
103
+ // ----- Other line items ----- //
104
+ //If global store config specifies: "tax_shipping", then create shipping cost line item. Note this is different from "Tax_Shipping" tax class of a product
105
+ if($mageOrderInvoice->getShippingAmount() === null){
106
+ $mageOrderInvoice->collectTotals();
107
+ }
108
+ $shipingAmount = $mageOrderInvoice->getShippingAmount();
109
+ if(!!Mage::getStoreConfig("speedtax/speedtax/tax_shipping") && $shipingAmount > 0.0){
110
+ $shippingLineItem = $this->_generateLineItemFromShippingCost($mageOrderAddress, $shipingAmount);
111
+ $shippingLineItem->lineItemNumber = count( $sptxInvoice->lineItems );
112
+ $sptxInvoice->lineItems[] = $shippingLineItem;
113
+ }
114
+
115
+ $sptxInvoice->invoiceDate = date('Y-m-d H:i:s');
116
+ return $sptxInvoice;
117
+ }
118
+
119
+ public function prepareSpeedTaxInvoiceByMageOrderCreditmemo(Mage_Sales_Model_Order_Creditmemo $mageOrderCreditmemo) {
120
+ //Clear the invoice number so that the request is just a query
121
+ $mageOrderAddress = $mageOrderCreditmemo->getShippingAddress();
122
+ $sptxInvoice = new stdClass();
123
+ //Important to keep unique, credit memo not yet attached to the order, count ++ so that it starts from 1
124
+ $sptxInvoice->invoiceNumber =
125
+ $mageOrderCreditmemo->getOrder()->getIncrementId()
126
+ . '-CR-' . ($mageOrderCreditmemo->getOrder()->getCreditmemosCollection()->count() + 1);
127
+ $sptxInvoice->customerIdentifier = Mage::getStoreConfig ( 'speedtax/speedtax/username' );
128
+
129
+ foreach ( $mageOrderCreditmemo->getAllItems() as $mageItem ) {
130
+ if(!$mageItem->getTaxAmount() || $mageItem->getTaxAmount() <= 0.0){
131
+ continue;
132
+ }
133
+ $lineItem = new stdClass();
134
+ $lineItem->productCode = $this->_getProductCode($mageItem);
135
+ $lineItem->customReference = $mageItem->getOrderItemId(); //This is during credit memo creation, no ID available
136
+ $lineItem->quantity = $mageItem->getQty();
137
+ $lineItem->shipFromAddress = $this->_getShipFromAddress();
138
+ $lineItem->shipToAddress = $this->_getShippingToAddress($mageOrderAddress); //Note, address type is validated at the entry point 'queryQuoteAddress'
139
+
140
+ //Price of row total, not unit price
141
+ $lineItemPrice = new stdClass();
142
+ $lineItemPrice->decimalValue = $mageItem->getRowTotal() - $mageItem->getDiscountAmount();
143
+ $lineItem->salesAmount = $lineItemPrice;
144
+
145
+ $lineItem->lineItemNumber = count( $sptxInvoice->lineItems );
146
+ $sptxInvoice->lineItems[] = $lineItem;
147
+ }
148
+
149
+ // ----- Other line items ----- //
150
+ //If global store config specifies: "tax_shipping", then create shipping cost line item. Note this is different from "Tax_Shipping" tax class of a product
151
+ if($mageOrderCreditmemo->getShippingAmount() === null){
152
+ $mageOrderCreditmemo->collectTotals();
153
+ }
154
+ $shipingAmount = $mageOrderCreditmemo->getShippingAmount();
155
+ if(!!Mage::getStoreConfig("speedtax/speedtax/tax_shipping") && $shipingAmount > 0.0){
156
+ $shippingLineItem = $this->_generateLineItemFromShippingCost($mageOrderAddress, $shipingAmount);
157
+ $shippingLineItem->lineItemNumber = count( $sptxInvoice->lineItems );
158
+ $sptxInvoice->lineItems[] = $shippingLineItem;
159
+ }
160
+
161
+ $sptxInvoice->invoiceDate = date('Y-m-d H:i:s');
162
+ return $sptxInvoice;
163
+ }
164
+
165
+ // ========================== Utilities ========================== //
166
+ protected function _generateLineItemFromShippingCost($mageAddress, $shipingAmount) {
167
+ $shippingLineItem = new stdClass();
168
+ $shippingLineItem->productCode = self::TAX_SHIPPING_LINEITEM_TAX_CLASS;
169
+ $shippingLineItem->customReference = self::TAX_SHIPPING_LINEITEM_REFERNCE_NAME;
170
+ $shippingLineItem->quantity = 1;
171
+ $shippingLineItem->shipFromAddress = $this->_getShipFromAddress ();
172
+ $shippingLineItem->shipToAddress = $this->_getShippingToAddress ($mageAddress); //Note, address type is validated at the entry point 'queryQuoteAddress'
173
+
174
+ $shippingPrice = new stdClass();
175
+ $shippingPrice->decimalValue = $shipingAmount;
176
+ $shippingLineItem->salesAmount = $shippingPrice;
177
+
178
+ return $shippingLineItem;
179
+ }
180
+
181
+ //Shipping Origin Address
182
+ protected function _getShipFromAddress() {
183
+ if($this->_shipFromAddress === null){
184
+ $this->_shipFromAddress = new stdClass();
185
+ $countryId = Mage::getStoreConfig ( 'shipping/origin/country_id');
186
+ $zip = Mage::getStoreConfig ('shipping/origin/postcode');
187
+ $regionId = Mage::getStoreConfig ( 'shipping/origin/region_id');
188
+ $state = Mage::getModel('directory/region')->load($regionId)->getName();
189
+ $city = Mage::getStoreConfig ('shipping/origin/city');
190
+ $street = Mage::getStoreConfig ('shipping/origin/street');
191
+
192
+ $this->_shipFromAddress->address1 = $street;
193
+ $this->_shipFromAddress->address2 = $city . ", " . $state . " " . $zip; //. ", " . $countryId;
194
+ }
195
+ return $this->_shipFromAddress;
196
+ }
197
+
198
+ //Shipping Destination Address
199
+ protected function _getShippingToAddress($address) {
200
+ if($this->_shipToAddress === null){
201
+ $this->_shipToAddress = new stdClass();
202
+ $country = $address->getCountry();
203
+ $zip = $address->getPostcode(); //$zip = preg_replace('/[^0-9\-]*/', '', $address->getPostcode()); //US zip code clean up
204
+ $state = $address->getRegion(); //No region resolution needed, $this->_getStateCodeByRegionId($address->getState());
205
+ $city = $address->getCity();
206
+ $street = implode(' ', $address->getStreet()); //In case of multiple line address
207
+
208
+ $this->_shipToAddress->address1 = $street;
209
+ $this->_shipToAddress->address2 = $city . ", " . $state . " " . $zip; //. ", " . $country;
210
+ }
211
+ return $this->_shipToAddress;
212
+ }
213
+
214
+
215
+ //In a standard setup, tax is calculated by tax class (i.e. product code), if empty use default
216
+ //Advanced calculation by product SKU is also possible. Please contact SpeedTax support to setup advanced service
217
+ protected function _getProductCode($item){
218
+ $useTaxCode = Mage::helper('speedtax')->useTaxClass();
219
+ if(!$useTaxCode){
220
+ return $item->getSku();
221
+ }
222
+ if($taxCode = $this->_getTaxClassByItem($item)){
223
+ return $taxCode;
224
+ }else{
225
+ return $item->getSku();
226
+ }
227
+ }
228
+
229
+ protected function _getTaxClassByItem($item){
230
+ $storeId = Mage::app()->getStore()->getId();
231
+ $taxClassId = Mage::getResourceModel('catalog/product')->getAttributeRawValue($item->getProductId(), 'tax_class_id', $storeId);
232
+ if($taxClassId){
233
+ $taxClassCode = Mage::getModel('tax/class_source_product')->getOptionText($taxClassId);
234
+ }else{
235
+ $taxClassCode = null;
236
+ }
237
+ return $taxClassCode;
238
+ }
239
+
240
+ }
app/code/local/Harapartners/SpeedTax/Helper/Connector/Speedtax.php ADDED
@@ -0,0 +1,182 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_SpeedTax_Helper_Connector_Speedtax extends Harapartners_ConnectorHub_Helper_Connector_Core {
14
+
15
+ const REQUEST_ACTION_CALCULATE_INVOICE = 'CalculateInvoice';
16
+ const REQUEST_ACTION_POST_INVOICE = 'PostInvoice';
17
+ const REQUEST_ACTION_POST_CREDITMEMO = 'PostCreditmemo';
18
+ const REQUEST_ACTION_VOID_INVOICE = 'VoidInvoice';
19
+ const REQUEST_ACTION_BATCH_VOID_INVOICES = 'BatchVoidInvoices';
20
+
21
+ const RESPONSE_TYPE_SUCCESS = 'SUCCESS';
22
+ const RESPONSE_TYPE_FAILED_WITH_ERRORS = 'FAILED_WITH_ERRORS';
23
+ const RESPONSE_TYPE_FAILED_INVOICE_NUMBER = 'FAILED_INVOICE_NUMBER';
24
+
25
+ protected $_serviceType = 'speedtax';
26
+
27
+ // ======================= Essential overrides ======================= //
28
+ public function getServiceMode(){
29
+ $serviceMode = Harapartners_ConnectorHub_Helper_Connector_Core::REQUEST_SERVICE_MODE_PRODUCTION;
30
+ if(!!Mage::getStoreConfig($this->_getConfigDataBasePath('is_test_mode'))){
31
+ $serviceMode = Harapartners_ConnectorHub_Helper_Connector_Core::REQUEST_SERVICE_MODE_TEST;
32
+ }
33
+ return $serviceMode;
34
+ }
35
+
36
+ protected function _getConnectorHubUrl(){
37
+ return $this->_getConnectorHubRootUrl() . 'SpeedTax.php';
38
+ }
39
+
40
+ protected function _getConfigDataBasePath($key){
41
+ return 'speedtax/speedtax/' . $key;
42
+ }
43
+
44
+ protected function _prepareCredentials(){
45
+ $username = Mage::getStoreConfig($this->_getConfigDataBasePath('username'));
46
+ $password = Mage::getStoreConfig($this->_getConfigDataBasePath('password'));
47
+ $password = Mage::helper('core')->decrypt($password);
48
+
49
+ $companyCode = Mage::getStoreConfig($this->_getConfigDataBasePath('company_code'));
50
+ $isTestMode = Mage::getStoreConfig($this->_getConfigDataBasePath('is_test_mode'));
51
+
52
+ $credentials = array(
53
+ 'username' => $username,
54
+ 'password' => $password,
55
+ 'company_code' => $companyCode,
56
+ 'is_test_mode' => $isTestMode
57
+ );
58
+ return $credentials;
59
+ }
60
+
61
+ // ====================== Requests ====================== //
62
+ public function calculateInvoiceRequest($sptxInvoice){
63
+ $response = $this->_doInvoiceRequest($sptxInvoice, self::REQUEST_ACTION_CALCULATE_INVOICE);
64
+ return $response->data->result;
65
+ }
66
+
67
+ public function postInvoiceRequest($sptxInvoice){
68
+ $response = $this->_doInvoiceRequest($sptxInvoice, self::REQUEST_ACTION_POST_INVOICE);
69
+ return $response->data->result;
70
+ }
71
+
72
+ public function postCreditmemoRequest($sptxInvoice){
73
+ $response = $this->_doInvoiceRequest($sptxInvoice, self::REQUEST_ACTION_POST_CREDITMEMO);
74
+ return $response->data->result;
75
+ }
76
+
77
+ public function cancelAllOrderTransactions($invoiceNumbers){
78
+ $credentials = $this->_prepareCredentials();
79
+ $request = array(
80
+ 'meta' => array(
81
+ 'action' => $actionType
82
+ ),
83
+ 'data' => array(
84
+ 'credentials' => $credentials,
85
+ 'invoice' => $sptxInvoice
86
+ )
87
+ );
88
+
89
+ $response = $this->_processRequest($request);
90
+
91
+ //Essential validation!
92
+ if(!$response->data || !$response->data->result){
93
+ Mage::throwException('Invalid tax response');
94
+ }
95
+ $responseResult = $response->data->result;
96
+ switch ($responseResult->resultType) {
97
+ case self::RESPONSE_TYPE_SUCCESS:
98
+ break;
99
+ case self::RESPONSE_TYPE_FAILED_WITH_ERRORS:
100
+ case self::RESPONSE_TYPE_FAILED_INVOICE_NUMBER:
101
+ default :
102
+ Mage::throwException('Tax request failed');
103
+ break;
104
+ }
105
+
106
+ return $response;
107
+ }
108
+
109
+ protected function _doInvoiceRequest($sptxInvoice, $actionType){
110
+ $credentials = $this->_prepareCredentials();
111
+ $request = array(
112
+ 'meta' => array(
113
+ 'action' => $actionType
114
+ ),
115
+ 'data' => array(
116
+ 'credentials' => $credentials,
117
+ 'invoice' => $sptxInvoice
118
+ )
119
+ );
120
+
121
+ $response = $this->_loadCachedInvoiceResponse($sptxInvoice, $actionType);
122
+ if(!$response){
123
+ $response = $this->_processRequest($request);
124
+ $this->_saveCachedInvoiceResponse($response, $sptxInvoice, $actionType);
125
+ }
126
+
127
+ //Essential validation!
128
+ if(!$response->data || !$response->data->result){
129
+ Mage::throwException('Invalid tax response');
130
+ }
131
+ $responseResult = $response->data->result;
132
+ switch ($responseResult->resultType) {
133
+ case self::RESPONSE_TYPE_SUCCESS:
134
+ break;
135
+ case self::RESPONSE_TYPE_FAILED_WITH_ERRORS:
136
+ case self::RESPONSE_TYPE_FAILED_INVOICE_NUMBER:
137
+ default :
138
+ Mage::throwException('Tax request failed');
139
+ break;
140
+ }
141
+
142
+ return $response;
143
+ }
144
+
145
+ protected function _loadCachedInvoiceResponse($sptxInvoice, $actionType){
146
+ if(!$this->_isCacheRequestAllowed($actionType)){
147
+ return false;
148
+ }
149
+ $sptxInvoiceCacheKey = $this->_generateInvoiceCacheKey($sptxInvoice);
150
+ $response = Mage::getSingleton('speedtax/session')->loadCachedResponse($sptxInvoiceCacheKey);
151
+ return $response;
152
+ }
153
+
154
+ protected function _saveCachedInvoiceResponse($response, $sptxInvoice, $actionType){
155
+ if(!$this->_isCacheRequestAllowed($actionType)){
156
+ return false;
157
+ }
158
+ $sptxInvoiceCacheKey = $this->_generateInvoiceCacheKey($sptxInvoice);
159
+ $response = Mage::getSingleton('speedtax/session')->saveCachedResponse($sptxInvoiceCacheKey, $response);
160
+ return true;
161
+ }
162
+
163
+ protected function _isCacheRequestAllowed($actionType){
164
+ $allRequestCache = false;
165
+ switch($actionType){
166
+ case self::REQUEST_ACTION_CALCULATE_INVOICE:
167
+ $allRequestCache = true;
168
+ break;
169
+ default:
170
+ $allRequestCache = false;
171
+ break;
172
+ }
173
+ return $allRequestCache;
174
+ }
175
+
176
+ protected function _generateInvoiceCacheKey($sptxInvoice){
177
+ $sptxInvoice = clone $sptxInvoice;
178
+ $sptxInvoice->invoiceDate = null;
179
+ return md5(json_encode($sptxInvoice));
180
+ }
181
+
182
+ }
app/code/local/Harapartners/SpeedTax/Helper/Data.php ADDED
@@ -0,0 +1,30 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_SpeedTax_Helper_Data extends Mage_Core_Helper_Abstract {
14
+
15
+ protected $_xmlPathPrefix = 'speedtax/speedtax/';
16
+
17
+ // =========================== config and essential flags =========================== //
18
+ public function isSpeedTaxEnabled(){
19
+ return Mage::getStoreConfig ( $this->_xmlPathPrefix . 'is_enabled' );
20
+ }
21
+
22
+ public function useTaxClass(){
23
+ return Mage::getStoreConfig ( $this->_xmlPathPrefix . 'customized_tax_class' );
24
+ }
25
+
26
+ public function isAddressValidationOn($address, $storeId) {
27
+ return Mage::getStoreConfig( $this->_xmlPathPrefix . 'validate_address', $storeId);
28
+ }
29
+
30
+ }
app/code/local/Harapartners/SpeedTax/Helper/Processor.php ADDED
@@ -0,0 +1,190 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license [^]
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+
15
+ class Harapartners_SpeedTax_Helper_Processor extends Mage_Core_Helper_Abstract {
16
+
17
+ const SPEEDTAX_INVOICE_STATUS_PENDING = 0;
18
+ const SPEEDTAX_INVOICE_STATUS_POSTED = 100;
19
+ const SPEEDTAX_INVOICE_STATUS_VOID = 200;
20
+ const SPEEDTAX_INVOICE_STATUS_ERROR = 300;
21
+
22
+ // ========================== Actions ========================== //
23
+ public function queryQuoteAddress(Mage_Sales_Model_Quote_Address $mageQuoteAddress){
24
+ if (!$this->_isTaxable($mageQuoteAddress)){
25
+ return false;
26
+ }
27
+ $sptxInvoice = Mage::helper('speedtax/connector_data')->prepareSpeedTaxInvoiceByMageQuoteAddress($mageQuoteAddress);
28
+ if(!$sptxInvoice|| !$sptxInvoice->lineItems){
29
+ return false;
30
+ }
31
+ $responseResult = Mage::helper('speedtax/connector_speedtax')->calculateInvoiceRequest($sptxInvoice);
32
+ $this->_applyResponseToQuote($responseResult, $mageQuoteAddress);
33
+ return $responseResult;
34
+ }
35
+
36
+ public function postOrderInvoice(Mage_Sales_Model_Order_Invoice $mageOrderInvoice){
37
+ if(!!$mageOrderInvoice->getData('speedtax_transaction_id')){
38
+ Mage::throwException('This invoice was already posted through SalesTax.');
39
+ }
40
+
41
+ $sptxInvoice = Mage::helper('speedtax/connector_data')->prepareSpeedTaxInvoiceByMageOrderInvoice($mageOrderInvoice);
42
+ if(!$sptxInvoice || !$sptxInvoice->lineItems){
43
+ return false;
44
+ }
45
+ //No caching allowed for order invoice
46
+ $responseResult = Mage::helper('speedtax/connector_speedtax')->postInvoiceRequest($sptxInvoice);
47
+ $this->_applyResponseToInvoice($responseResult, $mageOrderInvoice);
48
+
49
+ return $responseResult;
50
+ }
51
+
52
+ public function postOrderCreditmemo(Mage_Sales_Model_Order_Creditmemo $mageOrderCreditmemo) {
53
+ if(!!$mageOrderCreditmemo->getData('speedtax_transaction_id')){
54
+ Mage::throwException('This credit memo was already posted through SalesTax.');
55
+ }
56
+
57
+ $sptxInvoice = Mage::helper('speedtax/connector_data')->prepareSpeedTaxInvoiceByMageOrderCreditmemo($mageOrderCreditmemo);
58
+ if(!$sptxInvoice || !$sptxInvoice->lineItems){
59
+ return false;
60
+ }
61
+ //No caching allowed for order invoice
62
+ $responseResult = Mage::helper('speedtax/connector_speedtax')->postCreditmemoRequest($sptxInvoice);
63
+ $this->_applyResponseToCreditmemo($responseResult, $mageOrderCreditmemo);
64
+
65
+ return $responseResult;
66
+ }
67
+
68
+ public function cancelAllOrderTransactions(Mage_Sales_Model_Order $mageOrder) {
69
+ $invoiceNumbers = array();
70
+ $updateObjectArray = array();
71
+ foreach($mageOrder->getInvoiceCollection() as $mageOrderInvoice){
72
+ if(!!$mageOrderInvoice->getData('speedtax_invoice_number')
73
+ && $mageOrderInvoice->getData('speedtax_invoice_status') == self::SPEEDTAX_INVOICE_STATUS_POSTED ){
74
+ $invoiceNumbers[] = $mageOrderInvoice->getData('speedtax_invoice_number');
75
+ $updateObjectArray[$mageOrderInvoice->getData('speedtax_invoice_number')] = $mageOrderInvoice;
76
+ }
77
+ }
78
+ foreach($mageOrder->getCreditmemosCollection() as $mageOrderCreditmemo){
79
+ if(!!$mageOrderCreditmemo->getData('speedtax_invoice_number')
80
+ && $mageOrderCreditmemo->getData('speedtax_invoice_status') == self::SPEEDTAX_INVOICE_STATUS_POSTED ){
81
+ $invoiceNumbers[] = $mageOrderCreditmemo->getData('speedtax_invoice_number');
82
+ $updateObjectArray[$mageOrderCreditmemo->getData('speedtax_invoice_number')] = $mageOrderCreditmemo;
83
+ }
84
+ }
85
+
86
+ if(!$invoiceNumbers){
87
+ return false;
88
+ }
89
+ //No caching allowed for order invoice
90
+ $responseResult = Mage::helper('speedtax/connector_speedtax')->cancelAllOrderTransactions($invoiceNumbers);
91
+
92
+ //Update status
93
+ $batchVoidResults = json_decode($responseResult->data->result->batchVoidResults, 1);
94
+ foreach($batchVoidResults as $invoiceNumber => $voidResult){
95
+ $updateObject = $updateObjectArray[$invoiceNumber];
96
+ if($voidResult == Harapartners_SpeedTax_Helper_Connector_Speedtax::RESPONSE_TYPE_SUCCESS){
97
+ $updateObject->setData('speedtax_invoice_status', self::SPEEDTAX_INVOICE_STATUS_VOID);
98
+ }else{
99
+ $updateObject->setData('speedtax_invoice_status', self::SPEEDTAX_INVOICE_STATUS_ERROR);
100
+ }
101
+ $updateObject->save();
102
+ }
103
+
104
+ return $responseResult;
105
+ }
106
+
107
+
108
+ // ========================== Utility Functions ========================== //
109
+ //Mage_Sales_Model_Quote_Address or Mage_Sales_Model_Order_Address
110
+ protected function _isTaxable($mageAddress) {
111
+ //$mageAddress can be quote of order address, or null for virtual product
112
+ if(!($mageAddress instanceof Varien_Object)
113
+ || $mageAddress->getAddressType() != Mage_Sales_Model_Quote_Address::TYPE_SHIPPING
114
+ ){
115
+ return false;
116
+ }
117
+ //Nexus test
118
+ $originsString = Mage::getStoreConfig('speedtax/speedtax/origins');
119
+ return in_array($mageAddress->getRegionId(), explode(',', $originsString));
120
+ }
121
+
122
+ //Mage_Sales_Model_Quote_Address ONLY
123
+ protected function _applyResponseToQuote($responseResult, Mage_Sales_Model_Quote_Address $mageQuoteAddress){
124
+ foreach ( $mageQuoteAddress->getAllItems() as $mageQuoteItem ) {
125
+ $taxAmount = $this->_getLineItemTaxAmountByItemId($responseResult, $mageQuoteItem->getId());
126
+ $mageQuoteItem->setTaxAmount($taxAmount);
127
+ $mageQuoteItem->setBaseTaxAmount($taxAmount);
128
+ if(($mageQuoteItem->getRowTotal() - $mageQuoteItem->getDiscountAmount()) > 0){
129
+ $mageQuoteItem->setTaxPercent (sprintf("%.4f", 100*$taxAmount/($mageQuoteItem->getRowTotal() - $mageQuoteItem->getDiscountAmount())));
130
+ }
131
+ }
132
+ if(!!$this->_getTaxShippingAmount($responseResult)){
133
+ $taxShippingAmount = $this->_getTaxShippingAmount($responseResult);
134
+ $mageQuoteAddress->setShippingTaxAmount($taxShippingAmount);
135
+ $mageQuoteAddress->setBaseShippingTaxAmount($taxShippingAmount);
136
+ }
137
+ return;
138
+ }
139
+
140
+ protected function _applyResponseToInvoice($responseResult, Mage_Sales_Model_Order_Invoice $mageOrderInvoice){
141
+ $mageOrderInvoice->setData('speedtax_transaction_id', $responseResult->transactionId);
142
+ $mageOrderInvoice->setData('speedtax_invoice_number', $responseResult->invoiceNumber);
143
+ $mageOrderInvoice->setData('speedtax_invoice_status', self::SPEEDTAX_INVOICE_STATUS_POSTED);
144
+ $mageOrderInvoice->save();
145
+ return;
146
+ }
147
+
148
+ protected function _applyResponseToCreditmemo($responseResult, Mage_Sales_Model_Order_Creditmemo $mageOrderCreditmemo){
149
+ $mageOrderCreditmemo->setData('speedtax_transaction_id', $responseResult->transactionId);
150
+ $mageOrderCreditmemo->setData('speedtax_invoice_number', $responseResult->invoiceNumber);
151
+ $mageOrderCreditmemo->setData('speedtax_invoice_status', self::SPEEDTAX_INVOICE_STATUS_POSTED);
152
+ $mageOrderCreditmemo->save();
153
+ return;
154
+ }
155
+
156
+ public function getTotalTax($responseResult) {
157
+ return $responseResult->totalTax->decimalValue;
158
+ }
159
+
160
+ protected function _getLineItemTaxAmountByItemId($responseResult, $itemId) {
161
+ foreach($responseResult->lineItemBundles->lineItems as $responseLineItem){
162
+ if($responseLineItem->customReference == $itemId){
163
+ return $responseLineItem->taxAmount->decimalValue;
164
+ }
165
+ }
166
+ return 0.0;
167
+ }
168
+
169
+ protected function _getTaxShippingAmount() {
170
+ foreach($responseResult->lineItemBundles->lineItems as $responseLineItem){
171
+ if($responseLineItem->productCode == self::TAX_SHIPPING_LINEITEM_TAX_CLASS){
172
+ return $responseLineItem->taxAmount->decimalValue;
173
+ }
174
+ }
175
+ return 0.0;
176
+ }
177
+
178
+
179
+ //Adds a comment to order history. Method choosen based on Magento version.
180
+ // protected function _addStatusHistoryComment($order, $comment) {
181
+ // if(method_exists($order, 'addStatusHistoryComment')) {
182
+ // $order->addStatusHistoryComment($comment)->save();;
183
+ // } elseif(method_exists($order, 'addStatusToHistory')) {
184
+ // $order->addStatusToHistory($order->getStatus(), $comment, false)->save();;
185
+ // }
186
+ // return $this;
187
+ // }
188
+
189
+
190
+ }
app/code/local/Harapartners/SpeedTax/Model/Observer.php ADDED
@@ -0,0 +1,67 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license [^]
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+
15
+ class Harapartners_SpeedTax_Model_Observer extends Mage_Core_Model_Abstract {
16
+
17
+ public function saleOrderInvoicePay(Varien_Event_Observer $observer) {
18
+ if (!Mage::helper('speedtax')->isSpeedTaxEnabled()) {
19
+ return;
20
+ }
21
+ $invoice = $observer->getEvent()->getInvoice();
22
+ try {
23
+ $processor = Mage::helper('speedtax/processor');
24
+ $responseResult = $processor->postOrderInvoice($invoice);
25
+ } catch( Exception $e ) {
26
+ //Suppress exception so that the transaction is not reverted (payment already processed)
27
+ Mage::logException($e);
28
+ $maskedErrorMessage = 'There is an error processing tax information.';
29
+ Mage::getSingleton('core/session')->addError($maskedErrorMessage);
30
+ }
31
+ }
32
+
33
+ public function salesOrderCreditmemoRefund(Varien_Event_Observer $observer) {
34
+ if (!Mage::helper('speedtax')->isSpeedTaxEnabled()) {
35
+ return;
36
+ }
37
+ $creditmemo = $observer->getEvent()->getCreditmemo();
38
+ try {
39
+ $processor = Mage::helper('speedtax/processor');
40
+ $responseResult = $processor->postOrderCreditmemo($creditmemo);
41
+ } catch( Exception $e ) {
42
+ //Suppress exception so that the transaction is not reverted (payment already processed)
43
+ Mage::logException($e);
44
+ $maskedErrorMessage = 'There is an error processing tax information.';
45
+ Mage::getSingleton('core/session')->addError($maskedErrorMessage);
46
+ }
47
+ }
48
+
49
+ //For manual cancel or order edit related cancellation
50
+ public function orderCancelAfter(Varien_Event_Observer $observer) {
51
+ if (!Mage::helper('speedtax')->isSpeedTaxEnabled()) {
52
+ return;
53
+ }
54
+ $order = $observer->getEvent()->getOrder();
55
+ try {
56
+ $processor = Mage::helper('speedtax/processor');
57
+ $responseResult = $processor->cancelAllOrderTransactions($order);
58
+ } catch( Exception $e ) {
59
+ //Suppress exception so that the transaction is not reverted (payment already processed)
60
+ Mage::logException($e);
61
+ $maskedErrorMessage = 'There is an error processing tax information.';
62
+ Mage::getSingleton('core/session')->addError($maskedErrorMessage);
63
+ }
64
+ }
65
+
66
+
67
+ }
app/code/local/Harapartners/SpeedTax/Model/Rewrite/Tax/Sales/Total/Quote/Tax.php ADDED
@@ -0,0 +1,56 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_SpeedTax_Model_Rewrite_Tax_Sales_Total_Quote_Tax extends Mage_Tax_Model_Sales_Total_Quote_Tax {
14
+
15
+ public function collect(Mage_Sales_Model_Quote_Address $address) {
16
+ if (!Mage::helper('speedtax')->isSpeedTaxEnabled()) {
17
+ return parent::collect($address);
18
+ }
19
+
20
+ $store = $address->getQuote()->getStore();
21
+ $customer = $address->getQuote()->getCustomer();
22
+
23
+ $address->setTotalAmount($this->getCode(), 0);
24
+ $address->setBaseTotalAmount($this->getCode(), 0);
25
+
26
+ $address->setTaxAmount(0);
27
+ $address->setBaseTaxAmount(0);
28
+ $address->setShippingTaxAmount(0);
29
+ $address->setBaseShippingTaxAmount(0);
30
+
31
+ //Init
32
+ $this->_setAddress($address);
33
+ $this->_setAmount(0);
34
+ $this->_setBaseAmount(0);
35
+
36
+ try {
37
+ $processor = Mage::helper('speedtax/processor');
38
+ $responseResult = $processor->queryQuoteAddress($address);
39
+ //Address line item amount and shipping tax amount are updated within the query
40
+ if (!!$responseResult) {
41
+ $taxAmount = $processor->getTotalTax($responseResult);
42
+ $this->_addAmount(Mage::app()->getStore()->convertPrice($taxAmount, false));
43
+ $this->_addBaseAmount($taxAmount);
44
+ }
45
+ } catch(Exception $e) {
46
+ //Tax collecting is very important, this is within the collect total (cannot bubble exceptions), force a redirect
47
+ Mage::logException($e);
48
+ $maskedErrorMessage = 'There is an error calculating tax.';
49
+ Mage::getSingleton('core/session')->addError($maskedErrorMessage);
50
+ throw new Mage_Core_Model_Session_Exception($maskedErrorMessage); //Session exceptions will be redirected to base URL
51
+ }
52
+
53
+ return $this;
54
+ }
55
+
56
+ }
app/code/local/Harapartners/SpeedTax/Model/Session.php ADDED
@@ -0,0 +1,64 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license [^]
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+
15
+ class Harapartners_SpeedTax_Model_Session extends Mage_Core_Model_Session_Abstract {
16
+
17
+ const REQUEST_CACHE_TTL = 600;
18
+
19
+ public function __construct() {
20
+ $this->init('speedtax');
21
+ }
22
+
23
+ public function loadCachedResponse($sptxInvoiceCacheKey){
24
+ $cacheStorage = $this->getData('cache_storage');
25
+ if(!isset($cacheStorage[$sptxInvoiceCacheKey])){
26
+ return false;
27
+ }
28
+ $cacheEntry = $cacheStorage[$sptxInvoiceCacheKey];
29
+ if($this->_isCacheEntryValid($cacheEntry)){
30
+ return json_decode($cacheEntry['response_json']);
31
+ }
32
+ return false;
33
+ }
34
+
35
+ public function saveCachedResponse($sptxInvoiceCacheKey, $response){
36
+ $cacheStorage = $this->getData('cache_storage');
37
+ if(!$cacheStorage){
38
+ $cacheStorage = array();
39
+ }
40
+ $cacheStorage[$sptxInvoiceCacheKey] = array(
41
+ 'timestamp' => time(),
42
+ 'response_json' => json_encode($response)
43
+ );
44
+ $cacheStorage = $this->_clearExpiredEnties($cacheStorage);
45
+ $this->setData('cache_storage', $cacheStorage);
46
+ return true;
47
+ }
48
+
49
+ protected function _clearExpiredEnties($cacheStorage){
50
+ foreach($cacheStorage as $sptxInvoiceCacheKey => $cacheEntry){
51
+ if(!$this->_isCacheEntryValid($cacheEntry)){
52
+ unset($cacheStorage[$sptxInvoiceCacheKey]);
53
+ }
54
+ }
55
+ return $cacheStorage;
56
+ }
57
+
58
+ protected function _isCacheEntryValid($cacheEntry){
59
+ return isset($cacheEntry['timestamp'])
60
+ && $cacheEntry['timestamp'] + self::REQUEST_CACHE_TTL > time()
61
+ && isset($cacheEntry['response_json']);
62
+ }
63
+
64
+ }
app/code/local/Harapartners/SpeedTax/Model/Source/Usregions.php ADDED
@@ -0,0 +1,35 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ class Harapartners_Speedtax_Model_Source_Usregions
14
+ {
15
+ protected $_options;
16
+
17
+ public function toOptionArray($isMultiselect=false)
18
+ {
19
+ if (!$this->_options) {
20
+ $regionCollection = Mage::getModel( 'directory/region' )->getCollection();
21
+ $regionCollection->getSelect()->where( 'country_id = ?', 'US' );
22
+ $regionOptions = array();
23
+ foreach( $regionCollection as $region ) {
24
+ $regionOptions[] = array( 'label' => $region->getDefaultName(), 'value' => $region->getId() );
25
+ }
26
+ $this->_options = $regionOptions;
27
+ }
28
+ $options = $this->_options;
29
+ if(!$isMultiselect){
30
+ array_unshift($options, array('value'=>'', 'label'=>''));
31
+ }
32
+
33
+ return $options;
34
+ }
35
+ }
app/code/local/Harapartners/SpeedTax/controllers/Adminhtml/System/Config/AjaxController.php ADDED
@@ -0,0 +1,55 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /**
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ */
12
+
13
+ class Harapartners_SpeedTax_Adminhtml_System_Config_AjaxController extends Mage_Adminhtml_Controller_Action {
14
+
15
+ public function authenticationAction() {
16
+
17
+ try{
18
+ $username = $this->getRequest()->getParam('username');
19
+ $password = $this->getRequest()->getParam('password');
20
+ $companyCode = $this->getRequest()->getParam('company_code');
21
+ $isTestMode = $this->getRequest()->getParam('is_test_mode');
22
+ //Check encrypted config
23
+ if (preg_match('/^\*+$/', $password)) {
24
+ $password = Mage::helper('core')->decrypt(Mage::getStoreConfig('speedtax/speedtax/password'));
25
+ }
26
+ $credentials = array(
27
+ 'username' => $username,
28
+ 'password' => $password,
29
+ 'company_code' => $companyCode,
30
+ 'is_test_mode' => $isTestMode
31
+ );
32
+
33
+ //auth_token and data_token are handled within
34
+ $result = Mage::helper ('speedtax/connector_speedtax')->authenticationRequest($credentials);
35
+
36
+ }catch(Exception $e){
37
+ $errorMessage = $e->getMessage();
38
+ if(!$errorMessage){
39
+ $errorMessage = 'Connection failed.';
40
+ }
41
+ echo json_encode(array(
42
+ 'status' => 0,
43
+ 'message' => $errorMessage
44
+ )); //Json error
45
+ exit;
46
+ }
47
+ //Need to send $websiteResultJson, the store config is still the cache value, not our new value
48
+ echo json_encode(array(
49
+ 'status' => 1,
50
+ 'message' => 'Successful! Please save your configuration'
51
+ )); //Json success
52
+ exit;
53
+ }
54
+
55
+ }
app/code/local/Harapartners/SpeedTax/etc/config.xml ADDED
@@ -0,0 +1,132 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+ -->
15
+ <config>
16
+ <modules>
17
+ <Harapartners_SpeedTax>
18
+ <version>3.1.0</version>
19
+ </Harapartners_SpeedTax>
20
+ </modules>
21
+ <global>
22
+ <blocks>
23
+ <speedtax>
24
+ <class>Harapartners_SpeedTax_Block</class>
25
+ </speedtax>
26
+ </blocks>
27
+ <models>
28
+ <speedtax>
29
+ <class>Harapartners_SpeedTax_Model</class>
30
+ </speedtax>
31
+ <tax>
32
+ <rewrite>
33
+ <sales_total_quote_tax>Harapartners_SpeedTax_Model_Rewrite_Tax_Sales_Total_Quote_Tax</sales_total_quote_tax>
34
+ </rewrite>
35
+ </tax>
36
+ </models>
37
+ <helpers>
38
+ <speedtax>
39
+ <class>Harapartners_SpeedTax_Helper</class>
40
+ </speedtax>
41
+ </helpers>
42
+ <resources>
43
+ <speedtax_setup>
44
+ <setup>
45
+ <module>Harapartners_SpeedTax</module>
46
+ </setup>
47
+ <connection>
48
+ <use>core_setup</use>
49
+ </connection>
50
+ </speedtax_setup>
51
+ </resources>
52
+ <events>
53
+ <sales_order_invoice_pay>
54
+ <observers>
55
+ <speedtax>
56
+ <type>singleton</type>
57
+ <class>speedtax/observer</class>
58
+ <method>saleOrderInvoicePay</method>
59
+ </speedtax>
60
+ </observers>
61
+ </sales_order_invoice_pay>
62
+ <sales_order_creditmemo_refund>
63
+ <observers>
64
+ <speedtax>
65
+ <type>singleton</type>
66
+ <class>speedtax/observer</class>
67
+ <method>salesOrderCreditmemoRefund</method>
68
+ </speedtax>
69
+ </observers>
70
+ </sales_order_creditmemo_refund>
71
+ <order_cancel_after>
72
+ <observers>
73
+ <speedtax>
74
+ <type>singleton</type>
75
+ <class>speedtax/observer</class>
76
+ <method>orderCancelAfter</method>
77
+ </speedtax>
78
+ </observers>
79
+ </order_cancel_after>
80
+ </events>
81
+ </global>
82
+ <adminhtml>
83
+ <acl>
84
+ <resources>
85
+ <admin>
86
+ <children>
87
+ <system>
88
+ <children>
89
+ <config>
90
+ <children>
91
+ <speedtax translate="title" module="speedtax">
92
+ <title>SpeedTax Configuration</title>
93
+ </speedtax>
94
+ </children>
95
+ </config>
96
+ </children>
97
+ </system>
98
+ </children>
99
+ </admin>
100
+ </resources>
101
+ </acl>
102
+ </adminhtml>
103
+ <admin>
104
+ <routers>
105
+ <speedtax_adminhtml>
106
+ <use>admin</use>
107
+ <args>
108
+ <module>Harapartners_SpeedTax_Adminhtml</module>
109
+ <frontName>speedtax_adminhtml</frontName>
110
+ </args>
111
+ </speedtax_adminhtml>
112
+ </routers>
113
+ </admin>
114
+ <default>
115
+ <speedtax>
116
+ <speedtax>
117
+ <action>0</action>
118
+ <url>https://www.speedtax.com/</url>
119
+ <shipping_sku>Shipping</shipping_sku>
120
+ <adjustment_positive_sku>Adjustment</adjustment_positive_sku>
121
+ <adjustment_negative_sku>Adjustment</adjustment_negative_sku>
122
+ <sales_person_code>Magento</sales_person_code>
123
+ <error_full_stop>1</error_full_stop>
124
+ <error_frontend_action>2</error_frontend_action>
125
+ <error_frontend_message>Unfortunately, we could not calculate tax for your order. Please try again with a different address or contact us to complete your order.</error_frontend_message>
126
+ <error_backend_message>There was an error getting tax rates from Speedtax. Please see the error log for details.</error_backend_message>
127
+ <error_notification_toolbar>1</error_notification_toolbar>
128
+ <onepage_normalize_message>Your shipping address has been modified during our validation process. Please confirm the address to the right is accurate.</onepage_normalize_message>
129
+ </speedtax>
130
+ </speedtax>
131
+ </default>
132
+ </config>
app/code/local/Harapartners/SpeedTax/etc/system.xml ADDED
@@ -0,0 +1,167 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?xml version="1.0"?>
2
+ <!--
3
+ /*
4
+ * NOTICE OF LICENSE
5
+ *
6
+ * This source file is subject to the End User Software Agreement (EULA).
7
+ * It is also available through the world-wide-web at this URL:
8
+ * http://www.harapartners.com/license
9
+ * If you did not receive a copy of the license and are unable to
10
+ * obtain it through the world-wide-web, please send an email
11
+ * to eula@harapartners.com so we can send you a copy immediately.
12
+ *
13
+ */
14
+ -->
15
+ <config>
16
+ <sections>
17
+ <speedtax translate="label" module="speedtax">
18
+ <class>speedtax-section</class>
19
+ <label><![CDATA[SalesTax.com by <br/><img src="https://www.harapartners.com/skin/frontend/enterprise/harapartners/images/hp/HP2.0Logo.png" alt="HaraPartners" width="100" height="20">]]></label>
20
+ <header_css>speedtax-header</header_css>
21
+ <tab>sales</tab>
22
+ <sort_order>304</sort_order>
23
+ <show_in_default>1</show_in_default>
24
+ <show_in_website>1</show_in_website>
25
+ <show_in_store>1</show_in_store>
26
+ <groups>
27
+ <signup>
28
+ <label>Sign up for SalesTax.com</label>
29
+ <comment><![CDATA[
30
+ <p class="switcher">
31
+ Sign up for a <a href="http://harapartners.com/solutions/salestax/30daytrial" target="_blank" style="color: #00C3FF;">Free 30 Day Trial</a>.<br/>
32
+ <a href="http://www.harapartners.com/solutions/salestax/signup" target="_blank" style="color: #00C3FF;">Sign up for SalesTax.com to process your Sales Taxes.</a>.<br/>
33
+ Call with questions at <b>646-663-5672</b> or find more information under <a href="http://www.harapartners.com/salestax" target="_blank" style="color: #00C3FF;">http://www.harapartners.com/salestax</a>.
34
+ </p>
35
+ ]]></comment>
36
+ <sort_order>0</sort_order>
37
+ <show_in_default>1</show_in_default>
38
+ <show_in_website>1</show_in_website>
39
+ <show_in_store>1</show_in_store>
40
+ <expanded>1</expanded>
41
+ </signup>
42
+ <speedtax>
43
+ <label>SalesTax.com Configuration</label>
44
+ <sort_order>0</sort_order>
45
+ <show_in_default>1</show_in_default>
46
+ <show_in_website>1</show_in_website>
47
+ <show_in_store>1</show_in_store>
48
+ <fields>
49
+ <is_enabled translate="label">
50
+ <label>Status</label>
51
+ <comment>If the Status is set to "Disable", default Magento tax calculations will be used.</comment>
52
+ <frontend_type>select</frontend_type>
53
+ <source_model>adminhtml/system_config_source_enabledisable</source_model>
54
+ <sort_order>100</sort_order>
55
+ <show_in_default>1</show_in_default>
56
+ <show_in_website>1</show_in_website>
57
+ <show_in_store>1</show_in_store>
58
+ </is_enabled>
59
+ <username translate="label">
60
+ <label>Username</label>
61
+ <comment>Should have been provided in your sign up email.</comment>
62
+ <frontend_type>text</frontend_type>
63
+ <sort_order>110</sort_order>
64
+ <show_in_default>1</show_in_default>
65
+ <show_in_website>1</show_in_website>
66
+ <show_in_store>1</show_in_store>
67
+ <validate>required-entry</validate>
68
+ </username>
69
+ <password translate="label">
70
+ <label>Password</label>
71
+ <comment>Should have been provided in your sign up email.</comment>
72
+ <frontend_type>obscure</frontend_type>
73
+ <backend_model>adminhtml/system_config_backend_encrypted</backend_model>
74
+ <sort_order>115</sort_order>
75
+ <show_in_default>1</show_in_default>
76
+ <show_in_website>1</show_in_website>
77
+ <show_in_store>1</show_in_store>
78
+ <validate>required-entry</validate>
79
+ </password>
80
+ <company_code translate="label">
81
+ <label>Company Code</label>
82
+ <comment>Should have been provided in your sign up email.</comment>
83
+ <frontend_type>text</frontend_type>
84
+ <sort_order>120</sort_order>
85
+ <show_in_default>1</show_in_default>
86
+ <show_in_website>1</show_in_website>
87
+ <show_in_store>1</show_in_store>
88
+ <validate>required-entry</validate>
89
+ </company_code>
90
+ <is_test_mode translate="label">
91
+ <label>Test Mode</label>
92
+ <comment>Switch between test and live modes. Requires a test account and credentials.</comment>
93
+ <frontend_type>select</frontend_type>
94
+ <source_model>adminhtml/system_config_source_yesno</source_model>
95
+ <sort_order>125</sort_order>
96
+ <show_in_default>1</show_in_default>
97
+ <show_in_website>1</show_in_website>
98
+ <show_in_store>1</show_in_store>
99
+ </is_test_mode>
100
+ <authentication_wizard translate="button_label">
101
+ <label></label>
102
+ <comment><![CDATA[You <b style="color: red;">must</b> validate your login credentials first and then <b style="color: red;">save</b> the configuration.]]></comment>
103
+ <button_label>Validate login credentials</button_label>
104
+ <frontend_model>speedtax/adminhtml_system_config_form_field_authentication</frontend_model>
105
+ <sort_order>150</sort_order>
106
+ <show_in_default>1</show_in_default>
107
+ <show_in_website>1</show_in_website>
108
+ <show_in_store>0</show_in_store>
109
+ </authentication_wizard>
110
+ <tax_shipping translate="label">
111
+ <label>Calculate Taxes On Shipping</label>
112
+ <comment>This will send a line item for SHIPPING to be taxed.</comment>
113
+ <frontend_type>select</frontend_type>
114
+ <source_model>adminhtml/system_config_source_enabledisable</source_model>
115
+ <sort_order>311</sort_order>
116
+ <show_in_default>1</show_in_default>
117
+ <show_in_website>1</show_in_website>
118
+ <show_in_store>1</show_in_store>
119
+ </tax_shipping>
120
+ <origins translate="label">
121
+ <label>Nexus</label>
122
+ <comment><![CDATA[Multiple-select. Select all states where you have nexus and want sales taxes to be used for.]]></comment>
123
+ <frontend_type>multiselect</frontend_type>
124
+ <sort_order>350</sort_order>
125
+ <source_model>speedtax/source_usregions</source_model>
126
+ <show_in_default>1</show_in_default>
127
+ <show_in_website>1</show_in_website>
128
+ <show_in_store>0</show_in_store>
129
+ <validate>required-entry</validate>
130
+ </origins>
131
+ </fields>
132
+ </speedtax>
133
+ <help_extra>
134
+ <label>SalesTax.com Help</label>
135
+ <comment><![CDATA[
136
+ <p class="switcher">
137
+ Get help with configuring and setting up the SalesTax.com module at <a href="http://www.harapartners.com/salestax/help#configuration" target="_blank" style="color: #00C3FF;">http://www.harapartners.com/salestax/help#configuration</a>.<br/>
138
+ Find more information at <a href="http://www.harapartners.com/salestax/help" target="_blank" style="color: #00C3FF;">http://www.harapartners.com/salestax/help</a>.<br/>
139
+ Learn more about the SalesTax.com solution, additional features, updates and help at <a href="http://www.harapartners.com/salestax" target="_blank" style="color: #00C3FF;">http://www.harapartners.com/salestax</a>.
140
+ </p>
141
+ ]]></comment>
142
+ <sort_order>100</sort_order>
143
+ <show_in_default>1</show_in_default>
144
+ <show_in_website>1</show_in_website>
145
+ <show_in_store>1</show_in_store>
146
+ <expanded>1</expanded>
147
+ </help_extra>
148
+ </groups>
149
+ </speedtax>
150
+ <shipping>
151
+ <groups>
152
+ <origin>
153
+ <fields>
154
+ <street translate="label">
155
+ <label><![CDATA[Number & Street]]></label>
156
+ <frontend_type>text</frontend_type>
157
+ <sort_order>99</sort_order>
158
+ <show_in_default>1</show_in_default>
159
+ <show_in_website>1</show_in_website>
160
+ <show_in_store>1</show_in_store>
161
+ </street>
162
+ </fields>
163
+ </origin>
164
+ </groups>
165
+ </shipping>
166
+ </sections>
167
+ </config>
app/code/local/Harapartners/SpeedTax/sql/speedtax_setup/mysql4-upgrade-3.0.9-3.1.0.php ADDED
@@ -0,0 +1,126 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ <?php
2
+ /*
3
+ * NOTICE OF LICENSE
4
+ *
5
+ * This source file is subject to the End User Software Agreement (EULA).
6
+ * It is also available through the world-wide-web at this URL:
7
+ * http://www.harapartners.com/license [^]
8
+ * If you did not receive a copy of the license and are unable to
9
+ * obtain it through the world-wide-web, please send an email
10
+ * to eula@harapartners.com so we can send you a copy immediately.
11
+ *
12
+ */
13
+ $installer = $this;
14
+ $installer->startSetup();
15
+
16
+ $speedTaxTransactionIdColumnName = 'speedtax_transaction_id';
17
+ $speedtaxInvoiceNumberColumnName = 'speedtax_invoice_number';
18
+ $speedtaxInvoiceStatusColumnName = 'speedtax_invoice_status';
19
+ $connectionConfig = $installer->getConnection()->getConfig();
20
+
21
+ // ================ Invoice ================ //
22
+ $testQuery = "
23
+ SELECT * FROM information_schema.COLUMNS
24
+ WHERE column_name='$speedtaxInvoiceNumberColumnName'
25
+ AND table_name='{$this->getTable('sales/invoice')}'
26
+ AND table_schema='{$connectionConfig['dbname']}'
27
+ ";
28
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
29
+ $installer->run("
30
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
31
+ DROP COLUMN `$speedtaxInvoiceNumberColumnName`;
32
+ ");
33
+ }
34
+ $installer->run("
35
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
36
+ ADD COLUMN `$speedtaxInvoiceNumberColumnName` varchar(255);
37
+ ");
38
+
39
+ $testQuery = "
40
+ SELECT * FROM information_schema.COLUMNS
41
+ WHERE column_name='$speedtaxInvoiceStatusColumnName'
42
+ AND table_name='{$this->getTable('sales/invoice')}'
43
+ AND table_schema='{$connectionConfig['dbname']}'
44
+ ";
45
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
46
+ $installer->run("
47
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
48
+ DROP COLUMN `$speedtaxInvoiceStatusColumnName`;
49
+ ");
50
+ }
51
+ $installer->run("
52
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
53
+ ADD COLUMN `$speedtaxInvoiceStatusColumnName` SMALLINT(5) DEFAULT 0;
54
+ ");
55
+
56
+ $testQuery = "
57
+ SELECT * FROM information_schema.COLUMNS
58
+ WHERE column_name='$speedTaxTransactionIdColumnName'
59
+ AND table_name='{$this->getTable('sales/invoice')}'
60
+ AND table_schema='{$connectionConfig['dbname']}'
61
+ ";
62
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
63
+ $installer->run("
64
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
65
+ DROP COLUMN `$speedTaxTransactionIdColumnName`;
66
+ ");
67
+ }
68
+ $installer->run("
69
+ ALTER TABLE `{$this->getTable('sales/invoice')}`
70
+ ADD COLUMN `$speedTaxTransactionIdColumnName` varchar(255);
71
+ ");
72
+
73
+
74
+ // ================ Credit Memo ================ //
75
+ $testQuery = "
76
+ SELECT * FROM information_schema.COLUMNS
77
+ WHERE column_name='$speedtaxInvoiceNumberColumnName'
78
+ AND table_name='{$this->getTable('sales/creditmemo')}'
79
+ AND table_schema='{$connectionConfig['dbname']}'
80
+ ";
81
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
82
+ $installer->run("
83
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
84
+ DROP COLUMN `$speedtaxInvoiceNumberColumnName`;
85
+ ");
86
+ }
87
+ $installer->run("
88
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
89
+ ADD COLUMN `$speedtaxInvoiceNumberColumnName` varchar(255);
90
+ ");
91
+
92
+ $testQuery = "
93
+ SELECT * FROM information_schema.COLUMNS
94
+ WHERE column_name='$speedtaxInvoiceStatusColumnName'
95
+ AND table_name='{$this->getTable('sales/creditmemo')}'
96
+ AND table_schema='{$connectionConfig['dbname']}'
97
+ ";
98
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
99
+ $installer->run("
100
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
101
+ DROP COLUMN `$speedtaxInvoiceStatusColumnName`;
102
+ ");
103
+ }
104
+ $installer->run("
105
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
106
+ ADD COLUMN `$speedtaxInvoiceStatusColumnName` SMALLINT(5) DEFAULT 0;
107
+ ");
108
+
109
+ $testQuery = "
110
+ SELECT * FROM information_schema.COLUMNS
111
+ WHERE column_name='$speedTaxTransactionIdColumnName'
112
+ AND table_name='{$this->getTable('sales/creditmemo')}'
113
+ AND table_schema='{$connectionConfig['dbname']}'
114
+ ";
115
+ if(!!$installer->getConnection()->fetchAll($testQuery)){
116
+ $installer->run("
117
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
118
+ DROP COLUMN `$speedTaxTransactionIdColumnName`;
119
+ ");
120
+ }
121
+ $installer->run("
122
+ ALTER TABLE `{$this->getTable('sales/creditmemo')}`
123
+ ADD COLUMN `$speedTaxTransactionIdColumnName` varchar(255);
124
+ ");
125
+
126
+ $installer->endSetup();
package.xml CHANGED
@@ -1,7 +1,7 @@
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>SalesTax_Connector</name>
4
- <version>3.1.3</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.harapartners.com/terms/eula">Hara Partners End User License Agreement</license>
7
  <channel>community</channel>
@@ -11,8 +11,8 @@
11
  <notes>Simplify sales and use tax calculation, compliance, and management in the cloud!</notes>
12
  <authors><author><name>Ken Nunes</name><user>auto-converted</user><email>Ken.nunes@wolterskluwer.com</email></author></authors>
13
  <date>2014-01-13</date>
14
- <time>20:57:55</time>
15
- <contents><target name="mageetc"><dir name="modules"><file name="Harapartners_ConnectorHub.xml" hash="77e80f0f2d28c0ff45b869d467b49bbf"/><file name="Harapartners_SpeedTax.xml" hash="4e25b9cfbbb9568913aeb75dbae21b0d"/></dir></target></contents>
16
  <compatible/>
17
  <dependencies/>
18
  </package>
1
  <?xml version="1.0"?>
2
  <package>
3
  <name>SalesTax_Connector</name>
4
+ <version>3.1.4</version>
5
  <stability>stable</stability>
6
  <license uri="http://www.harapartners.com/terms/eula">Hara Partners End User License Agreement</license>
7
  <channel>community</channel>
11
  <notes>Simplify sales and use tax calculation, compliance, and management in the cloud!</notes>
12
  <authors><author><name>Ken Nunes</name><user>auto-converted</user><email>Ken.nunes@wolterskluwer.com</email></author></authors>
13
  <date>2014-01-13</date>
14
+ <time>21:16:23</time>
15
+ <contents><target name="magelocal"><dir name="Harapartners"><dir name="ConnectorHub"><dir name="etc"><file name="config.xml" hash="8ca81abfe825b4311d3df7f2f8eadcda"/></dir><dir name="Helper"><dir name="Connector"><file name="Core.php" hash="8920087fc8197902ebd939100dbaf6f4"/></dir><file name="Mcrypt.php" hash="928572b4884d60f03ecde04b63186ea2"/><file name="Object.php" hash="487cd77c21c8bb9dec6189cc19d8c6a5"/></dir><dir name="Model"><dir name="Rewrite"><dir name="Paypal"><dir name="Api"><file name="Nvp.php" hash="e260f23f4093e7932286f81bf48f855a"/></dir><file name="Config.php" hash="41db0559b01ef40fa3a33e85a416d016"/></dir></dir></dir></dir><dir name="SpeedTax"><dir name="Block"><dir name="Adminhtml"><dir name="System"><dir name="Config"><dir name="Form"><dir name="Field"><file name="Authentication.php" hash="8be5a91c0aa3d23ced5a2852b940dac3"/></dir></dir></dir></dir></dir></dir><dir name="controllers"><dir name="Adminhtml"><dir name="System"><dir name="Config"><file name="AjaxController.php" hash="3d127613228ef0decd5ea7e91c05ce83"/></dir></dir></dir></dir><dir name="etc"><file name="config.xml" hash="ca61333dc3d0679c5ee6a1770d15c53f"/><file name="system.xml" hash="a213e1d32c12a2251ecaf639ae491bcc"/></dir><dir name="Helper"><dir name="Connector"><file name="Data.php" hash="4ae2eb94b6cf797eef7e2a7a8249e073"/><file name="Speedtax.php" hash="c818691755b59c20d1271a2f3c22d579"/></dir><file name="Data.php" hash="4a3805bc334300c5b79afa89a3330be6"/><file name="Processor.php" hash="600241518208610cc76ffd6051d1cb6a"/></dir><dir name="Model"><dir name="Rewrite"><dir name="Tax"><dir name="Sales"><dir name="Total"><dir name="Quote"><file name="Tax.php" hash="00a4b49781a30b5b19ea82b083dcd2df"/></dir></dir></dir></dir></dir><dir name="Source"><file name="Usregions.php" hash="2ab7713b5b46f142e133459952cd1ef5"/></dir><file name="Observer.php" hash="609d1237bc2eddedeb629ed322540fc8"/><file name="Session.php" hash="46175fe01434d91757499d5c0f7f2bee"/></dir><dir name="sql"><dir name="speedtax_setup"><file name="mysql4-upgrade-3.0.9-3.1.0.php" hash="886b0ebdd5b0234b89fcff5fc07fbfd1"/></dir></dir></dir></dir></target><target name="mageetc"><dir name="modules"><file name="Harapartners_ConnectorHub.xml" hash="77e80f0f2d28c0ff45b869d467b49bbf"/><file name="Harapartners_SpeedTax.xml" hash="4e25b9cfbbb9568913aeb75dbae21b0d"/></dir></target></contents>
16
  <compatible/>
17
  <dependencies/>
18
  </package>