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
|
|
|
use eBayEnterprise\RetailOrderManagement\Api\Exception\NetworkError; |
17
|
|
|
use eBayEnterprise\RetailOrderManagement\Api\Exception\UnsupportedHttpAction; |
18
|
|
|
use eBayEnterprise\RetailOrderManagement\Api\Exception\UnsupportedOperation; |
19
|
|
|
use eBayEnterprise\RetailOrderManagement\Api\IBidirectionalApi; |
20
|
|
|
use eBayEnterprise\RetailOrderManagement\Payload\Exception\InvalidPayload; |
21
|
|
|
|
22
|
|
|
/** |
23
|
|
|
* Handles validating address via the address validation service, |
24
|
|
|
* storing and retrieving address suggestions. |
25
|
|
|
*/ |
26
|
|
|
class EbayEnterprise_Address_Model_Validator |
27
|
|
|
{ |
28
|
|
|
const SESSION_KEY = 'address_validation_addresses'; |
29
|
|
|
const SUGGESTIONS_ERROR_MESSAGE = 'EbayEnterprise_Address_Suggestions_Error_Message'; |
30
|
|
|
const NO_SUGGESTIONS_ERROR_MESSAGE = 'EbayEnterprise_Address_No_Suggestions_Error_Message'; |
31
|
|
|
|
32
|
|
|
/** @var EbayEnterprise_MageLog_Helper_Data */ |
33
|
|
|
protected $_logger; |
34
|
|
|
/** @var EbayEnterprise_Address_Helper_Data */ |
35
|
|
|
protected $_helper; |
36
|
|
|
/** @var EbayEnterprise_Eb2cCore_Helper_Data */ |
37
|
|
|
protected $_coreHelper; |
38
|
|
|
/** @var EbayEnterprise_MageLog_Helper_Context */ |
39
|
|
|
protected $_context; |
40
|
|
|
|
41
|
|
|
/** |
42
|
|
|
* @param array |
43
|
|
|
*/ |
44
|
|
|
public function __construct(array $args = []) |
45
|
|
|
{ |
46
|
|
|
list($this->_logger, $this->_helper, $this->_coreHelper, $this->_context) = $this->_checkTypes( |
47
|
|
|
$this->_nullCoalesce($args, 'logger', Mage::helper('ebayenterprise_magelog')), |
48
|
|
|
$this->_nullCoalesce($args, 'helper', Mage::helper('ebayenterprise_address')), |
49
|
|
|
$this->_nullCoalesce($args, 'core_helper', Mage::helper('eb2ccore')), |
50
|
|
|
$this->_nullCoalesce($args, 'context', Mage::helper('ebayenterprise_magelog/context')) |
51
|
|
|
); |
52
|
|
|
} |
53
|
|
|
|
54
|
|
|
/** |
55
|
|
|
* Type checks for constructor args array. |
56
|
|
|
* |
57
|
|
|
* @param EbayEnterprise_MageLog_Helper_Data |
58
|
|
|
* @param EbayEnterprise_Address_Helper_Data |
59
|
|
|
* @param EbayEnterprise_Eb2cCore_Helper_Data |
60
|
|
|
* @param EbayEnterprise_MageLog_Helper_Context |
61
|
|
|
*/ |
62
|
|
|
protected function _checkTypes( |
63
|
|
|
EbayEnterprise_MageLog_Helper_Data $logger, |
64
|
|
|
EbayEnterprise_Address_Helper_Data $helper, |
65
|
|
|
EbayEnterprise_Eb2cCore_Helper_Data $coreHelper, |
66
|
|
|
EbayEnterprise_MageLog_Helper_Context $context |
67
|
|
|
) { |
68
|
|
|
return [$logger, $helper, $coreHelper, $context]; |
69
|
|
|
} |
70
|
|
|
|
71
|
|
|
/** |
72
|
|
|
* Return the value at field in array if it exists. Otherwise, use the |
73
|
|
|
* default value. |
74
|
|
|
* @param array $arr |
75
|
|
|
* @param string|int $field Valid array key |
76
|
|
|
* @param mixed $default |
77
|
|
|
* @return mixed |
78
|
|
|
*/ |
79
|
|
|
protected function _nullCoalesce(array $arr, $field, $default) |
80
|
|
|
{ |
81
|
|
|
return isset($arr[$field]) ? $arr[$field] : $default; |
82
|
|
|
} |
83
|
|
|
|
84
|
|
|
/** |
85
|
|
|
* Get the session object to use for storing address information. |
86
|
|
|
* Currently will use the customer session but may be swapped out later. |
87
|
|
|
* @return Mage_Core_Model_Session_Abstract |
88
|
|
|
*/ |
89
|
|
|
protected function _getSession() |
90
|
|
|
{ |
91
|
|
|
return Mage::getSingleton('customer/session'); |
92
|
|
|
} |
93
|
|
|
|
94
|
|
|
/** |
95
|
|
|
* Get a new address vaildation request model for the given address and api. |
96
|
|
|
* |
97
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
98
|
|
|
* @param IBidirectionalApi $api |
99
|
|
|
* @return EbayEnterprise_Address_Model_Validation_Request |
100
|
|
|
*/ |
101
|
|
|
protected function _getValidationRequest(Mage_Customer_Model_Address_Abstract $address, IBidirectionalApi $api) |
102
|
|
|
{ |
103
|
|
|
return Mage::getModel('ebayenterprise_address/validation_request', ['api' => $api, 'address' => $address]); |
104
|
|
|
} |
105
|
|
|
|
106
|
|
|
/** |
107
|
|
|
* Get a new address validation response model for the api. |
108
|
|
|
* |
109
|
|
|
* @param IBidirectionalApi $api |
110
|
|
|
* @return EbayEnterprise_Address_Model_Validatoin_Response |
111
|
|
|
*/ |
112
|
|
|
protected function _getValidationResponse(IBidirectionalApi $api) |
113
|
|
|
{ |
114
|
|
|
return Mage::getModel('ebayenterprise_address/validation_response', ['api' => $api]); |
115
|
|
|
} |
116
|
|
|
|
117
|
|
|
/** |
118
|
|
|
* If a selection has been made, update the address object with data |
119
|
|
|
* from the stashed address. This will include copying over the |
120
|
|
|
* has_been_validated flag, which will bypass re-validating the address. |
121
|
|
|
* |
122
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
123
|
|
|
* @return Mage_Customer_Model_Address_Abstract |
124
|
|
|
*/ |
125
|
|
|
protected function _updateAddressWithSelection(Mage_Customer_Model_Address_Abstract $address) |
126
|
|
|
{ |
127
|
|
|
$key = Mage::app() |
128
|
|
|
->getRequest() |
129
|
|
|
->getPost(EbayEnterprise_Address_Block_Suggestions::SUGGESTION_INPUT_NAME); |
130
|
|
|
$suggestionAddress = $this->getStashedAddressByKey($key); |
131
|
|
|
if ($suggestionAddress) { |
132
|
|
|
$address->addData($suggestionAddress->getData()); |
133
|
|
|
} |
134
|
|
|
return $address; |
135
|
|
|
} |
136
|
|
|
|
137
|
|
|
/** |
138
|
|
|
* Determine if the address has already been validated. |
139
|
|
|
* Based upon: |
140
|
|
|
* - The address object having a 'has_been_validated' property which is true |
141
|
|
|
* - Matches the 'validated_address' object stashed in the session |
142
|
|
|
* @param Mage_Customer_Model_Address_Abstract |
143
|
|
|
* @return bool |
144
|
|
|
*/ |
145
|
|
|
protected function _hasAddressBeenValidated(Mage_Customer_Model_Address_Abstract $address) |
146
|
|
|
{ |
147
|
|
|
// flag set on addresses that are returned from the Address Validation response |
148
|
|
|
if ($address->getHasBeenValidated()) { |
149
|
|
|
return true; |
150
|
|
|
} |
151
|
|
|
// when the address is used as a shipping address, must ensure that the validated |
152
|
|
|
// address was validated as a shipping address |
153
|
|
|
if ($this->_isAddressUsedForShipping($address)) { |
154
|
|
|
$validatedAddress = $this->getValidatedAddress(Mage_Customer_Model_Address::TYPE_SHIPPING); |
155
|
|
|
} else { |
156
|
|
|
$validatedAddress = $this->getValidatedAddress($address->getAddressType()); |
157
|
|
|
} |
158
|
|
|
// ensure - a validated address of this type exists |
159
|
|
|
// it was actually validated/validation wasn't skipped |
160
|
|
|
// and it matches the current address |
161
|
|
|
return $validatedAddress && $this->_compareAddressToValidatedAddress($address, $validatedAddress); |
162
|
|
|
} |
163
|
|
|
|
164
|
|
|
/** |
165
|
|
|
* When a checkout quote exists, get the checkout "method" being used for checkout. |
166
|
|
|
* Should be one of the Checkout type consts defined by Mage_Checkout_Model_Type_Onepage |
167
|
|
|
* @return string |
168
|
|
|
*/ |
169
|
|
|
protected function _getCheckoutMethod() |
170
|
|
|
{ |
171
|
|
|
return Mage::getSingleton('checkout/type_onepage')->getCheckoutMethod(); |
172
|
|
|
} |
173
|
|
|
|
174
|
|
|
/** |
175
|
|
|
* Determine if the address is for use in checkout, specifically, Onepage Checkout |
176
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
177
|
|
|
* @return bool |
178
|
|
|
*/ |
179
|
|
|
protected function _isCheckoutAddress(Mage_Customer_Model_Address_Abstract $address) |
180
|
|
|
{ |
181
|
|
|
return $address->hasData('quote_id'); |
182
|
|
|
} |
183
|
|
|
|
184
|
|
|
/** |
185
|
|
|
* When dealing with checkout addresses, check if the current quote is virtual. |
186
|
|
|
* @return bool |
187
|
|
|
*/ |
188
|
|
|
protected function _isVirtualOrder() |
189
|
|
|
{ |
190
|
|
|
$quote = Mage::getSingleton('checkout/session')->getQuote(); |
191
|
|
|
if ($quote) { |
192
|
|
|
return $quote->isVirtual(); |
193
|
|
|
} |
194
|
|
|
return false; |
195
|
|
|
} |
196
|
|
|
|
197
|
|
|
/** |
198
|
|
|
* Is the address a billing address. |
199
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
200
|
|
|
* @return bool |
201
|
|
|
*/ |
202
|
|
|
protected function _isBillingAddress(Mage_Customer_Model_Address_Abstract $address) |
203
|
|
|
{ |
204
|
|
|
return $address->getAddressType() === Mage_Customer_Model_Address::TYPE_BILLING; |
205
|
|
|
} |
206
|
|
|
|
207
|
|
|
/** |
208
|
|
|
* Determine if the address should be used as a shipping address. |
209
|
|
|
* For billing address used as a shipping address, this will only |
210
|
|
|
* reliably work when the address is submitted during onepage checkout |
211
|
|
|
* as the only way to determine this is via the POST data submitted with the address. |
212
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
213
|
|
|
* @return bool |
214
|
|
|
*/ |
215
|
|
|
protected function _isAddressUsedForShipping(Mage_Customer_Model_Address_Abstract $address) |
216
|
|
|
{ |
217
|
|
|
// obviously, when the address type is shipping, it's a shipping address |
218
|
|
|
if ($address->getAddressType() === Mage_Customer_Model_Address::TYPE_SHIPPING) { |
219
|
|
|
return true; |
220
|
|
|
} |
221
|
|
|
|
222
|
|
|
// when address type is not a shipping address |
223
|
|
|
// only other way it could be a shipping address is during onepage checkout |
224
|
|
|
// billing address, in which case a 'billing[use_for_shipping]' field will be |
225
|
|
|
// submitted with the address. |
226
|
|
|
$data = Mage::app()->getRequest()->getPost('billing', []); |
227
|
|
|
$useForShipping = isset($data['use_for_shipping']) && $data['use_for_shipping']; |
228
|
|
|
return $useForShipping; |
229
|
|
|
} |
230
|
|
|
|
231
|
|
|
/** |
232
|
|
|
* Determine if the address is to be used as a billing address only and |
233
|
|
|
* will not be saved in the address book. |
234
|
|
|
* Only applies to Onepage Checkout |
235
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
236
|
|
|
* @return bool |
237
|
|
|
*/ |
238
|
|
|
protected function _isAddressBillingOnly(Mage_Customer_Model_Address_Abstract $address) |
239
|
|
|
{ |
240
|
|
|
return $this->_isBillingAddress($address) && !$this->_isAddressUsedForShipping($address); |
241
|
|
|
} |
242
|
|
|
|
243
|
|
|
/** |
244
|
|
|
* Determine if the address is to be saved in the address book as part of |
245
|
|
|
* onepage checkout. |
246
|
|
|
* |
247
|
|
|
* @return bool |
248
|
|
|
*/ |
249
|
|
|
protected function _isAddressBeingSaved() |
250
|
|
|
{ |
251
|
|
|
$request = Mage::app()->getRequest(); |
252
|
|
|
// get billing post data or shipping post data or empty array |
253
|
|
|
$data = $request->getPost('billing') ?: $request->getPost('shipping', []); |
254
|
|
|
// was the "save_in_address_book" checkbox submitted |
255
|
|
|
$postFlag = isset($data['save_in_address_book']) && $data['save_in_address_book']; |
256
|
|
|
|
257
|
|
|
// during checkout, the only two "types" of checkout that would actually allow |
258
|
|
|
// saving addresses in the address book are METHOD_REGISTER and METHOD_CUSTOMER |
259
|
|
|
$checkoutMethod = $this->_getCheckoutMethod(); |
260
|
|
|
$canSaveAddressesInCheckout = $checkoutMethod === Mage_Checkout_Model_Type_Onepage::METHOD_REGISTER || |
261
|
|
|
$checkoutMethod === Mage_Checkout_Model_Type_Onepage::METHOD_CUSTOMER; |
262
|
|
|
return $postFlag && $canSaveAddressesInCheckout; |
263
|
|
|
} |
264
|
|
|
|
265
|
|
|
/** |
266
|
|
|
* Determine if the address is from the customers address book or is a new address |
267
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
268
|
|
|
* @return bool |
269
|
|
|
*/ |
270
|
|
|
protected function _isAddressFromAddressBook(Mage_Customer_Model_Address_Abstract $address) |
271
|
|
|
{ |
272
|
|
|
return $address->getId() && $address->getCustomerId() && $address->getCustomerAddressId(); |
273
|
|
|
} |
274
|
|
|
|
275
|
|
|
/** |
276
|
|
|
* Determine if an address needs to be validated |
277
|
|
|
* Some conditions, like an address being saved in the address book, |
278
|
|
|
* always require validation. |
279
|
|
|
* Others conditions, like using an address for billing address only |
280
|
|
|
* or being from the address book, indicate that validation is not required. |
281
|
|
|
* @param Mage_Customer_Model_Address_Abstract |
282
|
|
|
* @return bool |
283
|
|
|
*/ |
284
|
|
|
public function shouldValidateAddress(Mage_Customer_Model_Address_Abstract $address) |
285
|
|
|
{ |
286
|
|
View Code Duplication |
if ($this->_hasAddressBeenValidated($address)) { |
|
|
|
|
287
|
|
|
$logMessage = 'No validation - already validated'; |
288
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
289
|
|
|
return false; |
290
|
|
|
} |
291
|
|
|
if ($this->_isCheckoutAddress($address)) { |
292
|
|
View Code Duplication |
if ($this->_isAddressFromAddressBook($address)) { |
|
|
|
|
293
|
|
|
$logMessage = 'No validation - from address book'; |
294
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
295
|
|
|
return false; |
296
|
|
|
} |
297
|
|
View Code Duplication |
if ($this->_isAddressBeingSaved()) { |
|
|
|
|
298
|
|
|
$logMessage = 'Require validation - saving address in address book'; |
299
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
300
|
|
|
return true; |
301
|
|
|
} |
302
|
|
View Code Duplication |
if ($this->_isVirtualOrder()) { |
|
|
|
|
303
|
|
|
$logMessage = 'No validation - virtual order'; |
304
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
305
|
|
|
return false; |
306
|
|
|
} |
307
|
|
View Code Duplication |
if ($this->_isAddressBillingOnly($address)) { |
|
|
|
|
308
|
|
|
$logMessage = 'No validation - billing only'; |
309
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
310
|
|
|
return false; |
311
|
|
|
} |
312
|
|
View Code Duplication |
if ($this->_isMissingRequiredFields($address)) { |
|
|
|
|
313
|
|
|
$logMessage = 'No validation - missing required fields'; |
314
|
|
|
$this->_logger->debug($logMessage, $this->_context->getMetaData(__CLASS__)); |
315
|
|
|
return false; |
316
|
|
|
} |
317
|
|
|
} |
318
|
|
|
return true; |
319
|
|
|
} |
320
|
|
|
|
321
|
|
|
/** |
322
|
|
|
* Perform the web request for address validation and return the response |
323
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
324
|
|
|
* @return EbayEnterprise_Address_Model_Validation_Response|null |
|
|
|
|
325
|
|
|
*/ |
326
|
|
|
protected function _makeRequestForAddress(Mage_Customer_Model_Address_Abstract $address) |
327
|
|
|
{ |
328
|
|
|
$config = $this->_helper->getConfigModel(); |
329
|
|
|
$api = $this->_coreHelper->getSdkApi($config->apiService, $config->apiOperation); |
|
|
|
|
330
|
|
|
$logger = $this->_logger; |
331
|
|
|
$logContext = $this->_context; |
332
|
|
|
try { |
333
|
|
|
$this->_prepareApiForAddressRequest($address, $api); |
334
|
|
|
$api->send(); |
335
|
|
|
return $this->_getValidationResponse($api); |
336
|
|
|
} catch (InvalidPayload $e) { |
337
|
|
|
$logMessage = 'Invalid payload for address validate operation. See exception log for more details.'; |
338
|
|
|
$logger->warning($logMessage, $logContext->getMetaData(__CLASS__, ['exception_message' => $e->getMessage()])); |
339
|
|
|
$logger->logException($e, $logContext->getMetaData(__CLASS__, [], $e)); |
340
|
|
|
throw $e; |
341
|
|
|
} catch (NetworkError $e) { |
342
|
|
|
$logMessage = 'Caught network error sending the address validation. See exception log for more details.'; |
343
|
|
|
$logger->warning($logMessage, $logContext->getMetaData(__CLASS__, ['exception_message' => $e->getMessage()])); |
344
|
|
|
$logger->logException($e, $logContext->getMetaData(__CLASS__, [], $e)); |
345
|
|
|
// Allow network errors to be bypassed, exception is caught and not re-thrown. |
346
|
|
|
} catch (UnsupportedOperation $e) { |
347
|
|
|
$logMessage = 'The address validate operation is unsupported in the current configuration. See exception log for more details.'; |
348
|
|
|
$logger->warning($logMessage, $logContext->getMetaData(__CLASS__, ['exception_message' => $e->getMessage()])); |
349
|
|
|
$logger->logException($e, $logContext->getMetaData(__CLASS__, [], $e)); |
350
|
|
|
throw $e; |
351
|
|
|
} catch (UnsupportedHttpAction $e) { |
352
|
|
|
$logMessage = 'The address validate operation is configured with an unsupported HTTP action. See exception log for more details.'; |
353
|
|
|
$logger->warning($logMessage, $logContext->getMetaData(__CLASS__, ['exception_message' => $e->getMessage()])); |
354
|
|
|
$logger->logException($e, $logContext->getMetaData(__CLASS__, [], $e)); |
355
|
|
|
throw $e; |
356
|
|
|
} catch (Exception $e) { |
357
|
|
|
$logMessage = 'Encountered unexpected exception from address validate operation. See exception log for more details.'; |
358
|
|
|
$logger->warning($logMessage, $logContext->getMetaData(__CLASS__, ['exception_message' => $e->getMessage()])); |
359
|
|
|
$logger->logException($e, $logContext->getMetaData(__CLASS__, [], $e)); |
360
|
|
|
throw $e; |
361
|
|
|
} |
362
|
|
|
return null; |
363
|
|
|
} |
364
|
|
|
|
365
|
|
|
/** |
366
|
|
|
* Prepare a request payload for the API to validate the address. |
367
|
|
|
* |
368
|
|
|
* @param Mage_Customer_Model_Address_Abstract |
369
|
|
|
* @param IBidirectionalApi |
370
|
|
|
* @return \eBayEnterprise\RetailOrderManagement\Payload\Address\IValidationRequest |
|
|
|
|
371
|
|
|
*/ |
372
|
|
|
protected function _prepareApiForAddressRequest(Mage_Customer_Model_Address_Abstract $address, IBidirectionalApi $api) |
373
|
|
|
{ |
374
|
|
|
return $api->setRequestBody( |
375
|
|
|
$this->_getValidationRequest($address, $api)->prepareRequest()->getRequest() |
376
|
|
|
); |
377
|
|
|
} |
378
|
|
|
|
379
|
|
|
/** |
380
|
|
|
* Validate an address via the Address Validation service. |
381
|
|
|
* Calls the API and feeds the results into a response model. |
382
|
|
|
* Will also ensure that the supplied address is populated with |
383
|
|
|
* the response from the service and suggested addresses are |
384
|
|
|
* stashed in the session for later use. |
385
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
386
|
|
|
* @param null $area |
387
|
|
|
* @return string the error message generated in validation |
|
|
|
|
388
|
|
|
*/ |
389
|
|
|
public function validateAddress(Mage_Customer_Model_Address_Abstract $address, $area = null) |
390
|
|
|
{ |
391
|
|
|
$response = null; |
392
|
|
|
$errorMessage = null; |
393
|
|
|
$address = $this->_updateAddressWithSelection($address); |
394
|
|
|
$adminValidation = ( |
395
|
|
|
$area === Mage_Core_Model_App_Area::AREA_ADMINHTML |
396
|
|
|
&& !$this->_isBillingAddress($address) |
397
|
|
|
&& !$this->_hasAddressBeenValidated($address) |
398
|
|
|
); |
399
|
|
|
if ($adminValidation || $this->shouldValidateAddress($address)) { |
400
|
|
|
$this->clearSessionAddresses(); |
401
|
|
|
$response = $this->_processRequest($address, $errorMessage); |
402
|
|
|
} |
403
|
|
|
$this->_updateSession($address, $response); |
404
|
|
|
return $errorMessage; |
405
|
|
|
} |
406
|
|
|
|
407
|
|
|
/** |
408
|
|
|
* Send the request and parse the response. |
409
|
|
|
* |
410
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
411
|
|
|
* @param string $errorMessage |
412
|
|
|
* @return EbayEnterprise_Address_Model_Validation_Response|null |
|
|
|
|
413
|
|
|
*/ |
414
|
|
|
protected function _processRequest(Mage_Customer_Model_Address_Abstract $address, &$errorMessage) |
415
|
|
|
{ |
416
|
|
|
$response = $this->_makeRequestForAddress($address); |
417
|
|
|
if ($response) { |
418
|
|
|
// copy over validated address data |
419
|
|
|
if ($response->isAddressValid()) { |
420
|
|
|
$address->addData($response->getValidAddress()->getData()); |
421
|
|
|
} else { |
422
|
|
|
$address->addData($response->getOriginalAddress()->getData()); |
423
|
|
|
if ($address->getSameAsBilling()) { |
424
|
|
|
$address->setSameAsBilling(false); |
425
|
|
|
} |
426
|
|
|
$errorMessage = ''; |
427
|
|
|
if ($response->getHasSuggestions()) { |
428
|
|
|
$errorMessage = $this->_helper->__(self::SUGGESTIONS_ERROR_MESSAGE); |
429
|
|
|
} else { |
430
|
|
|
$errorMessage = $this->_helper->__(self::NO_SUGGESTIONS_ERROR_MESSAGE); |
431
|
|
|
} |
432
|
|
|
} |
433
|
|
|
} |
434
|
|
|
return $response; |
435
|
|
|
} |
436
|
|
|
|
437
|
|
|
/** |
438
|
|
|
* Compare a validated address to a potentially unvalidated address. |
439
|
|
|
* The validated address should contain only the data that gets validated by |
440
|
|
|
* the service, e.g. an address object returned by $this->_extractValidatedAddressData. |
441
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
442
|
|
|
* @param Mage_Customer_Model_Address_Abstract $validatedAddress |
443
|
|
|
* @return bool - true if they match, false if not |
444
|
|
|
*/ |
445
|
|
|
protected function _compareAddressToValidatedAddress( |
446
|
|
|
Mage_Customer_Model_Address_Abstract $address, |
447
|
|
|
Mage_Customer_Model_Address_Abstract $validatedAddress |
448
|
|
|
) { |
449
|
|
|
$validatedData = $validatedAddress->getData(); |
450
|
|
|
foreach ($validatedData as $key => $value) { |
451
|
|
|
// skip a few keys we don't care about when comparing the addresses |
452
|
|
|
if ($key === 'address_type') { |
453
|
|
|
continue; |
454
|
|
|
} |
455
|
|
|
if ((string) $address->getData($key) !== (string) $value) { |
456
|
|
|
return false; |
457
|
|
|
} |
458
|
|
|
} |
459
|
|
|
return !empty($validatedData); |
460
|
|
|
} |
461
|
|
|
|
462
|
|
|
/** |
463
|
|
|
* Extract only the data from the addres that gets validated. |
464
|
|
|
* The extracted data can be compared to the data in an existing |
465
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
466
|
|
|
* @return Mage_Customer_Model_Address_Abstract - an address object containing only the data that gets validated |
467
|
|
|
*/ |
468
|
|
|
protected function _extractValidatedAddressData(Mage_Customer_Model_Address_Abstract $address) |
469
|
|
|
{ |
470
|
|
|
$validatedAddress = Mage::getModel('customer/address')->setData([ |
471
|
|
|
'street' => $address->getData('street'), |
472
|
|
|
'city' => $address->getCity(), |
473
|
|
|
'region_id' => $address->getRegionId(), |
474
|
|
|
'country_id' => $address->getCountryId(), |
475
|
|
|
'postcode' => $address->getPostcode(), |
476
|
|
|
'address_type' => $address->getAddressType(), |
477
|
|
|
]); |
478
|
|
|
return $validatedAddress; |
479
|
|
|
} |
480
|
|
|
|
481
|
|
|
/** |
482
|
|
|
* Copy over address name data from the source to the dest address. |
483
|
|
|
* @param Mage_Customer_Model_Address_Abstract $dest |
484
|
|
|
* @param Mage_Customer_Model_Address_Abstract $source |
485
|
|
|
* @return self |
486
|
|
|
*/ |
487
|
|
|
protected function _copyAddressName( |
488
|
|
|
Mage_Customer_Model_Address_Abstract $dest, |
489
|
|
|
Mage_Customer_Model_Address_Abstract $source |
490
|
|
|
) { |
491
|
|
|
$dest->addData([ |
492
|
|
|
'prefix' => $source->getPrefix(), |
493
|
|
|
'firstname' => $source->getFirstname(), |
494
|
|
|
'middlename' => $source->getMiddlename(), |
495
|
|
|
'lastname' => $source->getLastname(), |
496
|
|
|
'suffix' => $source->getSuffix() |
497
|
|
|
]); |
498
|
|
|
return $this; |
499
|
|
|
} |
500
|
|
|
|
501
|
|
|
/** |
502
|
|
|
* Store the necessary addresses and address data in the session. |
503
|
|
|
* Addresses are stored in a EbayEnterprise_Address_Model_Suggestion_Group. |
504
|
|
|
* Addresses get merged with the submitted address to fill in any |
505
|
|
|
* gaps between what the user gives us and what the service returns (like name and phone). |
506
|
|
|
* |
507
|
|
|
* @param Mage_Customer_Model_Address_Abstract $requestAddress |
508
|
|
|
* @param EbayEnterprise_Address_Model_Validation_Response|null $response |
509
|
|
|
* @return self |
510
|
|
|
*/ |
511
|
|
|
protected function _updateSession( |
512
|
|
|
Mage_Customer_Model_Address_Abstract $requestAddress, |
513
|
|
|
EbayEnterprise_Address_Model_Validation_Response $response = null |
514
|
|
|
) { |
515
|
|
|
$addressCollection = $this->getAddressCollection(); |
516
|
|
|
|
517
|
|
|
if ($response) { |
518
|
|
|
$originalAddress = $response->getOriginalAddress(); |
519
|
|
|
$originalAddress->setStashKey('original_address'); |
520
|
|
|
$this->_copyAddressName($originalAddress, $requestAddress); |
521
|
|
|
$addressCollection->setOriginalAddress($originalAddress); |
522
|
|
|
|
523
|
|
|
$suggestions = $response->getAddressSuggestions(); |
524
|
|
|
foreach ($suggestions as $idx => $suggestion) { |
525
|
|
|
$suggestion->setStashKey('suggested_addresses/' . $idx); |
526
|
|
|
$this->_copyAddressName($suggestion, $requestAddress); |
527
|
|
|
} |
528
|
|
|
$addressCollection->setSuggestedAddresses($suggestions); |
529
|
|
|
|
530
|
|
|
$addressCollection->setResponseMessage($response); |
531
|
|
|
$addressCollection->setHasFreshSuggestions(true); |
532
|
|
|
} else { |
533
|
|
|
$addressCollection->unsOriginalAddress(); |
534
|
|
|
$addressCollection->unsSuggestedAddresses(); |
535
|
|
|
$addressCollection->unsResponseMessage(); |
536
|
|
|
$addressCollection->unsHasFreshSuggestions(); |
537
|
|
|
} |
538
|
|
|
|
539
|
|
|
$validationAddressExtract = $this->_extractValidatedAddressData($requestAddress); |
540
|
|
|
$addressCollection->addValidatedAddress($validationAddressExtract); |
541
|
|
|
// when the address is a billing address used for billing and shipping |
542
|
|
|
// add a validated address for billing and shipping |
543
|
|
|
if ($this->_isBillingAddress($requestAddress) && $this->_isAddressUsedForShipping($requestAddress) |
544
|
|
|
) { |
545
|
|
|
$addressCollection->addValidatedAddress( |
546
|
|
|
$validationAddressExtract->setAddressType(Mage_Customer_Model_Address::TYPE_SHIPPING) |
547
|
|
|
); |
548
|
|
|
} |
549
|
|
|
$this->_getSession()->setAddressValidationAddresses($addressCollection); |
550
|
|
|
|
551
|
|
|
return $this; |
552
|
|
|
} |
553
|
|
|
|
554
|
|
|
/** |
555
|
|
|
* Return a Varien_Object containing stashed data about address validation and |
556
|
|
|
* validated addresses. Most of the properties it contains are retrievable |
557
|
|
|
* from this class so it is unlikely this will need to be called publicly. |
558
|
|
|
* |
559
|
|
|
* @return EbayEnterprise_Address_Model_Suggestion_Group |
560
|
|
|
*/ |
561
|
|
|
public function getAddressCollection() |
562
|
|
|
{ |
563
|
|
|
$collection = $this->_getSession()->getData(self::SESSION_KEY); |
564
|
|
|
return ($collection instanceof EbayEnterprise_Address_Model_Suggestion_Group) |
565
|
|
|
? $collection |
566
|
|
|
: Mage::getModel('ebayenterprise_address/suggestion_group'); |
567
|
|
|
} |
568
|
|
|
|
569
|
|
|
/** |
570
|
|
|
* Get the address returned as the "original" address from the service. |
571
|
|
|
* @param bool $keepFresh - flag passed to the session's method |
572
|
|
|
* @return Mage_Customer_Model_Address |
|
|
|
|
573
|
|
|
*/ |
574
|
|
|
public function getOriginalAddress($keepFresh = false) |
575
|
|
|
{ |
576
|
|
|
return $this->getAddressCollection()->getOriginalAddress($keepFresh); |
577
|
|
|
} |
578
|
|
|
|
579
|
|
|
/** |
580
|
|
|
* Get the suggested address returned by the service |
581
|
|
|
* @param bool $keepFresh - flag passed to the session's method |
582
|
|
|
* @return Mage_Customer_Model_Address[] |
|
|
|
|
583
|
|
|
*/ |
584
|
|
|
public function getSuggestedAddresses($keepFresh = false) |
585
|
|
|
{ |
586
|
|
|
return $this->getAddressCollection()->getSuggestedAddresses($keepFresh); |
587
|
|
|
} |
588
|
|
|
|
589
|
|
|
/** |
590
|
|
|
* Get the validated_address object from the session, this will be |
591
|
|
|
* just the address data from the last address validated by the service |
592
|
|
|
* @param $type |
593
|
|
|
* @return Mage_Customer_Model_Address_Abstract |
594
|
|
|
*/ |
595
|
|
|
public function getValidatedAddress($type) |
596
|
|
|
{ |
597
|
|
|
return $this->getAddressCollection()->getValidatedAddress($type); |
598
|
|
|
} |
599
|
|
|
|
600
|
|
|
/** |
601
|
|
|
* Return the address from the session represented by the given key. |
602
|
|
|
* If no address for that key exists, returns null. |
603
|
|
|
* @param string $key |
604
|
|
|
* @return Mage_Customer_Model_Address |
605
|
|
|
*/ |
606
|
|
|
public function getStashedAddressByKey($key) |
607
|
|
|
{ |
608
|
|
|
return $this->getAddressCollection()->getData($key); |
609
|
|
|
} |
610
|
|
|
|
611
|
|
|
/** |
612
|
|
|
* Returns whether or not there are address suggestions stored in the session |
613
|
|
|
* and they should be shown to the user. |
614
|
|
|
* @return bool |
615
|
|
|
*/ |
616
|
|
|
public function hasSuggestions() |
617
|
|
|
{ |
618
|
|
|
// when getting suggestions from the session, this should not flag the |
619
|
|
|
// addresses has having been used |
620
|
|
|
$suggestions = $this->getSuggestedAddresses(true); |
621
|
|
|
return !empty($suggestions); |
622
|
|
|
} |
623
|
|
|
|
624
|
|
|
/** |
625
|
|
|
* Returns the result of validation from the response message. |
626
|
|
|
* When there is no response message in the session, consider the address valid. |
627
|
|
|
* When there is a response message in the session, it should accurately indicate |
628
|
|
|
* if the address being validated by the request is valid. |
629
|
|
|
* @return bool |
630
|
|
|
*/ |
631
|
|
|
public function isValid() |
632
|
|
|
{ |
633
|
|
|
$response = $this->getAddressCollection()->getResponseMessage(); |
634
|
|
|
return !$response || $response->isAddressValid(); |
635
|
|
|
} |
636
|
|
|
|
637
|
|
|
/** |
638
|
|
|
* Returns whether or not the last set of suggestions are "fresh" |
639
|
|
|
* e.g. whether or not they have been used on the frontend or chosen as |
640
|
|
|
* the correct suggestion. |
641
|
|
|
* @return bool |
642
|
|
|
*/ |
643
|
|
|
public function hasFreshSuggestions() |
644
|
|
|
{ |
645
|
|
|
return $this->getAddressCollection()->getHasFreshSuggestions(); |
646
|
|
|
} |
647
|
|
|
|
648
|
|
|
/** |
649
|
|
|
* Remove the collection of addresses from the session. |
650
|
|
|
* @return self |
651
|
|
|
*/ |
652
|
|
|
public function clearSessionAddresses() |
653
|
|
|
{ |
654
|
|
|
$this->_getSession()->unsetData(self::SESSION_KEY); |
655
|
|
|
return $this; |
656
|
|
|
} |
657
|
|
|
|
658
|
|
|
/** |
659
|
|
|
* return true if the address contains enough data to be submitted for verification |
660
|
|
|
* @param Mage_Customer_Model_Address_Abstract $address |
661
|
|
|
* @return bool |
662
|
|
|
*/ |
663
|
|
|
protected function _isMissingRequiredFields(Mage_Customer_Model_Address_Abstract $address) |
664
|
|
|
{ |
665
|
|
|
$methods = ['getStreet1', 'getCity', 'getCountry']; |
666
|
|
|
$hasMissingFieds = false; |
667
|
|
|
foreach ($methods as $method) { |
668
|
|
|
$hasMissingFieds = $hasMissingFieds || !$address->$method(); |
669
|
|
|
} |
670
|
|
|
return $hasMissingFieds; |
671
|
|
|
} |
672
|
|
|
} |
673
|
|
|
|
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.