Passed
Pull Request — master (#261)
by
unknown
02:10
created

Tracking::setEndDate()   A

Complexity

Conditions 1
Paths 1

Size

Total Lines 4

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 0
CRAP Score 2

Importance

Changes 0
Metric Value
dl 0
loc 4
ccs 0
cts 3
cp 0
rs 10
c 0
b 0
f 0
cc 1
nc 1
nop 1
crap 2
1
<?php
2
3
namespace Ups;
4
5
use DOMDocument;
6
use Exception;
7
use Psr\Log\LoggerInterface;
8
use SimpleXMLElement;
9
use stdClass;
10
use DateTime;
11
12
/**
13
 * Tracking API Wrapper.
14
 */
15
class Tracking extends Ups
16
{
17
    const ENDPOINT = '/Track';
18
19
    /**
20
     * @var RequestInterface
21
     */
22
    private $request;
23
24
    /**
25
     *
26
     * Workaround flag to handle Multiple shipment nodes in tracking response
27
     * See GitHub Issue #117
28
     *
29
     * @todo: fix in next major release
30
     *
31
     * @var boolean
32
     */
33
    protected $allowMultipleShipments = false;
34
35
    /**
36
     * @todo: make private
37
     *
38
     * @var ResponseInterface
39
     */
40
    public $response;
41
42
    /**
43
     * @var string
44
     */
45
    private $trackingNumber;
46
47
    /**
48
     * @var string
49
     */
50
    private $referenceNumber;
51
52
    /**
53
     * @var string
54
     */
55
    private $requestOption;
56
57
    /**
58
     * @var string
59
     */
60
    private $shipperNumber;
61
62
    /**
63
     * @var \DateTime
64
     */
65
    private $beginDate;
66
67
    /**
68
     * @var \DateTime
69
     */
70
    private $endDate;
71
72
    /**
73
     * @param string|null $accessKey UPS License Access Key
74
     * @param string|null $userId UPS User ID
75
     * @param string|null $password UPS User Password
76
     * @param bool $useIntegration Determine if we should use production or CIE URLs.
77
     * @param RequestInterface|null $request
78
     * @param LoggerInterface|null $logger PSR3 compatible logger (optional)
79
     */
80 6 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...
81
    {
82 6
        if (null !== $request) {
83
            $this->setRequest($request);
84
        }
85 6
        parent::__construct($accessKey, $userId, $password, $useIntegration, $logger);
86 6
    }
87
88
    /**
89
     * Get package tracking information.
90
     *
91
     * @param string $trackingNumber The package's tracking number.
92
     * @param string $requestOption Optional processing. For Mail Innovations the only valid options are Last Activity and All activity.
93
     *
94
     * @throws Exception
95
     *
96
     * @return stdClass
97
     */
98 5
    public function track($trackingNumber, $requestOption = 'activity')
99
    {
100 5
        $this->trackingNumber = $trackingNumber;
101 5
        $this->requestOption = $requestOption;
102
103 5
        return $this->getFormattedResponse();
104
    }
105
106
    /**
107
     * Get package tracking information.
108
     *
109
     * @param string $referenceNumber Reference numbers can be a purchase order number, job number, etc. Reference number can be added when creating a shipment.
110
     * @param string $requestOption
111
     *
112
     * @throws Exception
113
     *
114
     * @return stdClass
115
     */
116 1
    public function trackByReference($referenceNumber, $requestOption = 'activity')
117
    {
118 1
        $this->referenceNumber = $referenceNumber;
119 1
        $this->requestOption = $requestOption;
120
121 1
        return $this->getFormattedResponse();
122
    }
123
124
    /**
125
     * Set shipper number
126
     *
127
     * @param string $shipperNumber
128
     *
129
     */
130
    public function setShipperNumber($shipperNumber)
131
    {
132
        $this->shipperNumber = $shipperNumber;
133
    }
134
135
    /**
136
     * Set begin date
137
     *
138
     * @param DateTime $beginDate
139
     *
140
     */
141
    public function setBeginDate(DateTime $beginDate)
142
    {
143
        $this->beginDate = $beginDate;
144
    }
145
146
    /**
147
     * Set end date
148
     *
149
     * @param DateTime $endDate
150
     *
151
     */
152
    public function setEndDate(DateTime $endDate)
153
    {
154
        $this->endDate = $endDate;
155
    }
156
157
    /**
158
     * @return stdClass
159
     * @throws Exception
160
     */
161 6 View Code Duplication
    private function getFormattedResponse()
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...
162
    {
163 6
        $this->response = $this->getRequest()->request(
164 6
            $this->createAccess(),
165 6
            $this->createRequest(),
166 6
            $this->compileEndpointUrl(self::ENDPOINT)
167 6
        );
168 6
        $response = $this->response->getResponse();
169
170 6
        if (null === $response) {
171 3
            throw new Exception('Failure (0): Unknown error', 0);
172
        }
173
174 3
        if ($response instanceof SimpleXMLElement && $response->Response->ResponseStatusCode == 0) {
175
            throw new Exception(
176
                "Failure ({$response->Response->Error->ErrorSeverity}): {$response->Response->Error->ErrorDescription}",
177
                (int)$response->Response->Error->ErrorCode
178
            );
179
        }
180
181 3
        return $this->formatResponse($response);
182
    }
183
184
    /**
185
     * Check if tracking number is for mail innovations.
186
     *
187
     * @return bool
188
     */
189 6
    private function isMailInnovations()
190
    {
191
        $patterns = [
192
193
            // UPS Mail Innovations tracking numbers
194 6
            '/^MI\d{6}\d{1,22}$/',// MI 000000 00000000+
195
196
            // USPS - Certified Mail
197 6
            '/^94071\d{17}$/',    // 9407 1000 0000 0000 0000 00
198 6
            '/^7\d{19}$/',        // 7000 0000 0000 0000 0000
199
200
            // USPS - Collect on Delivery
201 6
            '/^93033\d{17}$/',    // 9303 3000 0000 0000 0000 00
202 6
            '/^M\d{9}$/',         // M000 0000 00
203
204
            // USPS - Global Express Guaranteed
205 6
            '/^82\d{10}$/',       // 82 000 000 00
206
207
            // USPS - Priority Mail Express International
208 6
            '/^EC\d{9}US$/',      // EC 000 000 000 US
209
210
            // USPS Innovations Expedited
211 6
            '/^927\d{23}$/',      // 9270 8900 8900 8900 8900 8900 00
212
213
            // USPS - Priority Mail Express
214 6
            '/^927\d{19}$/',      // 9270 1000 0000 0000 0000 00
215 6
            '/^EA\d{9}US$/',      // EA 000 000 000 US
216
217
            // USPS - Priority Mail International
218 6
            '/^CP\d{9}US$/',      // CP 000 000 000 US
219
220
            // USPS - Priority Mail
221 6
            '/^92055\d{17}$/',    // 9205 5000 0000 0000 0000 00
222 6
            '/^14\d{18}$/',       // 1400 0000 0000 0000 0000
223
224
            // USPS - Registered Mail
225 6
            '/^92088\d{17}$/',    // 9208 8000 0000 0000 0000 00
226 6
            '/^RA\d{9}US$/',      // RA 000 000 000 US
227
228
            // USPS - Signature Confirmation
229 6
            '/^9202\d{16}US$/',   // 9202 1000 0000 0000 0000 00
230 6
            '/^23\d{16}US$/',     // 2300 0000 0000 0000 0000
231
232
            // USPS - Tracking
233 6
            '/^94\d{20}$/',       // 9400 1000 0000 0000 0000 00
234 6
            '/^03\d{18}$/',        // 0300 0000 0000 0000 0000
235
236
            // USPS - Parcel Select
237 6
            '/^9261\d{22}$/',       // 9261 0000 0000 0000 0000 0000 00
238 6
        ];
239
240 6
        foreach ($patterns as $pattern) {
241 6
            if (preg_match($pattern, $this->trackingNumber)) {
242 1
                return true;
243
            }
244 6
        }
245
246 5
        return false;
247
    }
248
249
    /**
250
     * Create the Tracking request.
251
     *
252
     * @return string
253
     */
254 6
    private function createRequest()
255
    {
256 6
        $xml = new DOMDocument();
257 6
        $xml->formatOutput = true;
258
259 6
        $trackRequest = $xml->appendChild($xml->createElement('TrackRequest'));
260 6
        $trackRequest->setAttribute('xml:lang', 'en-US');
261
262 6
        $request = $trackRequest->appendChild($xml->createElement('Request'));
263
264 6
        $node = $xml->importNode($this->createTransactionNode(), true);
265 6
        $request->appendChild($node);
266
267 6
        $request->appendChild($xml->createElement('RequestAction', 'Track'));
268
269 6
        if (null !== $this->requestOption) {
270 6
            $request->appendChild($xml->createElement('RequestOption', $this->requestOption));
271 6
        }
272
273 6
        if (null !== $this->trackingNumber) {
274 5
            $trackRequest->appendChild($xml->createElement('TrackingNumber', $this->trackingNumber));
275 5
        }
276
277 6
        if ($this->isMailInnovations()) {
278 1
            $trackRequest->appendChild($xml->createElement('IncludeMailInnovationIndicator'));
279 1
        }
280
281 6
        if (null !== $this->referenceNumber) {
282 1
            $trackRequest->appendChild($xml->createElement('ReferenceNumber'))->appendChild($xml->createElement('Value', $this->referenceNumber));
283 1
        }
284
285 6
        if (null !== $this->shipperNumber) {
286
            $trackRequest->appendChild($xml->createElement('ShipperNumber', $this->shipperNumber));
287
        }
288
289 6
        if (null !== $this->beginDate || null !== $this->endDate) {
290
            $DateRange = $xml->createElement('PickupDateRange');
291
292
            if (null !== $this->beginDate) {
293
                $beginDate = $this->beginDate->format('Ymd');
294
                $DateRange->appendChild($xml->createElement('BeginDate', $beginDate));
295
            }
296
297
            if (null !== $this->endDate) {
298
                $endDate = $this->endDate->format('Ymd');
299
                $DateRange->appendChild($xml->createElement('EndDate', $endDate));
300
            }
301
302
            $trackRequest->appendChild($DateRange);
303
        }
304
305 6
        return $xml->saveXML();
306
    }
307
308
    /**
309
     * Format the response.
310
     *
311
     * @param SimpleXMLElement $response
312
     *
313
     * @return stdClass
314
     */
315 3
    private function formatResponse(SimpleXMLElement $response)
316
    {
317 3
        if ($this->allowMultipleShipments) {
318
            $response = $this->convertXmlObject($response);
319
            if (!is_array($response->Shipment)) {
320
                $response->Shipment = [$response->Shipment];
321
            }
322
            return $response;
323
        }
324
325 3
        return $this->convertXmlObject($response->Shipment);
326
    }
327
328
    /**
329
     * @return RequestInterface
330
     */
331 6 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...
332
    {
333 6
        if (null === $this->request) {
334
            $this->request = new Request($this->logger);
335
        }
336
337 6
        return $this->request;
338
    }
339
340
    /**
341
     * @param RequestInterface $request
342
     *
343
     * @return $this
344
     */
345 6
    public function setRequest(RequestInterface $request)
346
    {
347 6
        $this->request = $request;
348
349 6
        return $this;
350
    }
351
352
    /**
353
     * @return ResponseInterface
354
     */
355 2
    public function getResponse()
356
    {
357 2
        return $this->response;
358
    }
359
360
    /**
361
     * @param ResponseInterface $response
362
     *
363
     * @return $this
364
     */
365
    public function setResponse(ResponseInterface $response)
366
    {
367
        $this->response = $response;
368
369
        return $this;
370
    }
371
372
    /**
373
     * @param bool $value
374
     * @return $this
375
     */
376
    public function allowMultipleShipments($value = true)
377
    {
378
        $this->allowMultipleShipments = $value ? true : false;
379
380
        return $this;
381
    }
382
}
383