PluginProbe
PostNL for WooCommerce / 4.4.1
PostNL for WooCommerce v4.4.1
5.9.12 5.9.11 5.9.10 5.9.9 5.9.8 5.9.7 5.9.6 trunk 2.5.0 2.5.1 2.5.2 2.5.3 2.5.4 2.5.5 3.1.4 3.1.5 3.1.6 3.1.7 4.0.0 4.0.1 4.0.2 4.3.2 4.3.3 4.4.0 4.4.1 All 72 releases
woo-postnl / vendor / myparcelnl / sdk / src / Model / Consignment / AbstractConsignment.php

AbstractConsignment.php in PostNL for WooCommerce 4.4.1, at vendor/myparcelnl/sdk/src/Model/Consignment/AbstractConsignment.php

1,820 lines 39.3 KB
No matching file
Up and down to move Enter to open Esc to close
Raw Download Zip
1 <?php
2
3 declare(strict_types=1);
4
5 namespace MyParcelNL\Sdk\src\Model\Consignment;
6
7 use MyParcelNL\Sdk\src\Concerns\HasCheckoutFields;
8 use MyParcelNL\Sdk\src\Exception\MissingFieldException;
9 use MyParcelNL\Sdk\src\Helper\SplitStreet;
10 use MyParcelNL\Sdk\src\Helper\TrackTraceUrl;
11 use MyParcelNL\Sdk\src\Helper\ValidatePostalCode;
12 use MyParcelNL\Sdk\src\Model\MyParcelCustomsItem;
13 use MyParcelNL\Sdk\src\Support\Helpers;
14
15 /**
16 * A model of a consignment
17 * Class Consignment
18 */
19 class AbstractConsignment
20 {
21 use HasCheckoutFields;
22
23 /**
24 * Consignment types
25 */
26 public const DELIVERY_TYPE_MORNING = 1;
27 public const DELIVERY_TYPE_STANDARD = 2;
28 public const DELIVERY_TYPE_EVENING = 3;
29 public const DELIVERY_TYPE_PICKUP = 4;
30
31 /**
32 * @deprecated Since November 2019 is it no longer possible to use pickup express.
33 */
34 public const DELIVERY_TYPE_PICKUP_EXPRESS = 5;
35
36 public const DELIVERY_TYPE_MORNING_NAME = "morning";
37 public const DELIVERY_TYPE_STANDARD_NAME = "standard";
38 public const DELIVERY_TYPE_EVENING_NAME = "evening";
39 public const DELIVERY_TYPE_PICKUP_NAME = "pickup";
40
41 /**
42 * @deprecated Since November 2019 is it no longer possible to use pickup express.
43 */
44 public const DELIVERY_TYPE_PICKUP_EXPRESS_NAME = "pickup_express";
45
46 public const DELIVERY_TYPES_IDS = [
47 self::DELIVERY_TYPE_MORNING,
48 self::DELIVERY_TYPE_STANDARD,
49 self::DELIVERY_TYPE_EVENING,
50 self::DELIVERY_TYPE_PICKUP,
51 self::DELIVERY_TYPE_PICKUP_EXPRESS,
52 ];
53
54 public const DELIVERY_TYPES_NAMES = [
55 self::DELIVERY_TYPE_MORNING_NAME,
56 self::DELIVERY_TYPE_STANDARD_NAME,
57 self::DELIVERY_TYPE_EVENING_NAME,
58 self::DELIVERY_TYPE_PICKUP_NAME,
59 self::DELIVERY_TYPE_PICKUP_EXPRESS_NAME,
60 ];
61
62 public const DELIVERY_TYPES_NAMES_IDS_MAP = [
63 self::DELIVERY_TYPE_MORNING_NAME => self::DELIVERY_TYPE_MORNING,
64 self::DELIVERY_TYPE_STANDARD_NAME => self::DELIVERY_TYPE_STANDARD,
65 self::DELIVERY_TYPE_EVENING_NAME => self::DELIVERY_TYPE_EVENING,
66 self::DELIVERY_TYPE_PICKUP_NAME => self::DELIVERY_TYPE_PICKUP,
67 self::DELIVERY_TYPE_PICKUP_EXPRESS_NAME => self::DELIVERY_TYPE_PICKUP_EXPRESS,
68 ];
69
70 public const DEFAULT_DELIVERY_TYPE = self::DELIVERY_TYPE_STANDARD;
71 public const DEFAULT_DELIVERY_TYPE_NAME = self::DELIVERY_TYPE_STANDARD_NAME;
72
73 /**
74 * Customs declaration types
75 */
76 public const PACKAGE_CONTENTS_COMMERCIAL_GOODS = 1;
77 public const PACKAGE_CONTENTS_COMMERCIAL_SAMPLES = 2;
78 public const PACKAGE_CONTENTS_DOCUMENTS = 3;
79 public const PACKAGE_CONTENTS_GIFTS = 4;
80 public const PACKAGE_CONTENTS_RETRUN_SHIPMENT = 5;
81
82 /**
83 * Package types
84 */
85 public const PACKAGE_TYPE_PACKAGE = 1;
86 public const PACKAGE_TYPE_MAILBOX = 2;
87 public const PACKAGE_TYPE_LETTER = 3;
88 public const PACKAGE_TYPE_DIGITAL_STAMP = 4;
89
90 public const PACKAGE_TYPE_PACKAGE_NAME = "package";
91 public const PACKAGE_TYPE_MAILBOX_NAME = "mailbox";
92 public const PACKAGE_TYPE_LETTER_NAME = "letter";
93 public const PACKAGE_TYPE_DIGITAL_STAMP_NAME = "digital_stamp";
94
95 public const PACKAGE_TYPES_IDS = [
96 self::PACKAGE_TYPE_PACKAGE,
97 self::PACKAGE_TYPE_MAILBOX,
98 self::PACKAGE_TYPE_LETTER,
99 self::PACKAGE_TYPE_DIGITAL_STAMP,
100 ];
101
102 public const PACKAGE_TYPES_NAMES = [
103 self::PACKAGE_TYPE_PACKAGE_NAME,
104 self::PACKAGE_TYPE_MAILBOX_NAME,
105 self::PACKAGE_TYPE_LETTER_NAME,
106 self::PACKAGE_TYPE_DIGITAL_STAMP_NAME,
107 ];
108
109 public const PACKAGE_TYPES_NAMES_IDS_MAP = [
110 self::PACKAGE_TYPE_PACKAGE_NAME => self::PACKAGE_TYPE_PACKAGE,
111 self::PACKAGE_TYPE_MAILBOX_NAME => self::PACKAGE_TYPE_MAILBOX,
112 self::PACKAGE_TYPE_LETTER_NAME => self::PACKAGE_TYPE_LETTER,
113 self::PACKAGE_TYPE_DIGITAL_STAMP_NAME => self::PACKAGE_TYPE_DIGITAL_STAMP,
114 ];
115
116 public const DEFAULT_PACKAGE_TYPE = self::PACKAGE_TYPE_PACKAGE;
117 public const DEFAULT_PACKAGE_TYPE_NAME = self::PACKAGE_TYPE_PACKAGE_NAME;
118
119 /**
120 * Regular expression used to make sure the date is correct.
121 */
122 public const DATE_REGEX = '~(\d{4}-\d{2}-\d{2})$~';
123 public const DATE_TIME_REGEX = '~(\d{4}-\d{2}-\d{2}\s\d{2}:\d{2}:\d{2})$~';
124 public const STATUS_CONCEPT = 1;
125 public const MAX_STREET_LENGTH = 40;
126
127 public const CC_NL = 'NL';
128 public const CC_BE = 'BE';
129
130 public const EURO_COUNTRIES = [
131 'NL',
132 'BE',
133 'AT',
134 'BG',
135 'CZ',
136 'CY',
137 'DK',
138 'EE',
139 'FI',
140 'FR',
141 'DE',
142 'GR',
143 'HU',
144 'IE',
145 'IT',
146 'LV',
147 'LT',
148 'LU',
149 'PL',
150 'PT',
151 'RO',
152 'SK',
153 'SI',
154 'ES',
155 'SE',
156 'XK',
157 ];
158
159 /**
160 * @var array
161 */
162 public const INSURANCE_POSSIBILITIES_LOCAL = [];
163
164 /**
165 * @var string
166 */
167 protected $local_cc = '';
168
169 /**
170 * @internal
171 * @var string
172 */
173 public $reference_identifier;
174
175 /**
176 * @internal
177 * @var int
178 */
179 public $consignment_id;
180
181 /**
182 * @internal
183 * @var string|null
184 */
185 public $api_key;
186
187 /**
188 * @internal
189 * @var string|null
190 */
191 public $barcode;
192
193 /**
194 * @internal
195 * @var int
196 */
197 public $status = null;
198
199 /**
200 * @internal
201 * @var integer
202 */
203 public $shop_id;
204
205 /**
206 * @internal
207 * @var string
208 */
209 public $cc;
210
211 /**
212 * @internal
213 * @var string
214 */
215 public $city;
216
217 /**
218 * @internal
219 * @var string
220 */
221 public $street;
222
223 /**
224 * @internal
225 * @var string
226 */
227 public $street_additional_info;
228
229 /**
230 * @internal
231 * @var string|null
232 */
233 public $number;
234
235 /**
236 * @internal
237 * @var string
238 */
239 public $number_suffix = '';
240
241 /**
242 * @internal
243 * @var string
244 */
245 public $box_number = '';
246
247 /**
248 * @internal
249 * @var string
250 */
251 public $postal_code;
252
253 /**
254 * @internal
255 * @var string
256 */
257 public $person;
258
259 /**
260 * @internal
261 * @var string
262 */
263 public $company = '';
264
265 /**
266 * @internal
267 * @var string
268 */
269 public $email = '';
270
271 /**
272 * @internal
273 * @var string
274 */
275 public $phone = '';
276
277 /**
278 * @internal
279 * @var integer
280 */
281 public $package_type;
282
283 /**
284 * @internal
285 * @var integer
286 */
287 public $delivery_type = self::DEFAULT_DELIVERY_TYPE;
288
289 /**
290 * @internal
291 * @var string
292 */
293 public $delivery_date;
294
295 /**
296 * @internal
297 * @var boolean
298 */
299 public $only_recipient;
300
301 /**
302 * @internal
303 * @var boolean
304 */
305 public $signature;
306
307 /**
308 * @internal
309 * @var boolean
310 */
311 public $return;
312
313 /**
314 * @internal
315 * @var boolean
316 */
317 public $large_format;
318
319 /**
320 * @internal
321 * @var boolean
322 */
323 public $age_check;
324
325 /**
326 * @internal
327 * @var string
328 */
329 public $label_description = '';
330
331 /**
332 * @internal
333 * @var int
334 */
335 public $insurance = 0;
336
337 /**
338 * @internal
339 * @var array
340 */
341 public $physical_properties = [];
342
343 /**
344 * @internal
345 * @var int
346 */
347 public $contents = self::PACKAGE_CONTENTS_COMMERCIAL_GOODS;
348
349 /**
350 * @internal
351 * @var string
352 */
353 public $invoice;
354
355 /**
356 * @internal
357 * @var array
358 */
359 public $items = [];
360
361 /**
362 * @internal
363 * @var string
364 */
365 public $pickup_cc;
366
367 /**
368 * @internal
369 * @var string
370 */
371 public $pickup_postal_code;
372
373 /**
374 * @internal
375 * @var string
376 */
377 public $pickup_street;
378
379 /**
380 * @internal
381 * @var string
382 */
383 public $pickup_city;
384
385 /**
386 * @internal
387 * @var string
388 */
389 public $pickup_number;
390
391 /**
392 * @internal
393 * @var string
394 */
395 public $pickup_location_name;
396
397 /**
398 * @internal
399 * @var string
400 */
401 public $pickup_location_code = '';
402
403 /**
404 * @internal
405 * @var null|string
406 */
407 public $retail_network_id;
408
409 /**
410 * @var bool
411 */
412 private $partOfMultiCollo = false;
413
414 /**
415 * @var bool
416 */
417 private $auto_detect_pickup = true;
418
419 /**
420 * @var bool
421 */
422 private $save_recipient_address = true;
423
424 /**
425 * @var Helpers
426 */
427 private $helper;
428
429 public function __construct()
430 {
431 $this->helper = new Helpers();
432 }
433
434 /**
435 * @return array
436 */
437 public function getInsurancePossibilities(): array
438 {
439 return static::INSURANCE_POSSIBILITIES_LOCAL;
440 }
441
442 /**
443 * @return string|null
444 */
445 public function getReferenceId()
446 {
447 return $this->reference_identifier;
448 }
449
450 /**
451 * @param mixed $reference_identifier
452 *
453 * @return $this
454 */
455 public function setReferenceId(?string $reference_identifier): self
456 {
457 if ($reference_identifier !== null) {
458 $this->reference_identifier = (string) $reference_identifier;
459 }
460
461 return $this;
462 }
463
464 /**
465 * The id of the consignment
466 * Save this id in your database
467 *
468 * @return int|null
469 */
470 public function getConsignmentId(): ?int
471 {
472 return $this->consignment_id;
473 }
474
475 /**
476 * @param int|null $id
477 *
478 * @return $this
479 * @internal
480 * The id of the consignment
481 */
482 public function setConsignmentId(?int $id): self
483 {
484 $this->consignment_id = $id;
485
486 return $this;
487 }
488
489 /**
490 * @return string|null
491 */
492 public function getApiKey(): ?string
493 {
494 return $this->api_key;
495 }
496
497 /**
498 * Set the api key for each shipment.
499 * The key must be given to each shipment. So you can create multiple shipments
500 * in one time for different shops. This way you will not have to ask for the
501 * shop ID. The field shop ID is therefore not necessary.
502 * Required: Yes
503 *
504 * @param string $apiKey
505 *
506 * @return $this
507 */
508 public function setApiKey(string $apiKey): self
509 {
510 $this->api_key = $apiKey;
511
512 return $this;
513 }
514
515 /**
516 * @return int
517 */
518 public function getCarrierId(): int
519 {
520 /** @noinspection PhpUndefinedClassConstantInspection */
521 return static::CARRIER_ID;
522 }
523
524 /**
525 * @param bool $value
526 *
527 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
528 */
529 public function setMultiCollo(bool $value = true): self
530 {
531 $this->partOfMultiCollo = $value;
532
533 return $this;
534 }
535
536 /**
537 * @return bool
538 */
539 public function isPartOfMultiCollo(): bool
540 {
541 return $this->partOfMultiCollo;
542 }
543
544 /**
545 * @return string|null
546 */
547 public function getBarcode(): ?string
548 {
549 return $this->barcode;
550 }
551
552 /**
553 * @param string|null $barcode
554 *
555 * @return $this
556 * @internal
557 */
558 public function setBarcode(?string $barcode): self
559 {
560 $this->barcode = $barcode;
561
562 return $this;
563 }
564
565 /**
566 * Get the status of the consignment
567 * Pattern: [1 – 99]<br>
568 * Example:
569 * 1 pending - concept
570 * 2 pending - registered
571 * 3 enroute - handed to carrier
572 * 4 enroute - sorting
573 * 5 enroute - distribution
574 * 6 enroute - customs
575 * 7 delivered - at recipient
576 * 8 delivered - ready for pickup
577 * 9 delivered - package picked up
578 * 10 delivered - return shipment ready for pickup
579 * 11 delivered - return shipment package picked up
580 * 12 printed - letter
581 * 13 credit
582 * 30 inactive - concept
583 * 31 inactive - registered
584 * 32 inactive - enroute - handed to carrier
585 * 33 inactive - enroute - sorting
586 * 34 inactive - enroute - distribution
587 * 35 inactive - enroute - customs
588 * 36 inactive - delivered - at recipient
589 * 37 inactive - delivered - ready for pickup
590 * 38 inactive - delivered - package picked up
591 * 99 inactive - unknown
592 *
593 * @return int
594 */
595 public function getStatus(): int
596 {
597 return $this->status;
598 }
599
600 /**
601 * Status of the consignment
602 *
603 * @param int $status
604 *
605 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
606 * @internal
607 */
608 public function setStatus($status): self
609 {
610 $this->status = $status;
611
612 return $this;
613 }
614
615 /**
616 * @return integer|null
617 */
618 public function getShopId(): int
619 {
620 return $this->shop_id;
621 }
622
623 /**
624 * @param mixed $shop_id
625 *
626 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
627 * @internal
628 * The shop id to which this shipment belongs
629 * When the store ID is not specified, the API will look at the API key.
630 * Required: No
631 * @internal
632 */
633 public function setShopId($shop_id): self
634 {
635 $this->shop_id = $shop_id;
636
637 return $this;
638 }
639
640 /**
641 * @return string|null
642 */
643 public function getCountry()
644 {
645 return $this->cc;
646 }
647
648 /**
649 * The address country code
650 * ISO3166-1 alpha2 country code<br>
651 * <br>
652 * Pattern: [A-Z]{2}<br>
653 * Example: NL, BE, CW<br>
654 * Required: Yes
655 *
656 * @param string $cc
657 *
658 * @return $this
659 */
660 public function setCountry($cc)
661 {
662 $this->cc = $cc;
663
664 return $this;
665 }
666
667 /**
668 * Check if the address is outside the EU
669 *
670 * @return bool
671 * @todo move to hasCountry trait maken
672 */
673 public function isCdCountry()
674 {
675 return false === $this->isEuCountry();
676 }
677
678 /**
679 * Check if the address is inside the EU
680 *
681 * @return bool
682 * @todo move to hasCountry
683 */
684 public function isEuCountry(): bool
685 {
686 return in_array(
687 $this->getCountry(),
688 self::EURO_COUNTRIES
689 );
690 }
691
692 /**
693 * @return string|null
694 */
695 public function getCity()
696 {
697 return $this->city;
698 }
699
700 /**
701 * The address city
702 * Required: Yes
703 *
704 * @param string $city
705 *
706 * @return $this
707 */
708 public function setCity($city)
709 {
710 $this->city = $city;
711
712 return $this;
713 }
714
715 /**
716 * @return string|null
717 * @throws \MyParcelNL\Sdk\src\Exception\MissingFieldException
718 * @var bool
719 */
720 public function getStreet($useStreetAdditionalInfo = false): string
721 {
722 if (null === $this->street) {
723 throw new MissingFieldException(
724 'First set the street with setStreet() before running getStreet()'
725 );
726 }
727
728 if ($useStreetAdditionalInfo && strlen($this->street) >= self::MAX_STREET_LENGTH) {
729 $streetParts = SplitStreet::getStreetParts($this->street);
730
731 return $streetParts[0];
732 }
733
734 return $this->street;
735 }
736
737 /**
738 * The address street name
739 * Required: Yes or use setFullStreet()
740 *
741 * @param string $street
742 *
743 * @return $this
744 */
745 public function setStreet($street)
746 {
747 $this->street = trim(str_replace('\n', ' ', $street));
748
749 return $this;
750 }
751
752 /**
753 * Get additional information for the street that should not be included in the street field
754 *
755 * @return string|null
756 * @todo move to hasStreet
757 */
758 public function getStreetAdditionalInfo(): ?string
759 {
760 if ($this->street === null) {
761 return null;
762 }
763
764 $streetParts = SplitStreet::getStreetParts($this->street);
765 $result = '';
766
767 if (isset($streetParts[1])) {
768 $result .= $streetParts[1];
769 }
770
771 $result .= ' ' . (string) $this->street_additional_info;
772
773 return trim($result);
774 }
775
776 /**
777 * The street additional info
778 * Required: No
779 *
780 * @param string $street_additional_info
781 *
782 * @return $this
783 */
784 public function setStreetAdditionalInfo(string $street_additional_info): self
785 {
786 $this->street_additional_info = $street_additional_info;
787
788 return $this;
789 }
790
791 /**
792 * Get entire street
793 *
794 * @return string Entire street
795 * @var bool
796 * @todo move to hasCountry
797 */
798 public function getFullStreet(bool $useStreetAdditionalInfo = false): string
799 {
800 $fullStreet = $this->getStreet($useStreetAdditionalInfo);
801
802 if ($this->getNumber()) {
803 $fullStreet .= ' ' . $this->getNumber();
804 }
805
806 if ($this->getBoxNumber()) {
807 $fullStreet .= ' ' . splitstreet::BOX_NL . ' ' . $this->getBoxNumber();
808 }
809
810 if ($this->getNumberSuffix()) {
811 $fullStreet .= ' ' . $this->getNumberSuffix();
812 }
813
814 return trim($fullStreet);
815 }
816
817 /**
818 * Splitting a full NL address and save it in this object
819 * Required: Yes or use setStreet()
820 *
821 * @param string $fullStreet
822 *
823 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
824 * @throws MissingFieldException
825 * @throws \BadMethodCallException
826 * @throws \Exception
827 */
828 public function setFullStreet(string $fullStreet): self
829 {
830 if ($this->getCountry() === null) {
831 throw new MissingFieldException(
832 'First set the country code with setCountry() before running setFullStreet()'
833 );
834 }
835
836 if (empty($this->local_cc)) {
837 throw new \BadMethodCallException('Can not create a shipment when the local country code is empty.');
838 }
839 $fullStreet = SplitStreet::splitStreet($fullStreet, $this->local_cc, $this->getCountry());
840 $this->setStreet($fullStreet->getStreet());
841 $this->setNumber($fullStreet->getNumber());
842 $this->setBoxNumber($fullStreet->getBoxNumber());
843 $this->setNumberSuffix($fullStreet->getNumberSuffix());
844
845 return $this;
846 }
847
848 /**
849 * @param bool $value
850 *
851 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
852 */
853 public function setSaveRecipientAddress(bool $value): self
854 {
855 $this->save_recipient_address = $value;
856
857 return $this;
858 }
859
860 /**
861 * @return bool
862 */
863 public function isSaveRecipientAddress(): bool
864 {
865 return $this->save_recipient_address;
866 }
867
868 /**
869 * @param string $barcode
870 * @param string $postalCode
871 * @param string $countryCode
872 *
873 * @return string
874 */
875 public function getBarcodeUrl(string $barcode, string $postalCode, string $countryCode): string
876 {
877 $barcodeUrl = TrackTraceUrl::create($barcode, $postalCode, $countryCode);
878
879 return $barcodeUrl;
880 }
881
882 /**
883 * @return string|null
884 */
885 public function getNumber(): ?string
886 {
887 return $this->number;
888 }
889
890 /**
891 * Street number
892 * Whole numeric value
893 * Pattern: [0-9]+
894 * Example: 10. 20. NOT 2,3
895 * Required: Yes for NL
896 *
897 * @param mixed $number
898 *
899 * @return $this
900 */
901 public function setNumber($number): self
902 {
903 $this->number = (string) $number;
904
905 return $this;
906 }
907
908 /**
909 * @return string|null
910 */
911 public function getNumberSuffix(): ?string
912 {
913 return $this->number_suffix;
914 }
915
916 /**
917 * Street number suffix.
918 * Required: no
919 *
920 * @param string|null $numberSuffix
921 *
922 * @return $this
923 */
924 public function setNumberSuffix(?string $numberSuffix): self
925 {
926 $this->number_suffix = $numberSuffix;
927
928 return $this;
929 }
930
931 /**
932 * @return string|null
933 */
934 public function getBoxNumber(): ?string
935 {
936 return $this->box_number;
937 }
938
939 /**
940 * Street number suffix.
941 * Required: no
942 *
943 * @param string|null $boxNumber
944 *
945 * @return $this
946 */
947 public function setBoxNumber(?string $boxNumber): self
948 {
949 $this->box_number = $boxNumber;
950
951 return $this;
952 }
953
954 /**
955 * @param array $consignmentEncoded
956 *
957 * @return array
958 */
959 public function encodeStreet(array $consignmentEncoded): array
960 {
961 $consignmentEncoded['recipient']['street'] = $this->getFullStreet(true);
962 $consignmentEncoded['recipient']['street_additional_info'] = $this->getStreetAdditionalInfo();
963
964 return $consignmentEncoded;
965 }
966
967 /**
968 * Check if address is correct
969 * Only for Dutch addresses
970 *
971 * @param $fullStreet
972 *
973 * @return bool
974 */
975 public function isCorrectAddress(string $fullStreet): bool
976 {
977 $localCountry = $this->local_cc;
978 $destinationCountry = $this->getCountry();
979
980 return SplitStreet::isCorrectStreet($fullStreet, $localCountry, $destinationCountry);
981 }
982
983 /**
984 * @return string|null
985 */
986 public function getPostalCode()
987 {
988 return $this->postal_code;
989 }
990
991 /**
992 * @param string $postalCode
993 *
994 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
995 * @throws \BadMethodCallException
996 * @throws \Exception
997 */
998 public function setPostalCode(string $postalCode): self
999 {
1000 if ($this->getCountry() === null) {
1001 throw new MissingFieldException(
1002 'First set the country code with setCountry() before running setPostalCode()'
1003 );
1004 }
1005 if (empty($this->local_cc)) {
1006 throw new \BadMethodCallException('Can not create a shipment when the local country code is empty.');
1007 }
1008
1009 if (! ValidatePostalCode::validate($postalCode, $this->getCountry())) {
1010 throw new \BadMethodCallException('Invalid postal code');
1011 }
1012
1013 $this->postal_code = $postalCode;
1014
1015 return $this;
1016 }
1017
1018 /**
1019 * @return string|null
1020 */
1021 public function getPerson(): string
1022 {
1023 return $this->person;
1024 }
1025
1026 /**
1027 * The person at this address
1028 * Required: Yes
1029 *
1030 * @param string $person
1031 *
1032 * @return $this
1033 */
1034 public function setPerson(string $person): self
1035 {
1036 $this->person = $person;
1037
1038 return $this;
1039 }
1040
1041 /**
1042 * @return string|null
1043 */
1044 public function getCompany(): ?string
1045 {
1046 return $this->company;
1047 }
1048
1049 /**
1050 * Company name
1051 * Required: no
1052 *
1053 * @param string|null $company
1054 *
1055 * @return $this
1056 */
1057 public function setCompany(?string $company): self
1058 {
1059 $this->company = $company;
1060
1061 return $this;
1062 }
1063
1064 /**
1065 * @return string
1066 */
1067 public function getEmail(): string
1068 {
1069 return $this->email;
1070 }
1071
1072 /**
1073 * The address email
1074 * Required: no
1075 *
1076 * @param string $email
1077 *
1078 * @return $this
1079 */
1080 public function setEmail(string $email): self
1081 {
1082 $this->email = $email;
1083
1084 return $this;
1085 }
1086
1087 /**
1088 * @return string|null
1089 */
1090 public function getPhone(): ?string
1091 {
1092 return $this->phone;
1093 }
1094
1095 /**
1096 * The address phone
1097 * Required: no
1098 *
1099 * @param string|null $phone
1100 *
1101 * @return $this
1102 */
1103 public function setPhone(?string $phone): ?self
1104 {
1105 $this->phone = $phone;
1106
1107 return $this;
1108 }
1109
1110 /**
1111 * @param int|null $default
1112 *
1113 * @return int|null
1114 */
1115 public function getPackageType($default = null): ?int
1116 {
1117 return $this->package_type ?? $default;
1118 }
1119
1120 /**
1121 * The package type
1122 * For international shipment only package type 1 is allowed
1123 * Pattern: [1 – 3]<br>
1124 * Example:
1125 * 1. package
1126 * 2. mailbox package
1127 * 3. letter
1128 * Required: Yes
1129 *
1130 * @param int $packageType
1131 *
1132 * @return $this
1133 */
1134 public function setPackageType(int $packageType): self
1135 {
1136 $this->package_type = $packageType;
1137
1138 return $this;
1139 }
1140
1141 /**
1142 * @return int
1143 */
1144 public function getDeliveryType(): int
1145 {
1146 return $this->delivery_type;
1147 }
1148
1149 /**
1150 * The delivery type for the package
1151 * Required: Yes if delivery_date has been specified
1152 *
1153 * @param int $deliveryType
1154 * @param bool $needDeliveryDate
1155 *
1156 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1157 */
1158 public function setDeliveryType(int $deliveryType, bool $needDeliveryDate = false): self
1159 {
1160 $this->delivery_type = $deliveryType;
1161
1162 return $this;
1163 }
1164
1165 /**
1166 * @param bool $value
1167 *
1168 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1169 */
1170 public function setAutoDetectPickup(bool $value): self
1171 {
1172 $this->auto_detect_pickup = $value;
1173
1174 return $this;
1175 }
1176
1177 /**
1178 * @return bool
1179 */
1180 public function isAutoDetectPickup(): bool
1181 {
1182 return $this->auto_detect_pickup;
1183 }
1184
1185 /**
1186 * @return string|null
1187 */
1188 public function getDeliveryDate(): ?string
1189 {
1190 return $this->delivery_date;
1191 }
1192
1193 /**
1194 * The delivery date time for this shipment
1195 * Pattern: YYYY-MM-DD | YYYY-MM-DD HH:MM:SS
1196 * Example: 2017-01-01 | 2017-01-01 00:00:00
1197 * Required: Yes if delivery type has been specified
1198 *
1199 * @param string|null $delivery_date
1200 *
1201 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1202 * @throws \BadMethodCallException
1203 */
1204 public function setDeliveryDate(?string $delivery_date): self
1205 {
1206 if (! $delivery_date) {
1207 $this->delivery_date = null;
1208
1209 return $this;
1210 }
1211
1212 $result = preg_match(self::DATE_REGEX, $delivery_date, $matches);
1213
1214 if ($result) {
1215 $delivery_date = (string) $delivery_date . ' 00:00:00';
1216 } else {
1217 $result = preg_match(self::DATE_TIME_REGEX, $delivery_date, $matches);
1218
1219 if (! $result) {
1220 throw new \BadMethodCallException(
1221 'Make sure the date ('
1222 . $delivery_date
1223 . ') is correct, like pattern: YYYY-MM-DD HH:MM:SS'
1224 . json_encode($matches)
1225 );
1226 }
1227 }
1228
1229 $this->delivery_date = (string) $delivery_date;
1230
1231 return $this;
1232 }
1233
1234 /**
1235 * @return bool
1236 */
1237 public function isOnlyRecipient(): bool
1238 {
1239 return false;
1240 }
1241
1242 /**
1243 * Deliver the package to the recipient only
1244 * Required: No
1245 *
1246 * @param bool $only_recipient
1247 *
1248 * @return $this
1249 */
1250 public function setOnlyRecipient(bool $only_recipient): self
1251 {
1252 if ($only_recipient) {
1253 throw new \BadMethodCallException('Only recipient has to be false in ' . static::class);
1254 }
1255
1256 return $this;
1257 }
1258
1259 /**
1260 * @return bool
1261 */
1262 public function isSignature(): bool
1263 {
1264 return false;
1265 }
1266
1267 /**
1268 * * Package must be signed for
1269 * Required: No
1270 *
1271 * @param bool $signature
1272 *
1273 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1274 */
1275 public function setSignature(bool $signature): self
1276 {
1277 if ($signature) {
1278 throw new \BadMethodCallException('Signature has to be false in ' . static::class);
1279 }
1280
1281 return $this;
1282 }
1283
1284 /**
1285 * Return the package if the recipient is not home
1286 *
1287 * @return boolean
1288 */
1289 public function isReturn()
1290 {
1291 return $this->return;
1292 }
1293
1294 /**
1295 * Return the package if the recipient is not home
1296 * Required: No
1297 *
1298 * @param bool $return
1299 *
1300 * @return $this
1301 * @throws \Exception
1302 */
1303 public function setReturn(bool $return): self
1304 {
1305 $this->return = $this->canHaveOption($return);
1306
1307 return $this;
1308 }
1309
1310 /**
1311 * @return bool
1312 */
1313 public function isLargeFormat(): bool
1314 {
1315 return false;
1316 }
1317
1318 /**
1319 * Large format package
1320 * Required: No
1321 *
1322 * @param bool $largeFormat
1323 *
1324 * @return $this
1325 */
1326 public function setLargeFormat(bool $largeFormat): self
1327 {
1328 if ($largeFormat) {
1329 throw new \BadMethodCallException('Large format has to be false in ' . static::class);
1330 }
1331
1332 return $this;
1333 }
1334
1335 /**
1336 * @return bool
1337 */
1338 public function hasAgeCheck(): bool
1339 {
1340 return false;
1341 }
1342
1343 /**
1344 * Age check
1345 * Required: No
1346 *
1347 * @param bool $ageCheck
1348 *
1349 * @return AbstractConsignment
1350 */
1351 public function setAgeCheck(bool $ageCheck): self
1352 {
1353 if ($ageCheck) {
1354 throw new \BadMethodCallException('Age check has to be false in ' . static::class);
1355 }
1356
1357 return $this;
1358 }
1359
1360 /**
1361 * @return string
1362 */
1363 public function getLabelDescription(): string
1364 {
1365 return $this->label_description;
1366 }
1367
1368 /**
1369 * This description will appear on the shipment label
1370 * Note: This will be overridden for return shipment by the following: Retour – 3SMYPAMYPAXXXXXX
1371 * Required: No
1372 *
1373 * @param mixed $label_description
1374 *
1375 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1376 */
1377 public function setLabelDescription($label_description): self
1378 {
1379 $this->label_description = (string) $label_description;
1380
1381 return $this;
1382 }
1383
1384 /**
1385 * @return int
1386 */
1387 public function getInsurance(): int
1388 {
1389 return $this->insurance;
1390 }
1391
1392 /**
1393 * Insurance price for the package.
1394 * Composite type containing integer and currency. The amount is without decimal separators.
1395 * Required: No
1396 *
1397 * @param int|null $insurance
1398 *
1399 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1400 * @throws \Exception
1401 */
1402 public function setInsurance(?int $insurance): self
1403 {
1404 if (null === $insurance) {
1405 $this->insurance = null;
1406
1407 return $this;
1408 }
1409
1410 if (empty(static::INSURANCE_POSSIBILITIES_LOCAL)) {
1411 throw new \BadMethodCallException('Property insurance_possibilities_local not found in ' . static::class);
1412 }
1413
1414 if (empty($this->local_cc)) {
1415 throw new \BadMethodCallException('Property local_cc not found in ' . static::class);
1416 }
1417
1418 if (! in_array($insurance, static::INSURANCE_POSSIBILITIES_LOCAL) && $this->getCountry() == $this->local_cc) {
1419 throw new \BadMethodCallException(
1420 'Insurance must be one of ' . implode(', ', static::INSURANCE_POSSIBILITIES_LOCAL)
1421 );
1422 }
1423
1424 if (! $this->canHaveOption()) {
1425 $insurance = 0;
1426 }
1427
1428 $this->insurance = $insurance;
1429
1430 return $this;
1431 }
1432
1433 /**
1434 * Required: Yes for non-EU shipments and digital stamps
1435 *
1436 * @param array $physical_properties
1437 *
1438 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1439 */
1440 public function setPhysicalProperties(array $physical_properties): self
1441 {
1442 $this->physical_properties = $physical_properties;
1443
1444 return $this;
1445 }
1446
1447 /**
1448 * @return array
1449 */
1450 public function getPhysicalProperties()
1451 {
1452 return $this->physical_properties;
1453 }
1454
1455 /**
1456 * @return integer
1457 */
1458 public function getContents(): int
1459 {
1460 return $this->contents;
1461 }
1462
1463 /**
1464 * The type of contents in the package.
1465 * The package contents are only needed in case of shipping outside EU,
1466 * this is mandatory info for customs form.
1467 * Pattern: [1 - 5]
1468 * Example: 1. commercial goods
1469 * 2. commercial samples
1470 * 3. documents
1471 * 4. gifts
1472 * 5. return shipment
1473 * Required: Yes for shipping outside EU
1474 *
1475 * @param int $contents
1476 *
1477 * @return $this
1478 */
1479 public function setContents(int $contents): self
1480 {
1481 $this->contents = $contents;
1482
1483 return $this;
1484 }
1485
1486 /**
1487 * @return string|null
1488 */
1489 public function getInvoice(): ?string
1490 {
1491 return $this->invoice;
1492 }
1493
1494 /**
1495 * The invoice number for the commercial goods or samples of package contents.
1496 * Required: Yes for international shipments
1497 *
1498 * @param string $invoice
1499 *
1500 * @return $this
1501 */
1502 public function setInvoice(string $invoice): self
1503 {
1504 $this->invoice = $invoice;
1505
1506 return $this;
1507 }
1508
1509 /**
1510 * @return MyParcelCustomsItem[]
1511 */
1512 public function getItems(): array
1513 {
1514 return $this->items;
1515 }
1516
1517 /**
1518 * A CustomsItem objects with description in the package.
1519 * Required: Yes for international shipments
1520 *
1521 * @param \MyParcelNL\Sdk\src\Model\MyParcelCustomsItem $item
1522 *
1523 * @return $this
1524 * @throws \MyParcelNL\Sdk\src\Exception\MissingFieldException
1525 */
1526 public function addItem(MyParcelCustomsItem $item): self
1527 {
1528 $item->ensureFilled();
1529
1530 $this->items[] = $item;
1531
1532 return $this;
1533 }
1534
1535 /**
1536 * @return string|null
1537 */
1538 public function getPickupCountry(): ?string
1539 {
1540 return $this->pickup_cc;
1541 }
1542
1543 /**
1544 * @param string $pickupCountry
1545 *
1546 * @return AbstractConsignment
1547 */
1548 public function setPickupCountry(string $pickupCountry): self
1549 {
1550 $this->pickup_cc = $pickupCountry;
1551
1552 return $this;
1553 }
1554
1555 /**
1556 * @return string|null
1557 */
1558 public function getPickupPostalCode(): ?string
1559 {
1560 return $this->pickup_postal_code;
1561 }
1562
1563 /**
1564 * Pattern: d{4}\s?[A-Z]{2}
1565 * Example: 2132BH
1566 * Required: Yes for pickup location
1567 *
1568 * @param string $pickup_postal_code
1569 *
1570 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1571 */
1572 public function setPickupPostalCode(string $pickup_postal_code): self
1573 {
1574 $this->pickup_postal_code = $pickup_postal_code;
1575
1576 return $this;
1577 }
1578
1579 /**
1580 * @return string|null
1581 */
1582 public function getPickupStreet(): ?string
1583 {
1584 return $this->pickup_street;
1585 }
1586
1587 /**
1588 * Pattern: [0-9A-Za-z]
1589 * Example: Burgemeester van Stamplein
1590 * Required: Yes for pickup location
1591 *
1592 * @param string $pickup_street
1593 *
1594 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1595 */
1596 public function setPickupStreet(string $pickup_street): self
1597 {
1598 $this->pickup_street = $pickup_street;
1599
1600 return $this;
1601 }
1602
1603 /**
1604 * @return string|null
1605 */
1606 public function getPickupCity(): ?string
1607 {
1608 return $this->pickup_city;
1609 }
1610
1611 /**
1612 * Pattern: [0-9A-Za-z]
1613 * Example: Hoofddorp
1614 * Required: Yes for pickup location
1615 *
1616 * @param string $pickup_city
1617 *
1618 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1619 */
1620 public function setPickupCity(string $pickup_city): self
1621 {
1622 $this->pickup_city = $pickup_city;
1623
1624 return $this;
1625 }
1626
1627 /**
1628 * @return string|null
1629 */
1630 public function getPickupNumber(): ?string
1631 {
1632 return $this->pickup_number;
1633 }
1634
1635 /**
1636 * Pattern: [0-9A-Za-z]
1637 * Example: 270
1638 * Required: Yes for pickup location
1639 *
1640 * @param string $pickup_number
1641 *
1642 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1643 */
1644 public function setPickupNumber(string $pickup_number): self
1645 {
1646 $this->pickup_number = (string) $pickup_number;
1647
1648 return $this;
1649 }
1650
1651 /**
1652 * @return string|null
1653 */
1654 public function getPickupLocationName(): ?string
1655 {
1656 return $this->pickup_location_name;
1657 }
1658
1659 /**
1660 * Pattern: [0-9A-Za-z]
1661 * Example: Albert Heijn
1662 * Required: Yes for pickup location
1663 *
1664 * @param string $pickup_location_name
1665 *
1666 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1667 */
1668 public function setPickupLocationName(string $pickup_location_name): self
1669 {
1670 $this->pickup_location_name = $pickup_location_name;
1671
1672 return $this;
1673 }
1674
1675 /**
1676 * @return string
1677 */
1678 public function getPickupLocationCode(): string
1679 {
1680 return $this->pickup_location_code;
1681 }
1682
1683 /**
1684 * Pattern: [0-9A-Za-z]
1685 * Example: Albert Heijn
1686 * Required: Yes for pickup location
1687 *
1688 * @param string $pickup_location_code
1689 *
1690 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1691 */
1692 public function setPickupLocationCode($pickup_location_code): self
1693 {
1694 $this->pickup_location_code = $pickup_location_code;
1695
1696 return $this;
1697 }
1698
1699 /**
1700 * @return null|string
1701 * @deprecated Use getRetailNetworkId instead
1702 *
1703 */
1704 public function getPickupNetworkId(): ?string
1705 {
1706 return $this->getRetailNetworkId();
1707 }
1708
1709 /**
1710 * @return null|string
1711 */
1712 public function getRetailNetworkId(): ?string
1713 {
1714 return $this->retail_network_id;
1715 }
1716
1717 /**
1718 * Pattern: [0-9A-Za-z]
1719 * Example: Albert Heijn
1720 * Required: Yes for pickup location
1721 *
1722 * @param string $retailNetworkId
1723 *
1724 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1725 * @deprecated Use setRetailNetworkId instead
1726 */
1727 public function setPickupNetworkId($retailNetworkId): self
1728 {
1729 if (! empty($retailNetworkId)) {
1730 throw new \BadMethodCallException('Pickup network id has to be empty in ' . static::class);
1731 }
1732
1733 return $this;
1734 }
1735
1736 /**
1737 * Pattern: [0-9A-Za-z]
1738 * Example: Albert Heijn
1739 * Required: Yes for pickup location
1740 *
1741 * @param string $retailNetworkId
1742 *
1743 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1744 */
1745 public function setRetailNetworkId(string $retailNetworkId): self
1746 {
1747 if (! empty($retailNetworkId)) {
1748 throw new \BadMethodCallException('Retail network id has to be empty in ' . static::class);
1749 }
1750
1751 return $this;
1752 }
1753
1754 /**
1755 * The total weight for all items in whole grams
1756 *
1757 * @return int
1758 */
1759 public function getTotalWeight(): int
1760 {
1761 if (! empty($this->getPhysicalProperties()['weight'])) {
1762 $weight = (int) $this->getPhysicalProperties()['weight'] ?? null;
1763 if ($weight) {
1764 return $weight;
1765 }
1766 }
1767
1768 $weight = 0;
1769
1770 foreach ($this->getItems() as $item) {
1771 $weight += $item->getWeight();
1772 }
1773
1774 if ($weight == 0) {
1775 $weight = 1;
1776 }
1777
1778 return $weight;
1779 }
1780
1781 /**
1782 * The weight has to be entered in grams
1783 *
1784 * @param int $weight
1785 *
1786 * @return \MyParcelNL\Sdk\src\Model\Consignment\AbstractConsignment
1787 */
1788 public function setTotalWeight(int $weight): self
1789 {
1790 $this->setPhysicalProperties(['weight' => $weight]);
1791
1792 return $this;
1793 }
1794
1795 /**
1796 * Only package type 1 can have extra options
1797 *
1798 * @param $option
1799 *
1800 * @return bool
1801 * @throws MissingFieldException
1802 */
1803 protected function canHaveOption(bool $option = true): bool
1804 {
1805 if ($this->getPackageType() === null) {
1806 throw new MissingFieldException('Set package type before ' . $option);
1807 }
1808
1809 return $this->getPackageType() == self::PACKAGE_TYPE_PACKAGE ? $option : false;
1810 }
1811
1812 /**
1813 * @return bool
1814 */
1815 public function validate(): bool
1816 {
1817 return true;
1818 }
1819 }
1820