Passed
Push — master ( 2b63db...3a2bd9 )
by Stefan
07:15
created

Shipping::recoverLabel()   C

Complexity

Conditions 8
Paths 22

Size

Total Lines 36
Code Lines 20

Duplication

Lines 0
Ratio 0 %

Importance

Changes 2
Bugs 0 Features 0
Metric Value
c 2
b 0
f 0
dl 0
loc 36
rs 5.3846
cc 8
eloc 20
nc 22
nop 4
1
<?php
2
3
namespace Ups;
4
5
use DOMDocument;
6
use DOMNode;
7
use Exception;
8
use InvalidArgumentException;
9
use Psr\Log\LoggerInterface;
10
use SimpleXMLElement;
11
use stdClass;
12
use Ups\Entity\Address;
13
use Ups\Entity\LabelSpecification;
14
use Ups\Entity\Package;
15
use Ups\Entity\Shipment;
16
use Ups\Entity\ShipmentRequestLabelSpecification;
17
use Ups\Entity\ShipmentRequestReceiptSpecification;
18
19
/**
20
 * Package Shipping API Wrapper
21
 * Based on UPS Developer Guide, dated: 31 Dec 2012.
22
 */
23
class Shipping extends Ups
24
{
25
    const REQ_VALIDATE = 'validate';
26
    const REQ_NONVALIDATE = 'nonvalidate';
27
28
    /**
29
     * @var string
30
     */
31
    private $shipConfirmEndpoint = '/ShipConfirm';
32
33
    /**
34
     * @var string
35
     */
36
    private $shipAcceptEndpoint = '/ShipAccept';
37
38
    /**
39
     * @var string
40
     */
41
    private $voidEndpoint = '/Void';
42
43
    /**
44
     * @var string
45
     */
46
    private $recoverLabelEndpoint = '/LabelRecovery';
47
48
    private $request;
49
50
    /**
51
     * @param string|null $accessKey UPS License Access Key
52
     * @param string|null $userId UPS User ID
53
     * @param string|null $password UPS User Password
54
     * @param bool $useIntegration Determine if we should use production or CIE URLs.
55
     * @param RequestInterface $request
56
     * @param LoggerInterface PSR3 compatible logger (optional)
57
     */
58 View Code Duplication
    public function __construct($accessKey = null, $userId = null, $password = null, $useIntegration = false, RequestInterface $request = null, LoggerInterface $logger = null)
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
59
    {
60
        if (null !== $request) {
61
            $this->setRequest($request);
62
        }
63
        parent::__construct($accessKey, $userId, $password, $useIntegration, $logger);
64
    }
65
66
    /**
67
     * Create a Shipment Confirm request (generate a digest).
68
     *
69
     * @param string $validation A UPS_Shipping::REQ_* constant (or null)
70
     * @param Shipment $shipment Shipment data container.
71
     * @param ShipmentRequestLabelSpecification|null $labelSpec LabelSpecification data. Optional
72
     * @param ShipmentRequestReceiptSpecification|null $receiptSpec ShipmentRequestReceiptSpecification data. Optional
73
     *
74
     * @throws Exception
75
     *
76
     * @return stdClass
77
     */
78
    public function confirm(
79
        $validation,
80
        Shipment $shipment,
81
        ShipmentRequestLabelSpecification $labelSpec = null,
82
        ShipmentRequestReceiptSpecification $receiptSpec = null
83
    ) {
84
        $request = $this->createConfirmRequest($validation, $shipment, $labelSpec, $receiptSpec);
85
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->shipConfirmEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
86
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
87
88
        if (null === $response) {
89
            throw new Exception('Failure (0): Unknown error', 0);
90
        }
91
92
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
93
            throw new Exception(
94
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
95
                (int)$response->Response->Error->ErrorCode
96
            );
97
        } else {
98
            return $this->formatResponse($response);
99
        }
100
    }
101
102
    /**
103
     * Creates a ShipConfirm request.
104
     *
105
     * @param string $validation
106
     * @param Shipment $shipment
107
     * @param ShipmentRequestLabelSpecification|null $labelSpec
108
     * @param ShipmentRequestReceiptSpecification|null $receiptSpec
109
     *
110
     * @return string
111
     */
112
    private function createConfirmRequest(
113
        $validation,
114
        Shipment $shipment,
115
        ShipmentRequestLabelSpecification $labelSpec = null,
116
        ShipmentRequestReceiptSpecification $receiptSpec = null
117
    ) {
118
        $xml = new DOMDocument();
119
        $xml->formatOutput = true;
120
121
        // Page 45
122
        $container = $xml->appendChild($xml->createElement('ShipmentConfirmRequest'));
123
124
        // Page 45
125
        $request = $container->appendChild($xml->createElement('Request'));
126
127
        $node = $xml->importNode($this->createTransactionNode(), true);
128
        $request->appendChild($node);
129
130
        $request->appendChild($xml->createElement('RequestAction', 'ShipConfirm'));
131
        $request->appendChild($xml->createElement('RequestOption', $validation ?: 'nonvalidate'));
132
133
        // Page 47
134
        $shipmentNode = $container->appendChild($xml->createElement('Shipment'));
135
136
        if ($shipment->getDescription()) {
137
            $shipmentNode->appendChild($xml->createElement('Description', $shipment->getDescription()));
138
        }
139
140
        $returnService = $shipment->getReturnService();
141
        if (isset($returnService)) {
142
            $node = $shipmentNode->appendChild($xml->createElement('ReturnService'));
143
144
            $node->appendChild($xml->createElement('Code', $returnService->getCode()));
145
        }
146
147
        if ($shipment->getDocumentsOnly()) {
148
            $shipmentNode->appendChild($xml->createElement('DocumentsOnly'));
149
        }
150
151
        $shipperNode = $shipmentNode->appendChild($xml->createElement('Shipper'));
152
153
        $shipperNode->appendChild($xml->createElement('Name', $shipment->getShipper()->getName()));
154
155
        if ($shipment->getShipper()->getAttentionName()) {
156
            $shipperNode->appendChild($xml->createElement('AttentionName', $shipment->getShipper()->getAttentionName()));
157
        }
158
159
        if ($shipment->getShipper()->getCompanyName()) {
160
            $shipperNode->appendChild($xml->createElement('CompanyDisplayableName', $shipment->getShipper()->getCompanyName()));
161
        }
162
163
        $shipperNode->appendChild($xml->createElement('ShipperNumber', $shipment->getShipper()->getShipperNumber()));
164
165
        if ($shipment->getShipper()->getTaxIdentificationNumber()) {
166
            $shipperNode->appendChild($xml->createElement('TaxIdentificationNumber', $shipment->getShipper()->getTaxIdentificationNumber()));
167
        }
168
169
        if ($shipment->getShipper()->getPhoneNumber()) {
170
            $shipperNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipper()->getPhoneNumber()));
171
        }
172
173
        if ($shipment->getShipper()->getFaxNumber()) {
174
            $shipperNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipper()->getFaxNumber()));
175
        }
176
177
        if ($shipment->getShipper()->getEMailAddress()) {
178
            $shipperNode->appendChild($xml->createElement('EMailAddress', $shipment->getShipper()->getEMailAddress()));
179
        }
180
181
        $shipperNode->appendChild($shipment->getShipper()->getAddress()->toNode($xml));
182
183
        $shipToNode = $shipmentNode->appendChild($xml->createElement('ShipTo'));
184
185
        $shipToNode->appendChild($xml->createElement('CompanyName', $shipment->getShipTo()->getCompanyName()));
186
187
        if ($shipment->getShipTo()->getAttentionName()) {
188
            $shipToNode->appendChild($xml->createElement('AttentionName', $shipment->getShipTo()->getAttentionName()));
189
        }
190
191
        if ($shipment->getShipTo()->getPhoneNumber()) {
192
            $shipToNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipTo()->getPhoneNumber()));
193
        }
194
195
        if ($shipment->getShipTo()->getFaxNumber()) {
196
            $shipToNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipTo()->getFaxNumber()));
197
        }
198
199
        if ($shipment->getShipTo()->getEMailAddress()) {
200
            $shipToNode->appendChild($xml->createElement('EMailAddress', $shipment->getShipTo()->getEMailAddress()));
201
        }
202
203
        $addressNode = $shipment->getShipTo()->getAddress()->toNode($xml);
204
205
        if ($shipment->getShipTo()->getLocationID()) {
206
            $addressNode->appendChild($xml->createElement('LocationID', strtoupper($shipment->getShipTo()->getLocationID())));
207
        }
208
209
        $shipToNode->appendChild($addressNode);
210
211
        if ($shipment->getShipFrom()) {
212
            $shipFromNode = $shipmentNode->appendChild($xml->createElement('ShipFrom'));
213
214
            $shipFromNode->appendChild($xml->createElement('CompanyName', $shipment->getShipFrom()->getCompanyName()));
215
216
            if ($shipment->getShipFrom()->getAttentionName()) {
217
                $shipFromNode->appendChild($xml->createElement('AttentionName', $shipment->getShipFrom()->getAttentionName()));
218
            }
219
220
            if ($shipment->getShipFrom()->getPhoneNumber()) {
221
                $shipFromNode->appendChild($xml->createElement('PhoneNumber', $shipment->getShipFrom()->getPhoneNumber()));
222
            }
223
224
            if ($shipment->getShipFrom()->getFaxNumber()) {
225
                $shipFromNode->appendChild($xml->createElement('FaxNumber', $shipment->getShipFrom()->getFaxNumber()));
226
            }
227
228
            $shipFromNode->appendChild($shipment->getShipFrom()->getAddress()->toNode($xml));
229
        }
230
231
        if ($shipment->getSoldTo()) {
232
            $soldToNode = $shipmentNode->appendChild($xml->createElement('SoldTo'));
233
234
            if ($shipment->getSoldTo()->getOption()) {
235
                $soldToNode->appendChild($xml->createElement('Option', $shipment->getSoldTo()->getOption()));
236
            }
237
238
            $soldToNode->appendChild($xml->createElement('CompanyName', $shipment->getSoldTo()->getCompanyName()));
239
240
            if ($shipment->getSoldTo()->getAttentionName()) {
241
                $soldToNode->appendChild($xml->createElement('AttentionName', $shipment->getSoldTo()->getAttentionName()));
242
            }
243
244
            if ($shipment->getSoldTo()->getPhoneNumber()) {
245
                $soldToNode->appendChild($xml->createElement('PhoneNumber', $shipment->getSoldTo()->getPhoneNumber()));
246
            }
247
248
            if ($shipment->getSoldTo()->getFaxNumber()) {
249
                $soldToNode->appendChild($xml->createElement('FaxNumber', $shipment->getSoldTo()->getFaxNumber()));
250
            }
251
252
            if ($shipment->getSoldTo()->getAddress()) {
253
                $soldToNode->appendChild($shipment->getSoldTo()->getAddress()->toNode($xml));
254
            }
255
        }
256
257
        $alternate = $shipment->getAlternateDeliveryAddress();
258
        if (isset($alternate)) {
259
            $shipmentNode->appendChild($alternate->toNode($xml));
260
        }
261
262
        if ($shipment->getPaymentInformation()) {
263
            $paymentNode = $shipmentNode->appendChild($xml->createElement('PaymentInformation'));
264
265
            if ($shipment->getPaymentInformation()->getPrepaid()) {
266
                $node = $paymentNode->appendChild($xml->createElement('Prepaid'));
267
                $node = $node->appendChild($xml->createElement('BillShipper'));
268
269
                $billShipper = $shipment->getPaymentInformation()->getPrepaid()->getBillShipper();
270
                if (isset($billShipper) && $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getAccountNumber()) {
271
                    $node->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getAccountNumber()));
272
                } elseif (isset($billShipper) && $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()) {
273
                    $ccNode = $node->appendChild($xml->createElement('CreditCard'));
274
                    $ccNode->appendChild($xml->createElement('Type', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getType()));
275
                    $ccNode->appendChild($xml->createElement('Number', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getNumber()));
276
                    $ccNode->appendChild($xml->createElement('ExpirationDate', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getExpirationDate()));
277
278
                    if ($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getSecurityCode()) {
279
                        $ccNode->appendChild($xml->createElement('SecurityCode', $shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getSecurityCode()));
280
                    }
281
282
                    if ($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getAddress()) {
283
                        $ccNode->appendChild($shipment->getPaymentInformation()->getPrepaid()->getBillShipper()->getCreditCard()->getAddress()->toNode($xml));
284
                    }
285
                }
286
            } elseif ($shipment->getPaymentInformation()->getBillThirdParty()) {
287
                $node = $paymentNode->appendChild($xml->createElement('BillThirdParty'));
288
                $btpNode = $node->appendChild($xml->createElement('BillThirdPartyShipper'));
289
                $btpNode->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getBillThirdParty()->getAccountNumber()));
290
291
                $tpNode = $btpNode->appendChild($xml->createElement('ThirdParty'));
292
                $addressNode = $tpNode->appendChild($xml->createElement('Address'));
293
294
                $thirdPartAddress = $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress();
295
                if (isset($thirdPartAddress) && $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getPostalCode()) {
296
                    $addressNode->appendChild($xml->createElement('PostalCode', $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getPostalCode()));
297
                }
298
299
                $addressNode->appendChild($xml->createElement('CountryCode', $shipment->getPaymentInformation()->getBillThirdParty()->getThirdPartyAddress()->getCountryCode()));
300
            } elseif ($shipment->getPaymentInformation()->getFreightCollect()) {
301
                $node = $paymentNode->appendChild($xml->createElement('FreightCollect'));
302
                $brNode = $node->appendChild($xml->createElement('BillReceiver'));
303
                $brNode->appendChild($xml->createElement('AccountNumber', $shipment->getPaymentInformation()->getFreightCollect()->getAccountNumber()));
304
305
                if ($shipment->getPaymentInformation()->getFreightCollect()->getBillReceiverAddress()) {
306
                    $addressNode = $brNode->appendChild($xml->createElement('Address'));
307
                    $addressNode->appendChild($xml->createElement('PostalCode', $shipment->getPaymentInformation()->getFreightCollect()->getBillReceiverAddress()->getPostalCode()));
308
                }
309
            } elseif ($shipment->getPaymentInformation()->getConsigneeBilled()) {
310
                $paymentNode->appendChild($xml->createElement('ConsigneeBilled'));
311
            }
312
//         TODO: create ItemizedPaymentInformation class and required subclasses for node processing
313
//        } elseif ($shipment->getItemizedPaymentInformation()) {
314
//            $paymentNode = $shipmentNode->appendChild($xml->createElement('ItemizedPaymentInformation'));
315
        }
316
317
        if ($shipment->getGoodsNotInFreeCirculationIndicator()) {
318
            $shipmentNode->appendChild($xml->createElement('GoodsNotInFreeCirculationIndicator'));
319
        }
320
321
        if ($shipment->getMovementReferenceNumber()) {
322
            $shipmentNode->appendChild($xml->createElement('MovementReferenceNumber', $shipment->getMovementReferenceNumber()));
323
        }
324
325
        $serviceNode = $shipmentNode->appendChild($xml->createElement('Service'));
326
        $serviceNode->appendChild($xml->createElement('Code', $shipment->getService()->getCode()));
327
328
        if ($shipment->getService()->getDescription()) {
329
            $serviceNode->appendChild($xml->createElement('Description', $shipment->getService()->getDescription()));
330
        }
331
332
        if ($shipment->getInvoiceLineTotal()) {
333
            $shipmentNode->appendChild($shipment->getInvoiceLineTotal()->toNode($xml));
334
        }
335
336
        if ($shipment->getNumOfPiecesInShipment()) {
337
            $shipmentNode->appendChild($xml->createElement('NumOfPiecesInShipment', $shipment->getNumOfPiecesInShipment()));
338
        }
339
340
        if ($shipment->getRateInformation()) {
341
            $node = $shipmentNode->appendChild($xml->createElement('RateInformation'));
342
            $node->appendChild($xml->createElement('NegotiatedRatesIndicator'));
343
        }
344
345
        foreach ($shipment->getPackages() as $package) {
346
            $shipmentNode->appendChild($xml->importNode($package->toNode($xml), true));
347
        }
348
349
        $shipmentServiceOptions = $shipment->getShipmentServiceOptions();
350
        if (isset($shipmentServiceOptions)) {
351
            $shipmentNode->appendChild($shipmentServiceOptions->toNode($xml));
352
        }
353
354
        $referenceNumber = $shipment->getReferenceNumber();
355
        if (isset($referenceNumber)) {
356
            $shipmentNode->appendChild($referenceNumber->toNode($xml));
357
        }
358
        
359
        $referenceNumber2 = $shipment->getReferenceNumber2();
360
        if (isset($referenceNumber2)) {
361
            $shipmentNode->appendChild($referenceNumber2->toNode($xml));
362
        }
363
364
        if ($labelSpec) {
365
            $container->appendChild($xml->importNode($this->compileLabelSpecificationNode($labelSpec), true));
366
        }
367
368
        $shipmentIndicationType = $shipment->getShipmentIndicationType();
369
        if (isset($shipmentIndicationType)) {
370
            $shipmentNode->appendChild($shipmentIndicationType->toNode($xml));
371
        }
372
373
        if ($receiptSpec) {
374
            $container->appendChild($xml->importNode($this->compileReceiptSpecificationNode($receiptSpec), true));
375
        }
376
377
        return $xml->saveXML();
378
    }
379
380
    /**
381
     * Create a Shipment Accept request (generate a shipping label).
382
     *
383
     * @param string $shipmentDigest The UPS Shipment Digest received from a ShipConfirm request.
384
     *
385
     * @throws Exception
386
     *
387
     * @return stdClass
388
     */
389
    public function accept($shipmentDigest)
390
    {
391
        $request = $this->createAcceptRequest($shipmentDigest);
392
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->shipAcceptEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
393
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
394
395
        if (null === $response) {
396
            throw new Exception('Failure (0): Unknown error', 0);
397
        }
398
399
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
400
            throw new Exception(
401
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
402
                (int)$response->Response->Error->ErrorCode
403
            );
404
        } else {
405
            return $this->formatResponse($response->ShipmentResults);
406
        }
407
    }
408
409
    /**
410
     * Creates a ShipAccept request.
411
     *
412
     * @param string $shipmentDigest
413
     *
414
     * @return string
415
     */
416
    private function createAcceptRequest($shipmentDigest)
417
    {
418
        $xml = new DOMDocument();
419
        $xml->formatOutput = true;
420
421
        $container = $xml->appendChild($xml->createElement('ShipmentAcceptRequest'));
422
        $request = $container->appendChild($xml->createElement('Request'));
423
424
        $node = $xml->importNode($this->createTransactionNode(), true);
425
        $request->appendChild($node);
426
427
        $request->appendChild($xml->createElement('RequestAction', 'ShipAccept'));
428
        $container->appendChild($xml->createElement('ShipmentDigest', $shipmentDigest));
429
430
        return $xml->saveXML();
431
    }
432
433
    /**
434
     * Void a shipping label / request.
435
     *
436
     * @param string|array $shipmentData Either the UPS Shipment Identification Number or an array of
437
     *                                   expanded shipment data [shipmentId:, trackingNumbers:[...]]
438
     *
439
     * @throws Exception
440
     *
441
     * @return stdClass
442
     */
443
    public function void($shipmentData)
444
    {
445
        if (is_array($shipmentData) && !isset($shipmentData['shipmentId'])) {
446
            throw new InvalidArgumentException('$shipmentData parameter is required to contain a key `shipmentId`.');
447
        }
448
449
        $request = $this->createVoidRequest($shipmentData);
450
        $this->response = $this->getRequest()->request($this->createAccess(), $request, $this->compileEndpointUrl($this->voidEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
451
        $response = $this->response->getResponse();
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
452
453
        if ($response->Response->ResponseStatusCode == 0) {
454
            throw new Exception(
455
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
456
                (int)$response->Response->Error->ErrorCode
457
            );
458
        } else {
459
            unset($response->Response);
460
461
            return $this->formatResponse($response);
462
        }
463
    }
464
465
    /**
466
     * Creates a void shipment request.
467
     *
468
     * @param string|array $shipmentData
469
     *
470
     * @return string
471
     */
472
    private function createVoidRequest($shipmentData)
473
    {
474
        $xml = new DOMDocument();
475
        $xml->formatOutput = true;
476
477
        $container = $xml->appendChild($xml->createElement('VoidShipmentRequest'));
478
        $request = $container->appendChild($xml->createElement('Request'));
479
480
        $node = $xml->importNode($this->createTransactionNode(), true);
481
        $request->appendChild($node);
482
483
        $request->appendChild($xml->createElement('RequestAction', '1'));
484
485
        if (is_string($shipmentData)) {
486
            $container->appendChild($xml->createElement('ShipmentIdentificationNumber', strtoupper($shipmentData)));
487
        } else {
488
            $expanded = $container->appendChild($xml->createElement('ExpandedVoidShipment'));
489
            $expanded->appendChild($xml->createElement('ShipmentIdentificationNumber', strtoupper($shipmentData['shipmentId'])));
490
491
            if (array_key_exists('trackingNumbers', $shipmentData)) {
492
                foreach ($shipmentData['trackingNumbers'] as $tn) {
493
                    $expanded->appendChild($xml->createElement('TrackingNumber', strtoupper($tn)));
494
                }
495
            }
496
        }
497
498
        return $xml->saveXML();
499
    }
500
501
    /**
502
     * Recover a shipping label.
503
     *
504
     * @param string|array $trackingData Either the tracking number or a map of ReferenceNumber data
505
     *                                         [value:, shipperNumber:]
506
     * @param array|null $labelSpecification Map of label specification data for this request. Optional.
507
     *                                         [userAgent:, imageFormat: 'HTML|PDF']
508
     * @param array|null $labelDelivery All elements are optional. [link:]
509
     * @param array|null $translate Map of translation data. Optional. [language:, dialect:]
510
     *
511
     * @throws Exception|InvalidArgumentException
512
     *
513
     * @return stdClass
514
     */
515
    public function recoverLabel($trackingData, $labelSpecification = null, $labelDelivery = null, $translate = null)
516
    {
517
        if (is_array($trackingData)) {
518
            if (!isset($trackingData['value'])) {
519
                throw new InvalidArgumentException('$trackingData parameter is required to contain `value`.');
520
            }
521
522
            if (!isset($trackingData['shipperNumber'])) {
523
                throw new InvalidArgumentException('$trackingData parameter is required to contain `shipperNumber`.');
524
            }
525
        }
526
527
        if (!empty($translate)) {
528
            if (!isset($translateOpts['language'])) {
0 ignored issues
show
Bug introduced by
The variable $translateOpts seems only to be defined at a later point. As such the call to isset() seems to always evaluate to false.

This check marks calls to isset(...) or empty(...) that are found before the variable itself is defined. These will always have the same result.

This is likely the result of code being shifted around. Consider removing these calls.

Loading history...
529
                $translateOpts['language'] = 'eng';
0 ignored issues
show
Coding Style Comprehensibility introduced by
$translateOpts was never initialized. Although not strictly required by PHP, it is generally a good practice to add $translateOpts = array(); before regardless.

Adding an explicit array definition is generally preferable to implicit array definition as it guarantees a stable state of the code.

Let’s take a look at an example:

foreach ($collection as $item) {
    $myArray['foo'] = $item->getFoo();

    if ($item->hasBar()) {
        $myArray['bar'] = $item->getBar();
    }

    // do something with $myArray
}

As you can see in this example, the array $myArray is initialized the first time when the foreach loop is entered. You can also see that the value of the bar key is only written conditionally; thus, its value might result from a previous iteration.

This might or might not be intended. To make your intention clear, your code more readible and to avoid accidental bugs, we recommend to add an explicit initialization $myArray = array() either outside or inside the foreach loop.

Loading history...
530
            }
531
532
            if (!isset($translateOpts['dialect'])) {
533
                $translateOpts['dialect'] = 'US';
534
            }
535
        }
536
537
        $request = $this->createRecoverLabelRequest($trackingData, $labelSpecification, $labelDelivery, $translate);
538
        $response = $this->request($this->createAccess(), $request, $this->compileEndpointUrl($this->recoverLabelEndpoint));
0 ignored issues
show
Deprecated Code introduced by
The method Ups\Ups::request() has been deprecated with message: Untestable

This method has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the method will be removed from the class and what other method or class to use instead.

Loading history...
539
540
        if ($response->Response->ResponseStatusCode == 0) {
541
            throw new Exception(
542
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
543
                (int)$response->Response->Error->ErrorCode
544
            );
545
        } else {
546
            unset($response->Response);
547
548
            return $this->formatResponse($response);
549
        }
550
    }
551
552
    /**
553
     * Creates a label recovery request.
554
     *
555
     * @param string|array $trackingData
556
     * @param array|null $labelSpecificationOpts
557
     * @param array|null $labelDeliveryOpts
558
     * @param array|null $translateOpts
559
     *
560
     * @return string
561
     */
562
    private function createRecoverLabelRequest($trackingData, $labelSpecificationOpts = null, $labelDeliveryOpts = null, $translateOpts = null)
0 ignored issues
show
Unused Code introduced by
The parameter $trackingData is not used and could be removed.

This check looks from parameters that have been defined for a function or method, but which are not used in the method body.

Loading history...
563
    {
564
        $xml = new DOMDocument();
565
        $xml->formatOutput = true;
566
567
        $container = $xml->appendChild($xml->createElement('LabelRecoveryRequest'));
568
        $request = $container->appendChild($xml->createElement('Request'));
569
570
        $node = $xml->importNode($this->createTransactionNode(), true);
571
        $request->appendChild($node);
572
573
        $request->appendChild($xml->createElement('RequestAction', 'LabelRecovery'));
574
575
        if (!empty($labelSpecificationOpts)) {
576
            $labelSpec = $request->appendChild($xml->createElement('LabelSpecification'));
577
578
            if (isset($labelSpecificationOpts['userAgent'])) {
579
                $labelSpec->appendChild($xml->createElement('HTTPUserAgent', $labelSpecificationOpts['userAgent']));
580
            }
581
582
            if (isset($labelSpecificationOpts['imageFormat'])) {
583
                $format = $labelSpec->appendChild($xml->createElement('LabelImageFormat'));
584
                $format->appendChild($xml->createElement('Code', $labelSpecificationOpts['imageFormat']));
585
            }
586
        }
587
588
        if (!empty($labelDeliveryOpts)) {
589
            $labelDelivery = $request->appendChild($xml->createElement('LabelDelivery'));
590
            $labelDelivery->appendChild($xml->createElement('LabelLinkIndicator', $labelDeliveryOpts['link']));
591
        }
592
593
        if (!empty($translateOpts)) {
594
            $translate = $request->appendChild($xml->createElement('Translate'));
595
            $translate->appendChild($xml->createElement('LanguageCode', $translateOpts['language']));
596
            $translate->appendChild($xml->createElement('DialectCode', $translateOpts['dialect']));
597
            $translate->appendChild($xml->createElement('Code', '01'));
598
        }
599
600
        return $xml->saveXML();
601
    }
602
603
    /**
604
     * Format the response.
605
     *
606
     * @param SimpleXMLElement $response
607
     *
608
     * @return stdClass
609
     */
610
    private function formatResponse(SimpleXMLElement $response)
611
    {
612
        return $this->convertXmlObject($response);
613
    }
614
615
    /**
616
     * @return RequestInterface
617
     */
618 View Code Duplication
    public function getRequest()
0 ignored issues
show
Duplication introduced by
This method seems to be duplicated in your project.

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.

Loading history...
619
    {
620
        if (null === $this->request) {
621
            $this->request = new Request($this->logger);
622
        }
623
624
        return $this->request;
625
    }
626
627
    /**
628
     * @param RequestInterface $request
629
     *
630
     * @return $this
631
     */
632
    public function setRequest(RequestInterface $request)
633
    {
634
        $this->request = $request;
635
636
        return $this;
637
    }
638
639
    /**
640
     * @return ResponseInterface
641
     */
642
    public function getResponse()
643
    {
644
        return $this->response;
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
Bug Compatibility introduced by
The expression $this->response; of type Ups\ResponseInterface|SimpleXMLElement adds the type SimpleXMLElement to the return on line 644 which is incompatible with the return type documented by Ups\Shipping::getResponse of type Ups\ResponseInterface.
Loading history...
645
    }
646
647
    /**
648
     * @param ResponseInterface $response
649
     *
650
     * @return $this
651
     */
652
    public function setResponse(ResponseInterface $response)
653
    {
654
        $this->response = $response;
0 ignored issues
show
Deprecated Code introduced by
The property Ups\Ups::$response has been deprecated.

This property has been deprecated. The supplier of the class has supplied an explanatory message.

The explanatory message should give you some clue as to whether and when the property will be removed from the class and what other property to use instead.

Loading history...
655
656
        return $this;
657
    }
658
659
    /**
660
     * @param ShipmentRequestReceiptSpecification $receiptSpec
661
     * @return DOMNode
662
     */
663
    private function compileReceiptSpecificationNode(ShipmentRequestReceiptSpecification $receiptSpec)
664
    {
665
        $xml = new DOMDocument();
666
        $xml->formatOutput = true;
667
668
        $receiptSpecNode = $xml->appendChild($xml->createElement('ReceiptSpecification'));
669
670
        $imageFormatNode = $receiptSpecNode->appendChild($xml->createElement('ImageFormat'));
671
        $imageFormatNode->appendChild($xml->createElement('Code', $receiptSpec->getImageFormatCode()));
672
673
        if ($receiptSpec->getImageFormatDescription()) {
674
            $imageFormatNode->appendChild($xml->createElement('Description', $receiptSpec->getImageFormatDescription()));
675
        }
676
677
        return $receiptSpecNode->cloneNode(true);
678
    }
679
680
    /**
681
     * @param ShipmentRequestLabelSpecification $labelSpec
682
     * @return DOMNode
683
     */
684
    private function compileLabelSpecificationNode(ShipmentRequestLabelSpecification $labelSpec)
685
    {
686
        $xml = new DOMDocument();
687
        $xml->formatOutput = true;
688
689
        $labelSpecNode = $xml->appendChild($xml->createElement('LabelSpecification'));
690
691
        $printMethodNode = $labelSpecNode->appendChild($xml->createElement('LabelPrintMethod'));
692
        $printMethodNode->appendChild($xml->createElement('Code', $labelSpec->getPrintMethodCode()));
693
694
        if ($labelSpec->getPrintMethodDescription()) {
695
            $printMethodNode->appendChild($xml->createElement('Description', $labelSpec->getPrintMethodDescription()));
696
        }
697
698
        if ($labelSpec->getHttpUserAgent()) {
699
            $labelSpecNode->appendChild($xml->createElement('HTTPUserAgent', $labelSpec->getHttpUserAgent()));
700
        }
701
702
        //Label print method is required only for GIF label formats
703
        if ($labelSpec->getPrintMethodCode() == ShipmentRequestLabelSpecification::IMG_FORMAT_CODE_GIF) {
704
            $imageFormatNode = $labelSpecNode->appendChild($xml->createElement('LabelImageFormat'));
705
            $imageFormatNode->appendChild($xml->createElement('Code', $labelSpec->getImageFormatCode()));
706
707
            if ($labelSpec->getImageFormatDescription()) {
708
                $imageFormatNode->appendChild($xml->createElement('Description', $labelSpec->getImageFormatDescription()));
709
            }
710
        } else {
711
            //Label stock size is required only for non-GIF label formats
712
            $stockSizeNode = $labelSpecNode->appendChild($xml->createElement('LabelStockSize'));
713
714
            $stockSizeNode->appendChild($xml->createElement('Height', $labelSpec->getStockSizeHeight()));
715
            $stockSizeNode->appendChild($xml->createElement('Width', $labelSpec->getStockSizeWidth()));
716
        }
717
718
        if ($labelSpec->getInstructionCode()) {
719
            $instructionNode = $labelSpecNode->appendChild($xml->createElement('Instruction'));
720
            $instructionNode->appendChild($xml->createElement('Code', $labelSpec->getInstructionCode()));
721
722
            if ($labelSpec->getInstructionDescription()) {
723
                $instructionNode->appendChild($xml->createElement('Description', $labelSpec->getInstructionDescription()));
724
            }
725
        }
726
727
        return $labelSpecNode->cloneNode(true);
728
    }
729
}
730