Completed
Push — master ( 94c6c6...18a47e )
by Tomáš
03:17
created

Client::orderB2AShipment()   A

Complexity

Conditions 3
Paths 3

Size

Total Lines 16

Duplication

Lines 0
Ratio 0 %

Code Coverage

Tests 8
CRAP Score 3

Importance

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