1
|
|
|
<?php |
2
|
|
|
/** |
3
|
|
|
* Copyright (c) 2013-2014 eBay Enterprise, Inc. |
4
|
|
|
* |
5
|
|
|
* NOTICE OF LICENSE |
6
|
|
|
* |
7
|
|
|
* This source file is subject to the Open Software License (OSL 3.0) |
8
|
|
|
* that is bundled with this package in the file LICENSE.md. |
9
|
|
|
* It is also available through the world-wide-web at this URL: |
10
|
|
|
* http://opensource.org/licenses/osl-3.0.php |
11
|
|
|
* |
12
|
|
|
* @copyright Copyright (c) 2013-2014 eBay Enterprise, Inc. (http://www.ebayenterprise.com/) |
13
|
|
|
* @license http://opensource.org/licenses/osl-3.0.php Open Software License (OSL 3.0) |
14
|
|
|
*/ |
15
|
|
|
|
16
|
|
|
class EbayEnterprise_Tax_Model_Observer |
17
|
|
|
{ |
18
|
|
|
/** @var bool Lock to guard against too much recursion in quote collect totals */ |
19
|
|
|
protected static $lockRecollectTotals = false; |
20
|
|
|
/** @var EbayEnterprise_Tax_Model_Collector */ |
21
|
|
|
protected $taxCollector; |
22
|
|
|
/** @var EbayEnterprise_Eb2cCore_Model_Session */ |
23
|
|
|
protected $coreSession; |
24
|
|
|
/** @var EbayEnterprise_MageLog_Helper_Data */ |
25
|
|
|
protected $logger; |
26
|
|
|
/** @var EbayEnterprise_MageLog_Helper_Context */ |
27
|
|
|
protected $logContext; |
28
|
|
|
|
29
|
|
|
/** |
30
|
|
|
* @param array |
31
|
|
|
*/ |
32
|
|
View Code Duplication |
public function __construct(array $args = []) |
|
|
|
|
33
|
|
|
{ |
34
|
|
|
list( |
35
|
|
|
$this->taxCollector, |
36
|
|
|
$this->coreSession, |
37
|
|
|
$this->logger, |
38
|
|
|
$this->logContext |
39
|
|
|
) = $this->checkTypes( |
40
|
|
|
$this->nullCoalesce($args, 'tax_collector', Mage::getModel('ebayenterprise_tax/collector')), |
41
|
|
|
$this->nullCoalesce($args, 'core_session', null), |
42
|
|
|
$this->nullCoalesce($args, 'logger', Mage::helper('ebayenterprise_magelog')), |
43
|
|
|
$this->nullCoalesce($args, 'log_context', Mage::helper('ebayenterprise_magelog/context')) |
44
|
|
|
); |
45
|
|
|
} |
46
|
|
|
|
47
|
|
|
/** |
48
|
|
|
* Enforce type checks on construct args array. |
49
|
|
|
* |
50
|
|
|
* @param EbayEnterprise_Tax_Model_Collector |
51
|
|
|
* @param EbayEnterprise_Tax_Model_Session |
52
|
|
|
* @param EbayEnterprise_MageLog_Helper_Data |
53
|
|
|
* @param EbayEnterprise_MageLog_Helper_Context |
54
|
|
|
* @return array |
55
|
|
|
*/ |
56
|
|
|
protected function checkTypes( |
|
|
|
|
57
|
|
|
EbayEnterprise_Tax_Model_Collector $taxCollector, |
|
|
|
|
58
|
|
|
EbayEnterprise_Eb2cCore_Model_Session $coreSession = null, |
|
|
|
|
59
|
|
|
EbayEnterprise_MageLog_Helper_Data $logger, |
|
|
|
|
60
|
|
|
EbayEnterprise_MageLog_Helper_Context $logContext |
|
|
|
|
61
|
|
|
) { |
62
|
|
|
return func_get_args(); |
63
|
|
|
} |
64
|
|
|
|
65
|
|
|
/** |
66
|
|
|
* Fill in default values. |
67
|
|
|
* |
68
|
|
|
* @param string |
69
|
|
|
* @param array |
70
|
|
|
* @param mixed |
71
|
|
|
* @return mixed |
72
|
|
|
*/ |
73
|
|
|
protected function nullCoalesce(array $arr, $key, $default) |
74
|
|
|
{ |
75
|
|
|
return isset($arr[$key]) ? $arr[$key] : $default; |
76
|
|
|
} |
77
|
|
|
|
78
|
|
|
/** |
79
|
|
|
* Get the session instance containing collected tax data for the quote. |
80
|
|
|
* Populates the class property if not set when requested. The property |
81
|
|
|
* will not be set during construction to minimize the risk of initializing |
82
|
|
|
* the session instance before the user session has been started. |
83
|
|
|
* |
84
|
|
|
* @return EbayEnterprise_Eb2cCore_Model_Session |
85
|
|
|
*/ |
86
|
|
|
protected function getCoreSession() |
87
|
|
|
{ |
88
|
|
|
if (!$this->coreSession) { |
89
|
|
|
$this->coreSession = Mage::getSingleton('eb2ccore/session'); |
90
|
|
|
} |
91
|
|
|
return $this->coreSession; |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Collect new tax totals if necessary after collecting quote totals. |
96
|
|
|
* Tax totals collected after all other quote totals so tax totals for the |
97
|
|
|
* entire quote may be collected at one - all other totals for all other |
98
|
|
|
* addresses must have already been collected. |
99
|
|
|
* |
100
|
|
|
* If new taxes are collected, all quote totals must be recollected. |
101
|
|
|
* |
102
|
|
|
* @param Varien_Event_Observer |
103
|
|
|
* @return self |
104
|
|
|
*/ |
105
|
|
|
public function handleSalesQuoteCollectTotalsAfter(Varien_Event_Observer $observer) |
106
|
|
|
{ |
107
|
|
|
$coreSession = $this->getCoreSession(); |
108
|
|
|
if ($coreSession->isTaxUpdateRequired()) { |
109
|
|
|
/** @var Mage_Sales_Model_Quote */ |
110
|
|
|
$quote = $observer->getEvent()->getQuote(); |
111
|
|
|
try { |
112
|
|
|
$this->taxCollector->collectTaxes($quote); |
113
|
|
|
} catch (EbayEnterprise_Tax_Exception_Collector_InvalidQuote_Exception $e) { |
114
|
|
|
// Exception for when a quote is not yet ready for making |
115
|
|
|
// a tax request. Not an entirely uncommon situation and |
116
|
|
|
// does not necessarily indicate anything is actually wrong |
117
|
|
|
// unless the quote is expected to be valid but isn't. |
118
|
|
|
$this->logger->debug('Quote not valid for tax request.', $this->logContext->getMetaData(__CLASS__)); |
119
|
|
|
return $this; |
120
|
|
|
} catch (EbayEnterprise_Tax_Exception_Collector_Exception $e) { |
121
|
|
|
// Want TDF to be non-blocking so exceptions from making the |
122
|
|
|
// request should be caught. Still need to exit here when there |
123
|
|
|
// is an exception, however, to allow the TDF to be retried |
124
|
|
|
// (don't reset update required flag) and prevent totals from being |
125
|
|
|
// recollected (nothing to update and, more imporantly, would |
126
|
|
|
// continue to loop until PHP crashes or a TDF request succeeds). |
127
|
|
|
$this->logger->warning('Tax request failed.', $this->logContext->getMetaData(__CLASS__, [], $e)); |
128
|
|
|
return $this; |
129
|
|
|
} |
130
|
|
|
// After retrieving new tax records, update the session with data |
131
|
|
|
// from the quote used to make the request and reset the tax |
132
|
|
|
// update required flag as another update should not be required |
133
|
|
|
// until some other change has been detected. |
134
|
|
|
$this->logger->debug('Update session flags after tax collection.', $this->logContext->getMetaData(__CLASS__)); |
135
|
|
|
$coreSession->updateWithQuote($quote)->resetTaxUpdateRequired(); |
136
|
|
|
// Need to trigger a re-collection of quote totals now that taxes |
137
|
|
|
// for the quote have been retrieved. On the second pass, tax totals |
138
|
|
|
// just collected should be applied to the quote and any totals |
139
|
|
|
// dependent upon tax totals - like grand total - should update |
140
|
|
|
// to include the tax totals. |
141
|
|
|
$this->recollectTotals($quote); |
142
|
|
|
} |
143
|
|
|
return $this; |
144
|
|
|
} |
145
|
|
|
|
146
|
|
|
/** |
147
|
|
|
* set the tax header error flag on the order create request. |
148
|
|
|
* @param Varien_Event_Observer |
149
|
|
|
* @return self |
150
|
|
|
*/ |
151
|
|
|
public function handleOrderCreateBeforeAttachEvent(Varien_Event_Observer $observer) |
152
|
|
|
{ |
153
|
|
|
$event = $observer->getEvent(); |
154
|
|
|
Mage::getModel( |
155
|
|
|
'ebayenterprise_tax/order_create_order', |
156
|
|
|
['order_create_request' => $event->getPayload()] |
157
|
|
|
)->addTaxHeaderErrorFlag(); |
158
|
|
|
return $this; |
159
|
|
|
} |
160
|
|
|
|
161
|
|
|
/** |
162
|
|
|
* set gifting tax data on the shipgroup payload for the order create request |
163
|
|
|
* @param Varien_Event_Observer |
164
|
|
|
* @return self |
165
|
|
|
*/ |
166
|
|
|
public function handleOrderCreateShipGroupEvent(Varien_Event_Observer $observer) |
167
|
|
|
{ |
168
|
|
|
$event = $observer->getEvent(); |
169
|
|
|
Mage::getModel( |
170
|
|
|
'ebayenterprise_tax/order_create_shipgroup', |
171
|
|
|
[ |
172
|
|
|
'address' => $event->getAddress(), |
173
|
|
|
'ship_group' => $event->getShipGroupPayload(), |
174
|
|
|
] |
175
|
|
|
)->addGiftTaxesToPayload(); |
176
|
|
|
return $this; |
177
|
|
|
} |
178
|
|
|
|
179
|
|
|
/** |
180
|
|
|
* set tax data on the orderitem payload for the order create request |
181
|
|
|
* @param Varien_Event_Observer |
182
|
|
|
* @return self |
183
|
|
|
*/ |
184
|
|
|
public function handleOrderCreateItemEvent(Varien_Event_Observer $observer) |
185
|
|
|
{ |
186
|
|
|
$event = $observer->getEvent(); |
187
|
|
|
$item = $event->getItem(); |
188
|
|
|
$quoteItemId = $item->getQuoteItemId(); |
189
|
|
|
Mage::getModel( |
190
|
|
|
'ebayenterprise_tax/order_create_orderitem', |
191
|
|
|
[ |
192
|
|
|
'item' => $event->getItem(), |
193
|
|
|
'tax_records' => $this->taxCollector->getTaxRecordsByItemId($quoteItemId), |
194
|
|
|
'duty' => $this->taxCollector->getTaxDutyByItemId($quoteItemId), |
195
|
|
|
'fees' => $this->taxCollector->getTaxFeesByItemId($quoteItemId), |
196
|
|
|
'order_item_payload' => $event->getItemPayload(), |
197
|
|
|
] |
198
|
|
|
)->addTaxesToPayload(); |
199
|
|
|
return $this; |
200
|
|
|
} |
201
|
|
|
|
202
|
|
|
/** |
203
|
|
|
* Recollect quote totals to update amounts based on newly received tax |
204
|
|
|
* data. This collect totals call is expected to happen recursively within |
205
|
|
|
* collect totals. The flags in eb2ccore/session are expected to prevent |
206
|
|
|
* going beyond a single recursive call to collect totals. As an additional |
207
|
|
|
* precaution, a lock is also used to prevent unexpected recursion. |
208
|
|
|
* |
209
|
|
|
* @param Mage_Sales_Model_Quote |
210
|
|
|
* @return Mage_Sales_Model_Quote |
211
|
|
|
*/ |
212
|
|
|
protected function recollectTotals(Mage_Sales_Model_Quote $quote) |
213
|
|
|
{ |
214
|
|
|
// Guard against unexpected recursion. Session flags should prevent |
215
|
|
|
// this but need to be sure this can't trigger infinite recursion. |
216
|
|
|
// If the lock is free (set to false), expect to not be within a recursive |
217
|
|
|
// collectTotals triggered by taxes. |
218
|
|
|
if (!self::$lockRecollectTotals) { |
219
|
|
|
// Acquire the lock prior to triggering the recursion. Prevents taxes |
220
|
|
|
// from being able to trigger further recursion. |
221
|
|
|
self::$lockRecollectTotals = true; |
222
|
|
|
$quote->collectTotals(); |
223
|
|
|
// Free the lock once we're clear of the recursive collectTotals. |
224
|
|
|
self::$lockRecollectTotals = false; |
225
|
|
|
} else { |
226
|
|
|
// Do not expect further recursive attempts to occur. Something |
227
|
|
|
// would be potentially wrong with the session flags if it does. |
228
|
|
|
$this->logger->warning('Attempted to recollect totals for taxes during a recursive collection. Additional collection averted to prevent further recursion.', $this->logContext->getMetaData(__CLASS__)); |
229
|
|
|
} |
230
|
|
|
return $quote; |
231
|
|
|
} |
232
|
|
|
} |
233
|
|
|
|
Duplicated code is one of the most pungent code smells. If you need to duplicate the same code in three or more different places, we strongly encourage you to look into extracting the code into a single class or operation.
You can also find more detailed suggestions in the “Code” section of your repository.