Completed
Push — master ( e83a08...7dd598 )
by Tomáš
03:07
created

Client::trackPackages()   B

Complexity

Conditions 8
Paths 6

Size

Total Lines 31

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 15
CRAP Score 8.0155

Importance

Changes 0
Metric Value
dl 0
loc 31
ccs 15
cts 16
cp 0.9375
rs 8.1795
c 0
b 0
f 0
cc 8
nc 6
nop 2
crap 8.0155
1
<?php
2
3
namespace Inspirum\Balikobot\Services;
4
5
use DateTime;
6
use Inspirum\Balikobot\Contracts\RequesterInterface;
7
use Inspirum\Balikobot\Definitions\API;
8
use Inspirum\Balikobot\Definitions\Request;
9
use Inspirum\Balikobot\Definitions\Shipper;
10
use Inspirum\Balikobot\Exceptions\BadRequestException;
11
12
class Client
13
{
14
    /**
15
     * API requester
16
     *
17
     * @var \Inspirum\Balikobot\Contracts\RequesterInterface
18
     */
19
    private $requester;
20
21
    /**
22
     * Balikobot API client
23
     *
24
     * @param \Inspirum\Balikobot\Contracts\RequesterInterface $requester
25
     */
26 247
    public function __construct(RequesterInterface $requester)
27
    {
28 247
        $this->requester = $requester;
29 247
    }
30
31
    /**
32
     * Add package(s) to the Balikobot
33
     *
34
     * @param string                     $shipper
35
     * @param array<array<string,mixed>> $packages
36
     * @param string|null                $version
37
     * @param mixed|null                 $labelsUrl
38
     *
39
     * @return array<array<string,mixed>>
40
     *
41
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
42
     */
43 24
    public function addPackages(string $shipper, array $packages, string $version = null, &$labelsUrl = null): array
44
    {
45 24
        $response = $this->requester->call($version ?: API::V1, $shipper, Request::ADD, $packages);
46
47 15
        if (isset($response[0]['package_id']) === false) {
48 1
            throw new BadRequestException($response);
49
        }
50
51 14
        if (isset($response['labels_url'])) {
52 5
            $labelsUrl = $response['labels_url'];
53
        }
54
55 14
        unset($response['labels_url']);
56 14
        unset($response['status']);
57
58 14
        if (count($response) !== count($packages)) {
59 1
            throw new BadRequestException($response);
60
        }
61
62 13
        return $response;
63
    }
64
65
    /**
66
     * Drops a package from the Balikobot – the package must be not ordered
67
     *
68
     * @param string $shipper
69
     * @param int    $packageId
70
     *
71
     * @return void
72
     *
73
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
74
     */
75 2
    public function dropPackage(string $shipper, int $packageId): void
76
    {
77 2
        $this->dropPackages($shipper, [$packageId]);
78 2
    }
79
80
    /**
81
     * Drops a package from the Balikobot – the package must be not ordered
82
     *
83
     * @param string     $shipper
84
     * @param array<int> $packageIds
85
     *
86
     * @return void
87
     *
88
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
89
     */
90 7
    public function dropPackages(string $shipper, array $packageIds): void
91
    {
92 7
        $data = $this->encapsulateIds($packageIds);
93
94 7
        if (count($data) === 0) {
95 1
            return;
96
        }
97
98 6
        $this->requester->call(API::V1, $shipper, Request::DROP, $data);
99 3
    }
100
101
    /**
102
     * Tracks a package
103
     *
104
     * @param string $shipper
105
     * @param string $carrierId
106
     *
107
     * @return array<array<string,int|string>>
108
     *
109
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
110
     */
111 6
    public function trackPackage(string $shipper, string $carrierId): array
112
    {
113 6
        $response = $this->trackPackages($shipper, [$carrierId]);
114
115 3
        return $response[0];
116
    }
117
118
    /**
119
     * Tracks a packages
120
     *
121
     * @param string        $shipper
122
     * @param array<string> $carrierIds
123
     *
124
     * @return array<array<array<string,int|string>>>
125
     *
126
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
127
     */
128 17
    public function trackPackages(string $shipper, array $carrierIds): array
129
    {
130 17
        $data = $this->encapsulateIds($carrierIds);
131
132 17
        $response = $this->requester->call(API::V2, $shipper, Request::TRACK, $data, false);
133
134 13
        unset($response['status']);
135
136
        // fixes that API return only last package statuses for GLS shipper
137
        if (
138 13
            $shipper === Shipper::GLS
139 13
            && count($carrierIds) > 1
140 13
            && count($response) === 1
141 13
            && isset($response[count($carrierIds) - 1])
142
        ) {
143 1
            for ($i = 0; $i < count($carrierIds) - 1; $i++) {
144 1
                $response[$i] = [];
145
            }
146 1
            sort($response);
147
        }
148
149 13
        if (isset($response[0]) === false) {
150 3
            throw new BadRequestException($response);
151
        }
152
153 10
        if (count($response) !== count($carrierIds)) {
154
            throw new BadRequestException($response);
155
        }
156
157 10
        return $response;
158
    }
159
160
    /**
161
     * Tracks a package, get the last info
162
     *
163
     * @param string $shipper
164
     * @param string $carrierId
165
     *
166
     * @return array<string,int|string>
167
     *
168
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
169
     */
170 7
    public function trackPackageLastStatus(string $shipper, string $carrierId): array
171
    {
172 7
        $response = $this->trackPackagesLastStatus($shipper, [$carrierId]);
173
174 3
        return $response[0];
175
    }
176
177
    /**
178
     * Tracks a package, get the last info
179
     *
180
     * @param string        $shipper
181
     * @param array<string> $carrierIds
182
     *
183
     * @return array<array<string,int|string|null>>
184
     *
185
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
186
     */
187 19
    public function trackPackagesLastStatus(string $shipper, array $carrierIds): array
188
    {
189 19
        $data = $this->encapsulateIds($carrierIds);
190
191 19
        $response = $this->requester->call(API::V1, $shipper, Request::TRACK_STATUS, $data, false);
192
193 15
        unset($response['status']);
194
195 15
        if (count($response) !== count($carrierIds)) {
196 3
            throw new BadRequestException($response);
197
        }
198
199 12
        $formatedStatuses = [];
200
201 12
        foreach ($response as $responseItem) {
202 12
            $this->validateStatus($responseItem, $response);
203
204 11
            $formatedStatuses[] = [
205 11
                'name'      => $responseItem['status_text'],
206 11
                'status_id' => $responseItem['status_id'],
207
                'date'      => null,
208
            ];
209
        }
210
211 10
        return $formatedStatuses;
212
    }
213
214
    /**
215
     * Returns packages from the front (not ordered) for given shipper
216
     *
217
     * @param string $shipper
218
     *
219
     * @return array<array<string,int|string>>
220
     *
221
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
222
     */
223 6
    public function getOverview(string $shipper): array
224
    {
225 6
        $response = $this->requester->call(API::V1, $shipper, Request::OVERVIEW, [], false);
226
227 4
        return $response;
228
    }
229
230
    /**
231
     * Gets labels
232
     *
233
     * @param string     $shipper
234
     * @param array<int> $packageIds
235
     *
236
     * @return string
237
     *
238
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
239
     */
240 7
    public function getLabels(string $shipper, array $packageIds): string
241
    {
242
        $data = [
243 7
            'package_ids' => $packageIds,
244
        ];
245
246 7
        $response = $this->requester->call(API::V1, $shipper, Request::LABELS, $data);
247
248 4
        $formattedResponse = $response['labels_url'];
249
250 4
        return $formattedResponse;
251
    }
252
253
    /**
254
     * Gets complete information about a package
255
     *
256
     * @param string $shipper
257
     * @param int    $packageId
258
     *
259
     * @return array<string,int|string>
260
     *
261
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
262
     */
263 6
    public function getPackageInfo(string $shipper, int $packageId): array
264
    {
265 6
        $response = $this->requester->call(API::V1, $shipper, Request::PACKAGE . '/' . $packageId, [], false);
266
267 4
        return $response;
268
    }
269
270
    /**
271
     * Order shipment for packages
272
     *
273
     * @param string     $shipper
274
     * @param array<int> $packageIds
275
     *
276
     * @return array<string,int|string>
277
     *
278
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
279
     */
280 7
    public function orderShipment(string $shipper, array $packageIds): array
281
    {
282
        $data = [
283 7
            'package_ids' => $packageIds,
284
        ];
285
286 7
        $response = $this->requester->call(API::V1, $shipper, Request::ORDER, $data);
287
288 4
        unset($response['status']);
289
290 4
        return $response;
291
    }
292
293
    /**
294
     * Get order details
295
     *
296
     * @param string $shipper
297
     * @param int    $orderId
298
     *
299
     * @return array<string,int|string|array>
300
     *
301
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
302
     */
303 7
    public function getOrder(string $shipper, int $orderId): array
304
    {
305 7
        $response = $this->requester->call(API::V1, $shipper, Request::ORDER_VIEW . '/' . $orderId, [], false);
306
307 5
        unset($response['status']);
308
309 5
        return $response;
310
    }
311
312
    /**
313
     * Order pickup for packages
314
     *
315
     * @param string      $shipper
316
     * @param \DateTime   $dateFrom
317
     * @param \DateTime   $dateTo
318
     * @param float       $weight
319
     * @param int         $packageCount
320
     * @param string|null $message
321
     *
322
     * @return void
323
     *
324
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
325
     */
326 4
    public function orderPickup(
327
        string $shipper,
328
        DateTime $dateFrom,
329
        DateTime $dateTo,
330
        float $weight,
331
        int $packageCount,
332
        string $message = null
333
    ): void {
334
        $data = [
335 4
            'date'          => $dateFrom->format('Y-m-d'),
336 4
            'time_from'     => $dateFrom->format('H:s'),
337 4
            'time_to'       => $dateTo->format('H:s'),
338 4
            'weight'        => $weight,
339 4
            'package_count' => $packageCount,
340 4
            'message'       => $message,
341
        ];
342
343 4
        $this->requester->call(API::V1, $shipper, Request::ORDER_PICKUP, $data);
344 1
    }
345
346
    /**
347
     * Returns available services for the given shipper
348
     *
349
     * @param string      $shipper
350
     * @param string|null $country
351
     * @param string|null $version
352
     *
353
     * @return array<string,string>
354
     *
355
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
356
     */
357 12
    public function getServices(string $shipper, string $country = null, string $version = null): array
358
    {
359 12
        $response = $this->requester->call($version ?: API::V1, $shipper, Request::SERVICES . '/' . $country);
360
361 8
        $formattedResponse = $response['service_types'] ?? [];
362
363 8
        return $formattedResponse;
364
    }
365
366
    /**
367
     * Returns available B2A services for the given shipper
368
     *
369
     * @param string $shipper
370
     *
371
     * @return array<string,string>
372
     *
373
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
374
     */
375 8
    public function getB2AServices(string $shipper): array
376
    {
377 8
        $response = $this->requester->call(API::V1, $shipper, Request::B2A . '/' . Request::SERVICES);
378
379 5
        $formattedResponse = $response['service_types'] ?? [];
380
381 5
        return $formattedResponse;
382
    }
383
384
    /**
385
     * Returns all manipulation units for the given shipper
386
     *
387
     * @param string $shipper
388
     *
389
     * @return array<string,string>
390
     *
391
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
392
     */
393 8
    public function getManipulationUnits(string $shipper): array
394
    {
395 8
        $response = $this->requester->call(API::V1, $shipper, Request::MANIPULATION_UNITS);
396
397 5
        $formattedResponse = $this->normalizeResponseItems($response['units'] ?? [], 'code', 'name');
398
399 5
        return $formattedResponse;
400
    }
401
402
    /**
403
     * Returns available manipulation units for the given shipper
404
     *
405
     * @param string $shipper
406
     *
407
     * @return array<string,string>
408
     *
409
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
410
     */
411 8
    public function getActivatedManipulationUnits(string $shipper): array
412
    {
413 8
        $response = $this->requester->call(API::V1, $shipper, Request::ACTIVATED_MANIPULATION_UNITS);
414
415 5
        $formattedResponse = $this->normalizeResponseItems($response['units'] ?? [], 'code', 'name');
416
417 5
        return $formattedResponse;
418
    }
419
420
    /**
421
     * Returns available branches for the given shipper and its service
422
     * Full branches instead branches request
423
     *
424
     * @param string      $shipper
425
     * @param string|null $service
426
     * @param bool        $fullBranchRequest
427
     * @param string|null $country
428
     * @param string|null $version
429
     *
430
     * @return array<array<string,mixed>>
431
     *
432
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
433
     */
434 15
    public function getBranches(
435
        string $shipper,
436
        ?string $service,
437
        bool $fullBranchRequest = false,
438
        string $country = null,
439
        string $version = null
440
    ): array {
441 15
        $usedRequest = $fullBranchRequest ? Request::FULL_BRANCHES : Request::BRANCHES;
442
443 15
        $response = $this->requester->call(
444 15
            $version ?: API::V1,
445
            $shipper,
446 15
            $usedRequest . '/' . $service . '/' . $country
447
        );
448
449 12
        $formattedResponse = $response['branches'] ?? [];
450
451 12
        return $formattedResponse;
452
    }
453
454
    /**
455
     * Returns available branches for the given shipper in given location
456
     *
457
     * @param string      $shipper
458
     * @param string      $country
459
     * @param string      $city
460
     * @param string|null $postcode
461
     * @param string|null $street
462
     * @param int|null    $maxResults
463
     * @param float|null  $radius
464
     * @param string|null $type
465
     *
466
     * @return array<array<string,mixed>>
467
     *
468
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
469
     */
470 9
    public function getBranchesForLocation(
471
        string $shipper,
472
        string $country,
473
        string $city,
474
        string $postcode = null,
475
        string $street = null,
476
        int $maxResults = null,
477
        float $radius = null,
478
        string $type = null
479
    ): array {
480
        $data = [
481 9
            'country'     => $country,
482 9
            'city'        => $city,
483 9
            'zip'         => $postcode,
484 9
            'street'      => $street,
485 9
            'max_results' => $maxResults,
486 9
            'radius'      => $radius,
487 9
            'type'        => $type,
488
        ];
489
490 9
        $response = $this->requester->call(API::V1, $shipper, Request::BRANCH_LOCATOR, array_filter($data));
491
492 6
        $formattedResponse = $response['branches'] ?? [];
493
494 6
        return $formattedResponse;
495
    }
496
497
    /**
498
     * Returns list of countries where service with cash-on-delivery payment type is available in
499
     *
500
     * @param string $shipper
501
     *
502
     * @return array<array<int|string,array<string,array>>>
503
     *
504
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
505
     */
506 8
    public function getCodCountries(string $shipper): array
507
    {
508 8
        $response = $this->requester->call(API::V1, $shipper, Request::CASH_ON_DELIVERY_COUNTRIES);
509
510 5
        $formattedResponse = $this->normalizeResponseItems(
511 5
            $response['service_types'] ?? [],
512 5
            'service_type',
513 5
            'cod_countries'
514
        );
515
516 5
        return $formattedResponse;
517
    }
518
519
    /**
520
     * Returns list of countries where service is available in
521
     *
522
     * @param string $shipper
523
     *
524
     * @return array<array<int|string,string>>
525
     *
526
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
527
     */
528 8
    public function getCountries(string $shipper): array
529
    {
530 8
        $response = $this->requester->call(API::V1, $shipper, Request::COUNTRIES);
531
532 5
        $formattedResponse = $this->normalizeResponseItems(
533 5
            $response['service_types'] ?? [],
534 5
            'service_type',
535 5
            'countries'
536
        );
537
538 5
        return $formattedResponse;
539
    }
540
541
    /**
542
     * Returns available branches for the given shipper and its service
543
     *
544
     * @param string      $shipper
545
     * @param string      $service
546
     * @param string|null $country
547
     *
548
     * @return array<array<string,mixed>>
549
     *
550
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
551
     */
552 12
    public function getPostCodes(string $shipper, string $service, string $country = null): array
553
    {
554 12
        $response = $this->requester->call(API::V1, $shipper, Request::ZIP_CODES . '/' . $service . '/' . $country);
555
556 9
        $country = $response['country'] ?? $country;
557
558 9
        $formattedResponse = [];
559
560 9
        foreach ($response['zip_codes'] ?? [] as $responseItem) {
561 5
            $formattedResponse[] = [
562 5
                'postcode'     => $responseItem['zip'] ?? ($responseItem['zip_start'] ?? null),
563 5
                'postcode_end' => $responseItem['zip_end'] ?? null,
564 5
                'city'         => $responseItem['city'] ?? null,
565 5
                'country'      => $responseItem['country'] ?? $country,
566 5
                '1B'           => (bool) ($responseItem['1B'] ?? false),
567
            ];
568
        }
569
570 9
        return $formattedResponse;
571
    }
572
573
    /**
574
     * Check package(s) data
575
     *
576
     * @param string               $shipper
577
     * @param array<array<string>> $packages
578
     *
579
     * @return void
580
     *
581
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
582
     */
583 5
    public function checkPackages(string $shipper, array $packages): void
584
    {
585 5
        $this->requester->call(API::V1, $shipper, Request::CHECK, $packages);
586 2
    }
587
588
    /**
589
     * Returns available manipulation units for the given shipper
590
     *
591
     * @param string $shipper
592
     *
593
     * @return array<string>
594
     *
595
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
596
     */
597 8
    public function getAdrUnits(string $shipper): array
598
    {
599 8
        $response = $this->requester->call(API::V1, $shipper, Request::ADR_UNITS);
600
601 5
        $formattedResponse = $this->normalizeResponseItems($response['units'] ?? [], 'code', 'name');
602
603 5
        return $formattedResponse;
604
    }
605
606
    /**
607
     * Returns available activated services for the given shipper
608
     *
609
     * @param string $shipper
610
     *
611
     * @return array<string,mixed>
612
     *
613
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
614
     */
615 6
    public function getActivatedServices(string $shipper): array
616
    {
617 6
        $response = $this->requester->call(API::V1, $shipper, Request::ACTIVATED_SERVICES);
618
619 4
        unset($response['status']);
620
621 4
        return $response;
622
    }
623
624
    /**
625
     * Order shipments from place B (typically supplier / previous consignee) to place A (shipping point)
626
     *
627
     * @param string                     $shipper
628
     * @param array<array<string,mixed>> $packages
629
     *
630
     * @return array<array<string,mixed>>
631
     *
632
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
633
     */
634 10
    public function orderB2AShipment(string $shipper, array $packages): array
635
    {
636 10
        $response = $this->requester->call(API::V1, $shipper, Request::B2A, $packages);
637
638 7
        if (isset($response[0]['package_id']) === false) {
639 1
            throw new BadRequestException($response);
640
        }
641
642 6
        unset($response['status']);
643
644 6
        if (count($response) !== count($packages)) {
645 1
            throw new BadRequestException($response);
646
        }
647
648 5
        return $response;
649
    }
650
651
    /**
652
     * Get PDF link with signed consignment delivery document by the recipient
653
     *
654
     * @param string $shipper
655
     * @param string $carrierId
656
     *
657
     * @return string
658
     *
659
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
660
     */
661 7
    public function getProofOfDelivery(string $shipper, string $carrierId): string
662
    {
663 7
        $response = $this->getProofOfDeliveries($shipper, [$carrierId]);
664
665 3
        return $response[0];
666
    }
667
668
    /**
669
     * Get array of PDF links with signed consignment delivery document by the recipient
670
     *
671
     * @param string        $shipper
672
     * @param array<string> $carrierIds
673
     *
674
     * @return array<string>
675
     *
676
     * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface
677
     */
678 19
    public function getProofOfDeliveries(string $shipper, array $carrierIds): array
679
    {
680 19
        $data = $this->encapsulateIds($carrierIds);
681
682 19
        $response = $this->requester->call(API::V1, $shipper, Request::PROOF_OF_DELIVERY, $data, false);
683
684 15
        unset($response['status']);
685
686 15
        if (count($response) !== count($carrierIds)) {
687 3
            throw new BadRequestException($response);
688
        }
689
690 12
        $formatedLinks = [];
691
692 12
        foreach ($response as $responseItem) {
693 12
            $this->validateStatus($responseItem, $response);
694
695 11
            $formatedLinks[] = $responseItem['file_url'];
696
        }
697
698 10
        return $formatedLinks;
699
    }
700
701
    /**
702
     * Validate response item status
703
     *
704
     * @param array<mixed,mixed> $responseItem
705
     * @param array<mixed,mixed> $response
706
     *
707
     * @return void
708
     */
709 24
    private function validateStatus(array $responseItem, array $response): void
710
    {
711 24
        if (isset($responseItem['status']) && ((int) $responseItem['status']) !== 200) {
712 4
            throw new BadRequestException($response);
713
        }
714 22
    }
715
716
    /**
717
     * Normalize response items
718
     *
719
     * @param array<array<string,string>> $items
720
     * @param string                      $keyName
721
     * @param string                      $valueName
722
     *
723
     * @return array<string,mixed>
724
     */
725 25
    private function normalizeResponseItems(array $items, string $keyName, string $valueName): array
726
    {
727 25
        $formattedResponse = [];
728
729 25
        foreach ($items as $item) {
730 10
            $formattedResponse[$item[$keyName]] = $item[$valueName];
731
        }
732
733 25
        return $formattedResponse;
734
    }
735
736
    /**
737
     * Encapsulate ids
738
     *
739
     * @param array<int|string> $ids
740
     *
741
     * @return array<array<int|string>>
742
     */
743 62
    private function encapsulateIds(array $ids): array
744
    {
745
        return array_map(function ($carrierId) {
746
            return [
747 61
                'id' => $carrierId,
748
            ];
749 62
        }, $ids);
750
    }
751
}
752