├── docs ├── README.md ├── get-started │ ├── installation.md │ └── core-concepts.md ├── carriers │ ├── post-nl.md │ ├── colissimo.md │ ├── fastway.md │ ├── interparcel.md │ ├── ups.md │ ├── tnt-australia.md │ ├── sendle.md │ ├── bring.md │ ├── fedex.md │ ├── royal-mail.md │ ├── usps.md │ ├── dhl-express.md │ ├── canada-post.md │ ├── new-zealand-post.md │ └── australia-post.md ├── models │ ├── http-client.md │ ├── tracking-detail.md │ ├── rate-response.md │ ├── label-response.md │ ├── tracking-response.md │ ├── request.md │ ├── label.md │ ├── shipment.md │ ├── rate.md │ ├── tracking.md │ ├── address.md │ └── package.md ├── api │ ├── logging.md │ └── events.md └── .sidebar.json ├── src ├── carriers │ ├── CarrierInterface.php │ ├── PostNL.php │ └── Colissimo.php ├── exceptions │ ├── ShippyException.php │ └── InvalidRequestException.php ├── Shippy.php ├── rates │ ├── postnl │ │ ├── InternationalBetaalservice.php │ │ ├── InternationalBrievenbuspakje.php │ │ ├── DomesticPakketNoTrackAndTrace.php │ │ ├── DomesticBrievenbuspakje.php │ │ ├── InternationalPakketNoTrackAndTrace.php │ │ ├── DomesticBrief.php │ │ ├── DomesticPakket.php │ │ ├── DomesticAangetekend.php │ │ ├── DomesticBetaalservice.php │ │ ├── DomesticVerzekerservice.php │ │ ├── InternationalBrief.php │ │ ├── InternationalPakket.php │ │ ├── InternationalAangetekend.php │ │ └── InternationalVerzekerservice.php │ ├── royalmail │ │ ├── postoffice │ │ │ ├── ParcelforceExpress10.php │ │ │ ├── ParcelforceExpress24.php │ │ │ ├── ParcelforceExpress48.php │ │ │ ├── ParcelforceExpressAm.php │ │ │ ├── ParcelforceExpress48Large.php │ │ │ ├── ParcelforceExpress9.php │ │ │ ├── InternationalEconomy.php │ │ │ ├── InternationalStandard.php │ │ │ ├── InternationalTrackedSigned.php │ │ │ ├── ParcelforceIrelandexpress.php │ │ │ ├── SpecialDelivery9am.php │ │ │ ├── SpecialDelivery1pm.php │ │ │ ├── Tracked24.php │ │ │ ├── Tracked48.php │ │ │ ├── InternationalTracked.php │ │ │ ├── FirstClass.php │ │ │ ├── SecondClass.php │ │ │ └── InternationalSigned.php │ │ └── online │ │ │ ├── InternationalEconomy.php │ │ │ ├── InternationalStandard.php │ │ │ ├── SpecialDelivery1pm.php │ │ │ ├── Tracked24.php │ │ │ ├── Tracked48.php │ │ │ ├── FirstClass.php │ │ │ ├── InternationalSigned.php │ │ │ └── SecondClass.php │ └── colissimo │ │ ├── DomOutremer.php │ │ ├── TomOutremer.php │ │ ├── TomEconomiqueOutremer.php │ │ ├── Europe.php │ │ ├── DomEconomiqueOutremer.php │ │ ├── International.php │ │ ├── EmballageInternational.php │ │ ├── FrFrance.php │ │ └── FrEmballageFrance.php ├── events │ ├── ModelEvent.php │ ├── RateEvent.php │ ├── LabelEvent.php │ └── TrackingEvent.php ├── models │ ├── RateResponse.php │ ├── LabelResponse.php │ ├── TrackingResponse.php │ ├── HttpClient.php │ ├── ResourceResponse.php │ ├── Request.php │ ├── Response.php │ ├── TrackingDetail.php │ ├── Label.php │ ├── PackageItem.php │ ├── Model.php │ ├── StaticRates.php │ ├── Rate.php │ └── PackageBox.php ├── helpers │ ├── DateTimeHelper.php │ ├── Xml.php │ ├── Json.php │ └── StringHelper.php └── LogTrait.php ├── .gitignore ├── LICENSE.md └── composer.json /docs/README.md: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /src/carriers/CarrierInterface.php: -------------------------------------------------------------------------------- 1 | $value) { 15 | $this->$name = $value; 16 | } 17 | } 18 | } 19 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # CRAFT ENVIRONMENT 2 | .env.php 3 | .env.sh 4 | .env 5 | 6 | # COMPOSER 7 | /vendor 8 | composer.lock 9 | 10 | # BUILD FILES 11 | /bower_components/* 12 | /node_modules/* 13 | /build/* 14 | /yarn-error.log 15 | 16 | # MISC FILES 17 | .cache 18 | .DS_Store 19 | .idea 20 | .project 21 | .settings 22 | .map 23 | *.esproj 24 | *.sublime-workspace 25 | *.sublime-project 26 | *.tmproj 27 | *.tmproject 28 | .vscode/* 29 | !.vscode/settings.json 30 | !.vscode/tasks.json 31 | !.vscode/launch.json 32 | !.vscode/extensions.json 33 | -------------------------------------------------------------------------------- /docs/carriers/fastway.md: -------------------------------------------------------------------------------- 1 | # Fastway 2 | Shippy provides the following feature support for Fastway. 3 | 4 | - Rates 5 | - Tracking 6 | 7 | ## API Credentials 8 | To use Fastway, you'll need to connect to their API. 9 | 10 | 1. Go to Fastway Developers Centre and register for API access. 11 | 1. Copy the **API Key** from Fastway as the `apiKey` with the Shippy carrier. 12 | 13 | ```php 14 | use verbb\shippy\carriers\Fastway; 15 | 16 | new Fastway([ 17 | 'isProduction' => false, 18 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 19 | ]); 20 | ``` 21 | -------------------------------------------------------------------------------- /src/models/RateResponse.php: -------------------------------------------------------------------------------- 1 | rates; 18 | } 19 | 20 | public function setRates(array $rates): RateResponse 21 | { 22 | $this->rates = $rates; 23 | return $this; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/models/LabelResponse.php: -------------------------------------------------------------------------------- 1 | labels; 18 | } 19 | 20 | public function setLabels(array $labels): LabelResponse 21 | { 22 | $this->labels = $labels; 23 | return $this; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/helpers/DateTimeHelper.php: -------------------------------------------------------------------------------- 1 | tracking; 18 | } 19 | 20 | public function setTracking(array $tracking): TrackingResponse 21 | { 22 | $this->tracking = $tracking; 23 | return $this; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /docs/carriers/interparcel.md: -------------------------------------------------------------------------------- 1 | # Interparcel 2 | Shippy provides the following feature support for Interparcel. 3 | 4 | - Rates 5 | - Tracking 6 | 7 | ## API Credentials 8 | To use Interparcel, you'll need to connect to their API. 9 | 10 | 1. Go to Interparcel and request Developer API access. 11 | 1. Once approved, you'll receive an email from the Interparcel support team. 12 | 1. Copy the **API Key** from Interparcel as the `apiKey` with the Shippy carrier. 13 | 14 | ```php 15 | use verbb\shippy\carriers\Interparcel; 16 | 17 | new Interparcel([ 18 | 'isProduction' => false, 19 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 20 | ]); 21 | ``` 22 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticBrievenbuspakje.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 380, 16 | 'width' => 265, 17 | 'height' => 32, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => 425, 21 | ], 22 | ], 23 | ]; 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /src/models/HttpClient.php: -------------------------------------------------------------------------------- 1 | push(Middleware::httpErrors(new BodySummarizer(99999)), 'http_errors'); 18 | $config['handler'] = $stack; 19 | } 20 | 21 | parent::__construct($config); 22 | } 23 | } -------------------------------------------------------------------------------- /docs/api/logging.md: -------------------------------------------------------------------------------- 1 | # Logging 2 | Shippy includes [PSR-3](https://www.php-fig.org/psr/psr-3/) logging throughout the various requests to APIs. You can use the interface to add your own application's logging to Shippy, to have logging routed through there. 3 | 4 | For example, we might like to use the popular [Monolog](https://github.com/Seldaek/monolog) package for logging. Maybe our application already uses it. 5 | 6 | ```php 7 | use Monolog\Logger; 8 | use Monolog\Handler\StreamHandler; 9 | use verbb\shippy\Shippy; 10 | 11 | $logger = new Logger('Shippy'); 12 | $logger->pushHandler(new StreamHandler('shippy.log')); 13 | 14 | Shippy::setLogger($logger); 15 | ``` 16 | 17 | With this in place, all logging that Shippy does will be routed through your Monolog logger, and into a `shippy.log` file within your application. This will include debug and error logging, which is configurable through your Monolog `Logger` instance. 18 | 19 | -------------------------------------------------------------------------------- /docs/carriers/ups.md: -------------------------------------------------------------------------------- 1 | # UPS 2 | Shippy provides the following feature support for UPS. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use UPS, you'll need to connect to their API. 10 | 11 | 1. Go to UPS and login to your account. 12 | 1. From the **Apps** section, follow the prompts to create a new app. 13 | 1. Copy the **Client ID** from UPS as the `username` with the Shippy carrier. 14 | 1. Copy the **Client Secret** from UPS as the `apiKey` with the Shippy carrier. 15 | 16 | To create labels, you'll be required to supply a few more details. 17 | 18 | ```php 19 | use verbb\shippy\carriers\UPS; 20 | 21 | new UPS([ 22 | 'isProduction' => false, 23 | 'clientId' => '••••••••••••••••', 24 | 'clientSecret' => '••••••••••••••••', 25 | 26 | // Required for labels 27 | 'accountNumber' => '••••••••••••••••', 28 | ]); 29 | ``` 30 | -------------------------------------------------------------------------------- /docs/models/tracking-detail.md: -------------------------------------------------------------------------------- 1 | # Tracking Detail 2 | A Tracking Detail model provides further detail on an individual [Tracking](docs:models/tracking) update. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | ----------------- | --------------------------------- | 9 | | `description` | `?string` | The description of the tracking update. 10 | | `date` | `?DateTime` | The date for this tracking update. 11 | | `location` | `?string` | The location marked for this tracking update. 12 | | `status` | `?string` | The status code for this tracking update. 13 | | `statusDetail` | `?string` | The status in detail for this tracking update. 14 | -------------------------------------------------------------------------------- /docs/models/rate-response.md: -------------------------------------------------------------------------------- 1 | # Rate Response 2 | The Rate Response model represents the response from a shipment-creation request. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | ------------- | --------------------------------- | 9 | | `content` | `string` | The body content of the response. Typically a JSON string, but this depends entirely on the carriers API. 10 | | `response` | `mixed` | The raw response from the carrier API. 11 | | `statusCode` | `?int` | The HTTP status code for the response. 12 | | `errorMessage` | `string` | The error message for the response, if applicable. 13 | | `rates` | `array` | A collection of [Rate](docs:models/rate) models. 14 | -------------------------------------------------------------------------------- /docs/models/label-response.md: -------------------------------------------------------------------------------- 1 | # Label Response 2 | The Label Response model represents the response from a shipment-creation request. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | ------------- | --------------------------------- | 9 | | `content` | `string` | The body content of the response. Typically a JSON string, but this depends entirely on the carriers API. 10 | | `response` | `mixed` | The raw response from the carrier API. 11 | | `statusCode` | `?int` | The HTTP status code for the response. 12 | | `errorMessage` | `string` | The error message for the response, if applicable. 13 | | `labels` | `array` | A collection of [Label](docs:models/label) models. 14 | -------------------------------------------------------------------------------- /docs/carriers/tnt-australia.md: -------------------------------------------------------------------------------- 1 | # TNT Australia 2 | Shippy provides the following feature support for TNT Australia. 3 | 4 | - Rates 5 | 6 | ## API Credentials 7 | To use TNT Australia, you'll need to connect to their API. 8 | 9 | 1. Go to TNT Australia Shipping Tools and register for API access. 10 | 1. Copy the **Account Number** from TNT Australia as the `accountNumber` with the Shippy carrier. 11 | 1. Copy the **Username** from TNT Australia as the `username` with the Shippy carrier. 12 | 1. Copy the **Password** from TNT Australia as the `password` with the Shippy carrier. 13 | 14 | ```php 15 | use verbb\shippy\carriers\TNTAustralia; 16 | 17 | new TNTAustralia([ 18 | 'isProduction' => false, 19 | 'accountNumber' => '•••••••••••••••••••••••••••••••••••', 20 | 'username' => '••••••••••••••••', 21 | 'password' => '••••••••••••••••', 22 | ]); 23 | ``` 24 | -------------------------------------------------------------------------------- /src/rates/postnl/InternationalPakketNoTrackAndTrace.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => false, 21 | self::ZONE_EU1 => 980, 22 | self::ZONE_EU2 => 1260, 23 | self::ZONE_EU3 => false, 24 | self::ZONE_WORLD => 1820, 25 | ], 26 | ], 27 | ]; 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /docs/models/tracking-response.md: -------------------------------------------------------------------------------- 1 | # Tracking Response 2 | The Tracking Response model represents the response from a shipment-creation request. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | ------------- | --------------------------------- | 9 | | `content` | `string` | The body content of the response. Typically a JSON string, but this depends entirely on the carriers API. 10 | | `response` | `mixed` | The raw response from the carrier API. 11 | | `statusCode` | `?int` | The HTTP status code for the response. 12 | | `errorMessage` | `string` | The error message for the response, if applicable. 13 | | `tracking` | `array` | A collection of [Tracking](docs:models/tracking) models. 14 | -------------------------------------------------------------------------------- /docs/carriers/sendle.md: -------------------------------------------------------------------------------- 1 | # Sendle 2 | Shippy provides the following feature support for Sendle. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use Sendle, you'll need to connect to their API. 10 | 11 | 1. Go to Sendle and login to your account. 12 | 1. You might prefer to create a Sandbox Sendle account for testing. 13 | 1. From the **Dashboard** visit the **Settings** tab from the sidebar. Click on the **Integrations** tab. 14 | 1. Copy the **Sendle ID** from Sendle as the `sendleId` with the Shippy carrier. 15 | 1. Copy the **API Key** from Sendle as the `apiKey` with the Shippy carrier. 16 | 17 | ```php 18 | use verbb\shippy\carriers\Sendle; 19 | 20 | new Sendle([ 21 | 'isProduction' => false, 22 | 'sendleId' => '••••••••••••••••', 23 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 24 | ]); 25 | ``` 26 | -------------------------------------------------------------------------------- /docs/carriers/bring.md: -------------------------------------------------------------------------------- 1 | # Bring 2 | Shippy provides the following feature support for Bring. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use Bring, you'll need to connect to their API. 10 | 11 | 1. Go to Bring and login to your account. 12 | 1. From the **Dashboard** visit the **Settings and API** page and generate your API keys. 13 | 1. Copy the **Username** from Bring as the `username` with the Shippy carrier. 14 | 1. Copy the **API Key** from Bring as the `apiKey` with the Shippy carrier. 15 | 16 | To create labels, you'll be required to supply a few more details. 17 | 18 | ```php 19 | use verbb\shippy\carriers\Bring; 20 | 21 | new Bring([ 22 | 'isProduction' => false, 23 | 'username' => '••••••••••••••••', 24 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 25 | 26 | // Required for labels 27 | 'clientUrl' => 'https://verbb.io', 28 | 'customerNumber' => '••••••••••', 29 | ]); 30 | ``` 31 | -------------------------------------------------------------------------------- /docs/models/request.md: -------------------------------------------------------------------------------- 1 | # Request 2 | A Request is a generic model for making a HTTP request for a given [HTTP Client](docs:models/http-client). Whenever requests need to be made to carrier APIs, it should be through a Request model. As such, it supports native [Guzzle](https://docs.guzzlephp.org/en/stable/request-options.html) requests parameters. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | ----------------- | ----------------- | --------------------------------- | 9 | | `httpClient` | `HttpClient` | The [HTTP Client](docs:models/http-client) the request should use. 10 | | `method` | `string` | The HTTP method to use. Default to `POST`. 11 | | `endpoint` | `string` | The relative endpoint to request to. 12 | | `payload` | `array` | The payload of data to send. 13 | -------------------------------------------------------------------------------- /docs/carriers/fedex.md: -------------------------------------------------------------------------------- 1 | # FedEx 2 | Shippy provides the following feature support for FedEx. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use FedEx, you'll need to connect to their API. 10 | 11 | 1. Go to FedEx and login to your account. 12 | 1. Follow the Get Started guide to create a **Project**. 13 | 1. Copy the **API Key** from FedEx as the `clientId` with the Shippy carrier. 14 | 1. Copy the **Secret Key** from FedEx as the `clientSecret` with the Shippy carrier. 15 | 1. Copy the **Shipping Account** from FedEx as the `accountNumber` with the Shippy carrier. 16 | 17 | ```php 18 | use verbb\shippy\carriers\FedEx; 19 | 20 | new FedEx([ 21 | 'isProduction' => false, 22 | 'clientId' => '••••••••••••••••', 23 | 'clientSecret' => '•••••••••••••••••••••••••••••••••••', 24 | 'accountNumber' => '••••••••••', 25 | ]); 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/carriers/royal-mail.md: -------------------------------------------------------------------------------- 1 | # Royal Mail 2 | Shippy provides the following feature support for Royal Mail. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | Royal Mail do not offer live rates via their API. Prices according to the [2023 price guide](https://www.royalmail.com/sites/royalmail.com/files/2023-03/royal-mail-our-prices-april-2023-ta.pdf). 9 | 10 | ## API Credentials 11 | To use Royal Mail, you'll need to connect to their API. 12 | 13 | 1. Go to Royal Mail and login to your account. 14 | 1. From the **My Apps** section, follow the prompts to create a new app. 15 | 1. Copy the **API Key** from Royal Mail as the `clientId` with the Shippy carrier. 16 | 1. Copy the **API Secret** from Royal Mail as the `clientSecret` with the Shippy carrier. 17 | 18 | ```php 19 | use verbb\shippy\carriers\RoyalMail; 20 | 21 | new RoyalMail([ 22 | 'isProduction' => false, 23 | 'clientId' => '••••••••••••••••', 24 | 'clientSecret' => '••••••••••••••••', 25 | ]); 26 | ``` 27 | -------------------------------------------------------------------------------- /docs/carriers/usps.md: -------------------------------------------------------------------------------- 1 | # USPS 2 | Shippy provides the following feature support for USPS. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use USPS, you'll need to connect to their API. 10 | 11 | 1. Go to USPS and login to your account. 12 | 1. From the **Apps** section, follow the prompts to create a new app. 13 | 1. Copy the **Consumer Key** from USPS as the `clientId` with the Shippy carrier. 14 | 1. Copy the **Consumer Secret** from USPS as the `clientSecret` with the Shippy carrier. 15 | 16 | To create labels, you'll be required to supply a few more details. 17 | 18 | ```php 19 | use verbb\shippy\carriers\USPS; 20 | 21 | new USPS([ 22 | 'isProduction' => false, 23 | 'clientId' => '••••••••••••••••', 24 | 'clientSecret' => '••••••••••••••••', 25 | 'accountNumber' => '••••••••••••••••', 26 | 27 | // Required for labels 28 | 'customerRegistrationId' => '••••••••••••••••', 29 | 'mailerId' => '••••••••••••••••', 30 | ]); 31 | ``` 32 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | Copyright (c) 2024 Verbb 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions: 6 | 7 | The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. 8 | 9 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. -------------------------------------------------------------------------------- /docs/models/label.md: -------------------------------------------------------------------------------- 1 | # Label 2 | When a [Shipment](docs:models/shipment) is created and lodged, a Label model will be created. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | --------------------- | --------------------------------- | 9 | | `carrier` | `CarrierInterface` | The carrier associated with the label. 10 | | `rate` | `Rate` | The [Rate](docs:models/rate) model associated with the label. 11 | | `trackingNumber` | `?string` | The tracking number the label is for. 12 | | `labelId` | `?string` | The carrier label ID. 13 | | `labelData` | `?string` | The raw data for the label. This is typically a `base64encoded` string representing a PDF, GIF or PNG for the actual label image. 14 | | `labelMime` | `?string` | The mime-type for the label data, which denotes the type of file the data is encoded for. 15 | | `response` | `array` | The raw response from the carrier for the consignment. 16 | 17 | -------------------------------------------------------------------------------- /docs/carriers/dhl-express.md: -------------------------------------------------------------------------------- 1 | # DHL Express 2 | Shippy provides the following feature support for DHL Express. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use DHL Express, you'll need to connect to their API. 10 | 11 | 1. Go to DHL Express and login to your account. 12 | 1. From the **Apps** section, follow the prompts to create a new app. 13 | 1. From the list of available APIs, select (as appropriate) 14 | - **DHL Express - MyDHL API** 15 | - **Shipment Tracking - Unified** 16 | 1. Copy the **API Key** from DHL Express as the `clientId` with the Shippy carrier. 17 | 1. Copy the **Username** from DHL Express as the `username` with the Shippy carrier. 18 | 1. Copy the **Password** from DHL Express as the `password` with the Shippy carrier. 19 | 1. Copy the **Account Number** from DHL Express as the `accountNumber` with the Shippy carrier. 20 | 21 | ```php 22 | use verbb\shippy\carriers\DHLExpress; 23 | 24 | new DHLExpress([ 25 | 'isProduction' => false, 26 | 'clientId' => '•••••••••••••••••••••••••••••••••••', 27 | 'username' => '••••••••••••••••', 28 | 'password' => '••••••••••••••••', 29 | 'accountNumber' => '••••••••••••••••', 30 | ]); 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/carriers/canada-post.md: -------------------------------------------------------------------------------- 1 | # Canada Post 2 | Shippy provides the following feature support for Canada Post. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use Canada Post, you'll need to connect to their API. 10 | 11 | 1. Go to Canada Post Developers Centre and register for API access. 12 | 1. Copy the **Customer Number** from Canada Post as the `customerNumber` with the Shippy carrier. 13 | 1. Copy the **Username** from Canada Post as the `username` with the Shippy carrier. 14 | 1. Copy the **Password** from Canada Post as the `password` with the Shippy carrier. 15 | 1. Copy the **Contract ID** from Canada Post as the `contractId` with the Shippy carrier. 16 | 17 | To create labels, you'll be required to supply a few more details. 18 | 19 | ```php 20 | use verbb\shippy\carriers\Canada Post; 21 | 22 | new Canada Post([ 23 | 'isProduction' => false, 24 | 'username' => '••••••••••••••••', 25 | 'password' => '••••••••••••••••', 26 | 'customerNumber' => '•••••••••••••••••••••••••••••••••••', 27 | 28 | // Required for labels 29 | 'contractId' => '•••••••••••••••••••••••••••••••••••', 30 | ]); 31 | ``` 32 | -------------------------------------------------------------------------------- /docs/models/shipment.md: -------------------------------------------------------------------------------- 1 | # Shipment 2 | A Shipment model represents the top-level model that you work with from start to end. 3 | 4 | A shipment is assigned a origin and destination [Address](docs:models/address) and one or more [Package](docs:models/package) models. You also assign it one or more Carriers to fetch rates for. 5 | 6 | Once rates have been fetched, you can also generate labels for a shipment, which would be lodged with the carrier for pickup and dispatch. 7 | 8 | ## Properties 9 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 10 | 11 | | Property | Type | Description 12 | | ----------------- | ----------------- | --------------------------------- | 13 | | `from` | `Address` | The [Address](docs:models/address) model for the origin sender. 14 | | `to` | `Address` | The [Address](docs:models/address) model for the destination receiver. 15 | | `currency` | `string` | The currency the shipment should be using. 16 | | `packages` | `array` | A collection of [Package](docs:models/package) models for the shipment. 17 | | `carriers` | `array` | A collection of Carriers to fetch rates for. 18 | -------------------------------------------------------------------------------- /src/models/ResourceResponse.php: -------------------------------------------------------------------------------- 1 | response; 31 | } 32 | 33 | public function setResponse(array $response): ResourceResponse 34 | { 35 | $this->response = $response; 36 | return $this; 37 | } 38 | 39 | public function getErrors(): array 40 | { 41 | return $this->errors; 42 | } 43 | 44 | public function setErrors(array $errors): ResourceResponse 45 | { 46 | $this->errors = $errors; 47 | return $this; 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /src/events/RateEvent.php: -------------------------------------------------------------------------------- 1 | carrier; 23 | } 24 | 25 | public function setCarrier(?CarrierInterface $carrier): RateEvent 26 | { 27 | $this->carrier = $carrier; 28 | return $this; 29 | } 30 | 31 | public function getRequest(): ?Request 32 | { 33 | return $this->request; 34 | } 35 | 36 | public function setRequest(?Request $request): RateEvent 37 | { 38 | $this->request = $request; 39 | return $this; 40 | } 41 | 42 | public function getData(): array 43 | { 44 | return $this->data; 45 | } 46 | 47 | public function setData(array $data): RateEvent 48 | { 49 | $this->data = $data; 50 | return $this; 51 | } 52 | } -------------------------------------------------------------------------------- /docs/carriers/new-zealand-post.md: -------------------------------------------------------------------------------- 1 | # New Zealand Post 2 | Shippy provides the following feature support for New Zealand Post. 3 | 4 | - Rates 5 | - Tracking 6 | - Labels 7 | 8 | ## API Credentials 9 | To use New Zealand Post, you'll need to connect to their API. 10 | 11 | 1. Go to New Zealand Post and login to your account. Complete the commercial access form. 12 | 1. Request API access for an application. 13 | 1. Once access have been granted, click “add a new application”. 14 | 1. Include OAuth 2.0 grant type "Client Credentials Grant". 15 | 1. Navigate to your application. 17 | 1. Copy the **Client ID** from New Zealand Post as the `clientId` with the Shippy carrier. 18 | 1. Copy the **Client Secret** from New Zealand Post as the `clientSecret` with the Shippy carrier. 19 | 20 | ```php 21 | use verbb\shippy\carriers\NewZealandPost; 22 | 23 | new NewZealandPost([ 24 | 'isProduction' => false, 25 | 'clientId' => '••••••••••••••••', 26 | 'clientSecret' => '•••••••••••••••••••••••••••••••••••', 27 | ]); 28 | ``` 29 | -------------------------------------------------------------------------------- /src/events/LabelEvent.php: -------------------------------------------------------------------------------- 1 | carrier; 23 | } 24 | 25 | public function setCarrier(?CarrierInterface $carrier): LabelEvent 26 | { 27 | $this->carrier = $carrier; 28 | return $this; 29 | } 30 | 31 | public function getRequest(): ?Request 32 | { 33 | return $this->request; 34 | } 35 | 36 | public function setRequest(?Request $request): LabelEvent 37 | { 38 | $this->request = $request; 39 | return $this; 40 | } 41 | 42 | public function getData(): array 43 | { 44 | return $this->data; 45 | } 46 | 47 | public function setData(array $data): LabelEvent 48 | { 49 | $this->data = $data; 50 | return $this; 51 | } 52 | } -------------------------------------------------------------------------------- /src/events/TrackingEvent.php: -------------------------------------------------------------------------------- 1 | carrier; 23 | } 24 | 25 | public function setCarrier(?CarrierInterface $carrier): TrackingEvent 26 | { 27 | $this->carrier = $carrier; 28 | return $this; 29 | } 30 | 31 | public function getRequest(): ?Request 32 | { 33 | return $this->request; 34 | } 35 | 36 | public function setRequest(?Request $request): TrackingEvent 37 | { 38 | $this->request = $request; 39 | return $this; 40 | } 41 | 42 | public function getData(): array 43 | { 44 | return $this->data; 45 | } 46 | 47 | public function setData(array $data): TrackingEvent 48 | { 49 | $this->data = $data; 50 | return $this; 51 | } 52 | } -------------------------------------------------------------------------------- /docs/models/rate.md: -------------------------------------------------------------------------------- 1 | # Rate 2 | A Rate model represents the estimated cost to ship a shipment from an origin address to a destination address. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | ------------------------- | --------------------- | --------------------------------- | 9 | | `carrier` | `CarrierInterface` | The carrier associated with the rate. 10 | | `serviceName` | `?string` | The name of the carrier service this rate is for. 11 | | `serviceCode` | `?string` | The code or identifier of the carrier service this rate is for. 12 | | `rate` | `?string` | The amount for the rate. 13 | | `currency` | `?string` | The currency code for the rate. 14 | | `deliveryDays` | `?int` | The number of delivery days estimated (carrier support). 15 | | `deliveryDate` | `?DateTime` | The date for estimated delivery (carrier support). 16 | | `deliveryDateGuaranteed` | `?bool` | Whether the delivery date is guaranteed (carrier support). 17 | | `response` | `array` | The raw response from the carrier API for the rate response. 18 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpress10.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-200' => [ 22 | 2000 => 2745, 23 | 5000 => 2745, 24 | 10000 => 3045, 25 | 15000 => 3395, 26 | 20000 => 3395, 27 | 25000 => 3795, 28 | 30000 => 3795, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-200' => [ 35 | 'length' => 1500, 36 | 'width' => 750, 37 | 'height' => 750, 38 | 'weight' => 30000, 39 | ], 40 | ]; 41 | 42 | $boxPricing = self::getBoxPricing($boxes, $bands); 43 | 44 | foreach ($boxPricing as $key => $box) { 45 | // 20% VAT 46 | if (!self::$includeVat) { 47 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 48 | } 49 | } 50 | 51 | return $boxPricing; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpress24.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-150' => [ 22 | 2000 => 1345, 23 | 5000 => 1345, 24 | 10000 => 1645, 25 | 15000 => 1995, 26 | 20000 => 1995, 27 | 25000 => 2395, 28 | 30000 => 2395, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-150' => [ 35 | 'length' => 1500, 36 | 'width' => 750, 37 | 'height' => 750, 38 | 'weight' => 30000, 39 | ], 40 | ]; 41 | 42 | $boxPricing = self::getBoxPricing($boxes, $bands); 43 | 44 | foreach ($boxPricing as $key => $box) { 45 | // 20% VAT 46 | if (!self::$includeVat) { 47 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 48 | } 49 | } 50 | 51 | return $boxPricing; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpress48.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-150' => [ 22 | 2000 => 1295, 23 | 5000 => 1295, 24 | 10000 => 1495, 25 | 15000 => 1795, 26 | 20000 => 1795, 27 | 25000 => 2095, 28 | 30000 => 2095, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-150' => [ 35 | 'length' => 1500, 36 | 'width' => 750, 37 | 'height' => 750, 38 | 'weight' => 30000, 39 | ], 40 | ]; 41 | 42 | $boxPricing = self::getBoxPricing($boxes, $bands); 43 | 44 | foreach ($boxPricing as $key => $box) { 45 | // 20% VAT 46 | if (!self::$includeVat) { 47 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 48 | } 49 | } 50 | 51 | return $boxPricing; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpressAm.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-200' => [ 22 | 2000 => 1745, 23 | 5000 => 1745, 24 | 10000 => 2045, 25 | 15000 => 2395, 26 | 20000 => 2395, 27 | 25000 => 2795, 28 | 30000 => 2795, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-200' => [ 35 | 'length' => 1500, 36 | 'width' => 750, 37 | 'height' => 750, 38 | 'weight' => 30000, 39 | ], 40 | ]; 41 | 42 | $boxPricing = self::getBoxPricing($boxes, $bands); 43 | 44 | foreach ($boxPricing as $key => $box) { 45 | // 20% VAT 46 | if (!self::$includeVat) { 47 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 48 | } 49 | } 50 | 51 | return $boxPricing; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /src/models/Request.php: -------------------------------------------------------------------------------- 1 | httpClient; 21 | } 22 | 23 | public function setHttpClient(?HttpClient $httpClient): Request 24 | { 25 | $this->httpClient = $httpClient; 26 | return $this; 27 | } 28 | 29 | public function getMethod(): string 30 | { 31 | return $this->method; 32 | } 33 | 34 | public function setMethod(string $method): Request 35 | { 36 | $this->method = $method; 37 | return $this; 38 | } 39 | 40 | public function getEndpoint(): string 41 | { 42 | return $this->endpoint; 43 | } 44 | 45 | public function setEndpoint(string $endpoint): Request 46 | { 47 | $this->endpoint = $endpoint; 48 | return $this; 49 | } 50 | 51 | public function getPayload(): array 52 | { 53 | return $this->payload; 54 | } 55 | 56 | public function setPayload(array $payload): Request 57 | { 58 | $this->payload = $payload; 59 | return $this; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpress48Large.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-150' => [ 22 | 2000 => 4795, 23 | 5000 => 4795, 24 | 10000 => 5495, 25 | 15000 => 6795, 26 | 20000 => 6795, 27 | 25000 => 9095, 28 | 30000 => 9095, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-150' => [ 35 | 'length' => 2500, 36 | 'width' => 1250, 37 | 'height' => 1250, 38 | 'weight' => 30000, 39 | ], 40 | ]; 41 | 42 | $boxPricing = self::getBoxPricing($boxes, $bands); 43 | 44 | foreach ($boxPricing as $key => $box) { 45 | // 20% VAT 46 | if (!self::$includeVat) { 47 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 48 | } 49 | } 50 | 51 | return $boxPricing; 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /docs/models/tracking.md: -------------------------------------------------------------------------------- 1 | # Tracking 2 | A Tracking model represents a singular tracking update from a carrier on a shipment. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | ------------------------- | --------------------- | --------------------------------- | 9 | | `carrier` | `CarrierInterface` | The carrier associated with the tracking. 10 | | `trackingNumber` | `?string` | The tracking number for the shipment. 11 | | `status` | `?string` | The carrier status for tracking. 12 | | `statusDetail` | `?string` | The carrier status in detail for tracking. 13 | | `estimatedDelivery` | `?DateTime` | The estimated delivery date for the shipment. 14 | | `signedBy` | `?string` | Who the parcel was signed by upon delivery (carrier support). 15 | | `weight` | `?string` | The weight of the shipment (carrier support). 16 | | `weightUnit` | `?string` | The weight unit of the shipment (carrier support). 17 | | `details` | `array` | A collection of [Tracking Detail](docs:models/tracking-detail) models. 18 | | `errors` | `array` | A collection of any errors encountered for tracking. 19 | | `response` | `array` | The raw response from the carrier API for the rate response. 20 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceExpress9.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-200' => [ 22 | 2000 => 5745, 23 | 5000 => 5745, 24 | 10000 => 6545, 25 | 15000 => 7395, 26 | 20000 => 7395, 27 | 25000 => 8795, 28 | 30000 => 8795, 29 | ], 30 | ], 31 | ]; 32 | 33 | $boxes = [ 34 | 'packet-200' => [ 35 | 'length' => 1500, 36 | 'width' => 750, 37 | 'height' => 750, 38 | 'weight' => 30000, 39 | 'itemValue' => 500, 40 | ], 41 | ]; 42 | 43 | $boxPricing = self::getBoxPricing($boxes, $bands); 44 | 45 | foreach ($boxPricing as $key => $box) { 46 | // 20% VAT 47 | if (!self::$includeVat) { 48 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 49 | } 50 | } 51 | 52 | return $boxPricing; 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /composer.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "verbb/shippy", 3 | "description": "A framework agnostic, multi-carrier shipping library for PHP.", 4 | "version": "1.2.15", 5 | "keywords": [ 6 | "australia-post", 7 | "auspost", 8 | "ups", 9 | "usps", 10 | "fedex" 11 | ], 12 | "support": { 13 | "email": "support@verbb.io", 14 | "issues": "https://github.com/verbb/shippy/issues?state=open", 15 | "source": "https://github.com/verbb/shippy", 16 | "docs": "https://github.com/verbb/shippy", 17 | "rss": "https://github.com/verbb/shippy/commits/v2.atom" 18 | }, 19 | "license": "MIT", 20 | "authors": [ 21 | { 22 | "name": "Verbb", 23 | "homepage": "https://verbb.io" 24 | } 25 | ], 26 | "require": { 27 | "php": "^8.0", 28 | "ext-json": "*", 29 | "commerceguys/addressing": "^1.0 || ^2.0", 30 | "dvdoug/boxpacker": "^3.0 || ^4.0", 31 | "guzzlehttp/guzzle": "^7.0", 32 | "illuminate/collections": "^8.0 || ^9.0 || ^10.0 || ^11.0 || ^12.0", 33 | "php-units-of-measure/php-units-of-measure": "^2.0", 34 | "psr/log": "^1.0 || ^2.0 || ^3.0", 35 | "symfony/event-dispatcher": "^5.0 || ^6.0 || ^7.0", 36 | "symfony/serializer": "^5.0 || ^6.0 || ^7.0" 37 | }, 38 | "require-dev": { 39 | "monolog/monolog": "^1.0 || ^2.0" 40 | }, 41 | "config": { 42 | "sort-packages": true, 43 | "optimize-autoloader": true 44 | }, 45 | "autoload": { 46 | "psr-4": { 47 | "verbb\\shippy\\": "src/" 48 | } 49 | } 50 | } 51 | -------------------------------------------------------------------------------- /src/helpers/Xml.php: -------------------------------------------------------------------------------- 1 | encode($data, 'xml', $options); 28 | } catch (Throwable $e) { 29 | Shippy::error('XML Encode Error: “{message}” {file}:{line}', [ 30 | 'message' => $e->getMessage(), 31 | 'file' => $e->getFile(), 32 | 'line' => $e->getLine(), 33 | ]); 34 | 35 | return ''; 36 | } 37 | } 38 | 39 | public static function decode(?string $data): array 40 | { 41 | try { 42 | return self::getXmlEncoder()->decode((string)$data, 'xml'); 43 | } catch (Throwable $e) { 44 | Shippy::error('XML Decode Error: “{message}” {file}:{line}', [ 45 | 'message' => $e->getMessage(), 46 | 'file' => $e->getFile(), 47 | 'line' => $e->getLine(), 48 | ]); 49 | 50 | return []; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /src/helpers/Json.php: -------------------------------------------------------------------------------- 1 | encode($data, 'json', $options); 28 | } catch (Throwable $e) { 29 | Shippy::error('JSON Encode Error: “{message}” {file}:{line}', [ 30 | 'message' => $e->getMessage(), 31 | 'file' => $e->getFile(), 32 | 'line' => $e->getLine(), 33 | ]); 34 | 35 | return ''; 36 | } 37 | } 38 | 39 | public static function decode(?string $data): array 40 | { 41 | try { 42 | return self::getJsonEncoder()->decode((string)$data, 'json'); 43 | } catch (Throwable $e) { 44 | Shippy::error('JSON Decode Error: “{message}” {file}:{line}', [ 45 | 'message' => $e->getMessage(), 46 | 'file' => $e->getFile(), 47 | 'line' => $e->getLine(), 48 | ]); 49 | 50 | return []; 51 | } 52 | } 53 | } -------------------------------------------------------------------------------- /docs/models/address.md: -------------------------------------------------------------------------------- 1 | # Address 2 | An Address model is used to represent a location for both the sender and delivery of a shipment. It includes the physical address, name, email and phone. 3 | 4 | ## Properties 5 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 6 | 7 | | Property | Type | Description 8 | | --------------------- | ------------- | --------------------------------- | 9 | | `firstName` | `?string` | The first name of the sender or receiver. 10 | | `lastName` | `?string` | The last name of the sender or receiver. 11 | | `companyName` | `?string` | The company name of the sender or receiver. 12 | | `email` | `?string` | The email of the sender or receiver. 13 | | `phone` | `?string` | The phone number of the sender or receiver. 14 | | `street1` | `?string` | The street address (line 1) of the sender or receiver. 15 | | `street2` | `?string` | The street address (line 2) of the sender or receiver. 16 | | `street3` | `?string` | The street address (line 3) of the sender or receiver. 17 | | `city` | `?string` | The city of the sender or receiver. 18 | | `postalCode` | `?string` | The postal or zip code of the sender or receiver. 19 | | `countryCode` | `?string` | The country code of the sender or receiver. 20 | | `stateProvince` | `?string` | The state or province of the sender or receiver. 21 | | `isResidential` | `bool` | Whether this address is considered residential. Some providers require this definition. 22 | -------------------------------------------------------------------------------- /docs/models/package.md: -------------------------------------------------------------------------------- 1 | # Package 2 | A Package model is used to represent the "thing" to ship, and is sent to the carrier API. It includes dimensions, weight and units associated with these values. 3 | 4 | A package should represent a box, satchel or parcel with your carrier, and can likely handle multiple items within it. Shippy doesn't handle packing your items into a Package. 5 | 6 | ## Properties 7 | Properties are `protected` and can be accessed with their `getPropertyName()` getter method or set via `setPropertyName(value)` setter method. 8 | 9 | | Property | Type | Description 10 | | --------------------- | ----------------- | --------------------------------- | 11 | | `weight` | `?string` | The total weight of the package. 12 | | `width` | `?string` | The total width of the package. 13 | | `length` | `?string` | The total length of the package. 14 | | `height` | `?string` | The total height of the package. 15 | | `price` | `?string` | The price for the contents of the package, used for insurance and customs. 16 | | `weightUnit` | `string` | The weight unit. Default to `g`. 17 | | `dimensionUnit` | `string` | The dimension unit. Default to `mm`. 18 | | `packageType` | `?string` | For carriers that need a "type". 19 | | `packagePreset` | `?string` | For carriers that support a pre-defined package name or service. 20 | | `reference` | `?string` | For carriers that support storing a reference against a package. 21 | | `description` | `?string` | For carriers that support storing a description against a package. 22 | | `isDocument` | `bool` | Whether the package should be classified as documents, for the carriers that support this definition. 23 | -------------------------------------------------------------------------------- /src/helpers/StringHelper.php: -------------------------------------------------------------------------------- 1 | Australia Post Developers website and register for an API Key. 15 | 1. Use the **API Key** from Australia Post as the `apiKey` with the Shippy carrier. 16 | 17 | ```php 18 | use verbb\shippy\carriers\AustraliaPost; 19 | 20 | new AustraliaPost([ 21 | 'isProduction' => false, 22 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 23 | ]); 24 | ``` 25 | 26 | ### Shipping and Tracking (All) 27 | A more involved API that handles all features. You will be required to have an Australia Post account. 28 | 29 | 1. Go to Australia Post Developers website and register for an API Key. 30 | 1. Provide your Australia Post (eParcel) account number and complete the registration process. 31 | 1. Use the **API Key** from Australia Post as the `apiKey` with the Shippy carrier. 32 | 1. Use the **Password** from Australia Post as the `password` with the Shippy carrier. 33 | 1. Use the **Account Number** from Australia Post as the `accountNumber` with the Shippy carrier. 34 | 35 | ```php 36 | use verbb\shippy\carriers\AustraliaPost; 37 | 38 | new AustraliaPost([ 39 | 'isProduction' => false, 40 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 41 | 'password' => '•••••••••••••••', 42 | 'accountNumber' => '•••••••••', 43 | ]); 44 | ``` -------------------------------------------------------------------------------- /src/models/Response.php: -------------------------------------------------------------------------------- 1 | content; 24 | } 25 | 26 | public function setContent(string $content): Response 27 | { 28 | $this->content = $content; 29 | return $this; 30 | } 31 | 32 | public function getResponse(): mixed 33 | { 34 | return $this->response; 35 | } 36 | 37 | public function setResponse(mixed $response): Response 38 | { 39 | $this->response = $response; 40 | return $this; 41 | } 42 | 43 | public function getStatusCode(): ?int 44 | { 45 | return $this->statusCode; 46 | } 47 | 48 | public function setStatusCode(?int $statusCode): Response 49 | { 50 | $this->statusCode = $statusCode; 51 | return $this; 52 | } 53 | 54 | public function getErrorMessage(): ?string 55 | { 56 | return $this->errorMessage; 57 | } 58 | 59 | public function setErrorMessage(?string $errorMessage): Response 60 | { 61 | $this->errorMessage = $errorMessage; 62 | return $this; 63 | } 64 | 65 | public function json(): array 66 | { 67 | return Json::decode($this->content); 68 | } 69 | 70 | public function xml(): array 71 | { 72 | return Xml::decode($this->content); 73 | } 74 | } 75 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticBrief.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 380, 16 | 'width' => 265, 17 | 'height' => 32, 18 | 'weight' => 20, 19 | 'price' => [ 20 | self::ZONE_NL => 83, 21 | ], 22 | ], 23 | 'brief-50g' => [ 24 | 'length' => 380, 25 | 'width' => 265, 26 | 'height' => 32, 27 | 'weight' => 50, 28 | 'price' => [ 29 | self::ZONE_NL => 166, 30 | ], 31 | ], 32 | 'brief-100g' => [ 33 | 'length' => 380, 34 | 'width' => 265, 35 | 'height' => 32, 36 | 'weight' => 100, 37 | 'price' => [ 38 | self::ZONE_NL => 249, 39 | ], 40 | ], 41 | 'brief-250g' => [ 42 | 'length' => 380, 43 | 'width' => 265, 44 | 'height' => 32, 45 | 'weight' => 250, 46 | 'price' => [ 47 | self::ZONE_NL => 332, 48 | ], 49 | ], 50 | 'brief-2kg' => [ 51 | 'length' => 380, 52 | 'width' => 265, 53 | 'height' => 32, 54 | 'weight' => 2000, 55 | 'price' => [ 56 | self::ZONE_NL => 415, 57 | ], 58 | ], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticPakket.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => 695, 21 | ], 22 | ], 23 | 'pakket-5kg' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 5000, 28 | 'price' => [ 29 | self::ZONE_NL => 695, 30 | ], 31 | ], 32 | 'pakket-10kg' => [ 33 | 'length' => 1760, 34 | 'width' => 780, 35 | 'height' => 580, 36 | 'weight' => 10000, 37 | 'price' => [ 38 | self::ZONE_NL => 695, 39 | ], 40 | ], 41 | 'pakket-20kg' => [ 42 | 'length' => 1760, 43 | 'width' => 780, 44 | 'height' => 580, 45 | 'weight' => 20000, 46 | 'price' => [ 47 | self::ZONE_NL => 1325, 48 | ], 49 | ], 50 | 'pakket-30kg' => [ 51 | 'length' => 1760, 52 | 'width' => 780, 53 | 'height' => 580, 54 | 'weight' => 30000, 55 | 'price' => [ 56 | self::ZONE_NL => 1325, 57 | ], 58 | ], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticAangetekend.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => 860, 21 | ], 22 | ], 23 | 'pakket-5kg' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 5000, 28 | 'price' => [ 29 | self::ZONE_NL => 860, 30 | ], 31 | ], 32 | 'pakket-10kg' => [ 33 | 'length' => 1760, 34 | 'width' => 780, 35 | 'height' => 580, 36 | 'weight' => 10000, 37 | 'price' => [ 38 | self::ZONE_NL => 860, 39 | ], 40 | ], 41 | 'pakket-20kg' => [ 42 | 'length' => 1760, 43 | 'width' => 780, 44 | 'height' => 580, 45 | 'weight' => 20000, 46 | 'price' => [ 47 | self::ZONE_NL => 1490, 48 | ], 49 | ], 50 | 'pakket-30kg' => [ 51 | 'length' => 1760, 52 | 'width' => 780, 53 | 'height' => 580, 54 | 'weight' => 30000, 55 | 'price' => [ 56 | self::ZONE_NL => 1490, 57 | ], 58 | ], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticBetaalservice.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => 1835, 21 | ], 22 | ], 23 | 'pakket-5kg' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 5000, 28 | 'price' => [ 29 | self::ZONE_NL => 1835, 30 | ], 31 | ], 32 | 'pakket-10kg' => [ 33 | 'length' => 1760, 34 | 'width' => 780, 35 | 'height' => 580, 36 | 'weight' => 10000, 37 | 'price' => [ 38 | self::ZONE_NL => 1835, 39 | ], 40 | ], 41 | 'pakket-20kg' => [ 42 | 'length' => 1760, 43 | 'width' => 780, 44 | 'height' => 580, 45 | 'weight' => 20000, 46 | 'price' => [ 47 | self::ZONE_NL => 2320, 48 | ], 49 | ], 50 | 'pakket-30kg' => [ 51 | 'length' => 1760, 52 | 'width' => 780, 53 | 'height' => 580, 54 | 'weight' => 30000, 55 | 'price' => [ 56 | self::ZONE_NL => 2320, 57 | ], 58 | ], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/rates/postnl/DomesticVerzekerservice.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => 1445, 21 | ], 22 | ], 23 | 'pakket-5kg' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 5000, 28 | 'price' => [ 29 | self::ZONE_NL => 1445, 30 | ], 31 | ], 32 | 'pakket-10kg' => [ 33 | 'length' => 1760, 34 | 'width' => 780, 35 | 'height' => 580, 36 | 'weight' => 10000, 37 | 'price' => [ 38 | self::ZONE_NL => 1445, 39 | ], 40 | ], 41 | 'pakket-20kg' => [ 42 | 'length' => 1760, 43 | 'width' => 780, 44 | 'height' => 580, 45 | 'weight' => 20000, 46 | 'price' => [ 47 | self::ZONE_NL => 2075, 48 | ], 49 | ], 50 | 'pakket-30kg' => [ 51 | 'length' => 1760, 52 | 'width' => 780, 53 | 'height' => 580, 54 | 'weight' => 30000, 55 | 'price' => [ 56 | self::ZONE_NL => 2075, 57 | ], 58 | ], 59 | ]; 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/LogTrait.php: -------------------------------------------------------------------------------- 1 | error(self::t($message, $params)); 31 | } 32 | 33 | public static function warning(string $message, array $params = []): void 34 | { 35 | static::getLogger()->warning(self::t($message, $params)); 36 | } 37 | 38 | public static function notice(string $message, array $params = []): void 39 | { 40 | static::getLogger()->notice(self::t($message, $params)); 41 | } 42 | 43 | public static function info(string $message, array $params = []): void 44 | { 45 | static::getLogger()->info(self::t($message, $params)); 46 | } 47 | 48 | public static function debug(string $message, array $params = []): void 49 | { 50 | static::getLogger()->debug(self::t($message, $params)); 51 | } 52 | 53 | public static function t(string $message, array $params = []): string 54 | { 55 | $placeholders = []; 56 | 57 | foreach ($params as $name => $value) { 58 | $placeholders['{' . $name . '}'] = $value; 59 | } 60 | 61 | return ($placeholders === []) ? $message : strtr($message, $placeholders); 62 | } 63 | 64 | } -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/InternationalEconomy.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 260, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 350, 26 | 250 => 585, 27 | 500 => 660, 28 | 750 => 775, 29 | ], 30 | self::PACKET => [ 31 | 250 => 745, 32 | 500 => 1035, 33 | 750 => 1165, 34 | 1000 => 1300, 35 | 1500 => 1430, 36 | 2000 => 1620, 37 | ], 38 | ], 39 | '2025' => [ 40 | self::LETTER => [ 41 | 100 => 310, 42 | ], 43 | self::LARGE_LETTER => [ 44 | 100 => 410, 45 | 250 => 730, 46 | 500 => 845, 47 | 750 => 1025, 48 | ], 49 | self::PACKET => [ 50 | 250 => 930, 51 | 500 => 1400, 52 | 750 => 1445, 53 | 1000 => 1560, 54 | 1500 => 1715, 55 | 2000 => 2025, 56 | ], 57 | ], 58 | ]; 59 | 60 | return self::getBoxPricing(self::$internationalDefaultBox, $bands, 20); 61 | } 62 | } 63 | -------------------------------------------------------------------------------- /docs/.sidebar.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "title": "Get Started", 4 | "collapsable": false, 5 | "children": [ 6 | "get-started/installation", 7 | "get-started/core-concepts", 8 | "get-started/fetching-rates", 9 | "get-started/tracking-status", 10 | "get-started/creating-labels" 11 | ] 12 | }, 13 | { 14 | "title": "Carriers", 15 | "collapsable": false, 16 | "children": [ 17 | "carriers/aramex", 18 | "carriers/aramex-australia", 19 | "carriers/aramex-new-zealand", 20 | "carriers/australia-post", 21 | "carriers/bring", 22 | "carriers/canada-post", 23 | "carriers/colissimo", 24 | "carriers/dhl-express", 25 | "carriers/fastway", 26 | "carriers/fedex", 27 | "carriers/fedex-freight", 28 | "carriers/interparcel", 29 | "carriers/new-zealand-post", 30 | "carriers/post-nl", 31 | "carriers/royal-mail", 32 | "carriers/sendle", 33 | "carriers/tnt-australia", 34 | "carriers/ups", 35 | "carriers/usps", 36 | "carriers/custom-carrier" 37 | ] 38 | }, 39 | { 40 | "title": "API", 41 | "collapsable": false, 42 | "children": [ 43 | "api/logging", 44 | "api/events" 45 | ] 46 | }, 47 | { 48 | "title": "Models", 49 | "collapsable": false, 50 | "children": [ 51 | "models/address", 52 | "models/http-client", 53 | "models/label", 54 | "models/label-response", 55 | "models/package", 56 | "models/rate", 57 | "models/rate-response", 58 | "models/request", 59 | "models/shipment", 60 | "models/tracking", 61 | "models/tracking-detail", 62 | "models/tracking-response" 63 | ] 64 | } 65 | ] -------------------------------------------------------------------------------- /src/rates/royalmail/online/InternationalEconomy.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 260, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 350, 26 | 250 => 585, 27 | 500 => 660, 28 | 750 => 775, 29 | ], 30 | self::PACKET => [ 31 | 100 => 740, 32 | 250 => 740, 33 | 500 => 1030, 34 | 750 => 1160, 35 | 1000 => 1295, 36 | 1250 => 1425, 37 | 1500 => 1425, 38 | 2000 => 1615, 39 | ], 40 | ], 41 | '2025' => [ 42 | self::LETTER => [ 43 | 100 => 310, 44 | ], 45 | self::LARGE_LETTER => [ 46 | 100 => 410, 47 | 250 => 730, 48 | 500 => 845, 49 | 750 => 1025, 50 | ], 51 | self::PACKET => [ 52 | 250 => 925, 53 | 500 => 1395, 54 | 750 => 1440, 55 | 1000 => 1555, 56 | 1500 => 1710, 57 | 2000 => 2020, 58 | ], 59 | ], 60 | ]; 61 | 62 | return self::getBoxPricing(self::$internationalDefaultBox, $bands, 20); 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /src/models/TrackingDetail.php: -------------------------------------------------------------------------------- 1 | description; 25 | } 26 | 27 | public function setDescription(?string $description): TrackingDetail 28 | { 29 | $this->description = $description; 30 | return $this; 31 | } 32 | 33 | public function getDate(): ?DateTime 34 | { 35 | return $this->date; 36 | } 37 | 38 | public function setDate(DateTime|string|null $date): TrackingDetail 39 | { 40 | $this->date = DateTimeHelper::toDateTime($date); 41 | return $this; 42 | } 43 | 44 | public function getLocation(): ?string 45 | { 46 | return $this->location; 47 | } 48 | 49 | public function setLocation(?string $location): TrackingDetail 50 | { 51 | $this->location = $location; 52 | return $this; 53 | } 54 | 55 | public function getStatus(): ?string 56 | { 57 | return $this->status; 58 | } 59 | 60 | public function setStatus(?string $status): TrackingDetail 61 | { 62 | $this->status = $status; 63 | return $this; 64 | } 65 | 66 | public function getStatusDetail(): ?string 67 | { 68 | return $this->statusDetail; 69 | } 70 | 71 | public function setStatusDetail(?string $statusDetail): TrackingDetail 72 | { 73 | $this->statusDetail = $statusDetail; 74 | return $this; 75 | } 76 | 77 | } -------------------------------------------------------------------------------- /src/rates/colissimo/DomOutremer.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_DOM => 930, 21 | ], 22 | ], 23 | 'pack-1000' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 1000, 28 | 'price' => [ 29 | self::ZONE_DOM => 1410, 30 | ], 31 | ], 32 | 'pack-2000' => [ 33 | 'length' => 1000, 34 | 'width' => 500, 35 | 'height' => 500, 36 | 'weight' => 2000, 37 | 'price' => [ 38 | self::ZONE_DOM => 1920, 39 | ], 40 | ], 41 | 'pack-5000' => [ 42 | 'length' => 1000, 43 | 'width' => 500, 44 | 'height' => 500, 45 | 'weight' => 5000, 46 | 'price' => [ 47 | self::ZONE_DOM => 2890, 48 | ], 49 | ], 50 | 'pack-10000' => [ 51 | 'length' => 1000, 52 | 'width' => 500, 53 | 'height' => 500, 54 | 'weight' => 10000, 55 | 'price' => [ 56 | self::ZONE_DOM => 4640, 57 | ], 58 | ], 59 | 'pack-30000' => [ 60 | 'length' => 1000, 61 | 'width' => 500, 62 | 'height' => 500, 63 | 'weight' => 30000, 64 | 'price' => [ 65 | self::ZONE_DOM => 10360, 66 | ], 67 | ], 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/rates/colissimo/TomOutremer.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 990, 17 | 'height' => 990, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_TOM => 1120, 21 | ], 22 | ], 23 | 'pack-1000' => [ 24 | 'length' => 1000, 25 | 'width' => 990, 26 | 'height' => 990, 27 | 'weight' => 1000, 28 | 'price' => [ 29 | self::ZONE_TOM => 1680, 30 | ], 31 | ], 32 | 'pack-2000' => [ 33 | 'length' => 1000, 34 | 'width' => 990, 35 | 'height' => 990, 36 | 'weight' => 2000, 37 | 'price' => [ 38 | self::ZONE_TOM => 2960, 39 | ], 40 | ], 41 | 'pack-5000' => [ 42 | 'length' => 1000, 43 | 'width' => 990, 44 | 'height' => 990, 45 | 'weight' => 5000, 46 | 'price' => [ 47 | self::ZONE_TOM => 4960, 48 | ], 49 | ], 50 | 'pack-10000' => [ 51 | 'length' => 1000, 52 | 'width' => 990, 53 | 'height' => 990, 54 | 'weight' => 10000, 55 | 'price' => [ 56 | self::ZONE_TOM => 9660, 57 | ], 58 | ], 59 | 'pack-30000' => [ 60 | 'length' => 1000, 61 | 'width' => 990, 62 | 'height' => 990, 63 | 'weight' => 30000, 64 | 'price' => [ 65 | self::ZONE_TOM => 25000, 66 | ], 67 | ], 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/rates/colissimo/TomEconomiqueOutremer.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_TOM => 1080, 21 | ], 22 | ], 23 | 'pack-1000' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 1000, 28 | 'price' => [ 29 | self::ZONE_TOM => 1630, 30 | ], 31 | ], 32 | 'pack-2000' => [ 33 | 'length' => 1000, 34 | 'width' => 500, 35 | 'height' => 500, 36 | 'weight' => 2000, 37 | 'price' => [ 38 | self::ZONE_TOM => 2900, 39 | ], 40 | ], 41 | 'pack-5000' => [ 42 | 'length' => 1000, 43 | 'width' => 500, 44 | 'height' => 500, 45 | 'weight' => 5000, 46 | 'price' => [ 47 | self::ZONE_TOM => 4800, 48 | ], 49 | ], 50 | 'pack-10000' => [ 51 | 'length' => 1000, 52 | 'width' => 500, 53 | 'height' => 500, 54 | 'weight' => 10000, 55 | 'price' => [ 56 | self::ZONE_TOM => 9450, 57 | ], 58 | ], 59 | 'pack-30000' => [ 60 | 'length' => 1000, 61 | 'width' => 500, 62 | 'height' => 500, 63 | 'weight' => 30000, 64 | 'price' => [ 65 | self::ZONE_TOM => 24800, 66 | ], 67 | ], 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/rates/colissimo/Europe.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 990, 17 | 'height' => 990, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_INTERNATIONAL_A => 1230, 21 | ], 22 | ], 23 | 'pack-1000' => [ 24 | 'length' => 1000, 25 | 'width' => 990, 26 | 'height' => 990, 27 | 'weight' => 1000, 28 | 'price' => [ 29 | self::ZONE_INTERNATIONAL_A => 1505, 30 | ], 31 | ], 32 | 'pack-2000' => [ 33 | 'length' => 1000, 34 | 'width' => 990, 35 | 'height' => 990, 36 | 'weight' => 2000, 37 | 'price' => [ 38 | self::ZONE_INTERNATIONAL_A => 1680, 39 | ], 40 | ], 41 | 'pack-5000' => [ 42 | 'length' => 1000, 43 | 'width' => 990, 44 | 'height' => 990, 45 | 'weight' => 5000, 46 | 'price' => [ 47 | self::ZONE_INTERNATIONAL_A => 2150, 48 | ], 49 | ], 50 | 'pack-10000' => [ 51 | 'length' => 1000, 52 | 'width' => 990, 53 | 'height' => 990, 54 | 'weight' => 10000, 55 | 'price' => [ 56 | self::ZONE_INTERNATIONAL_A => 3550, 57 | ], 58 | ], 59 | 'pack-30000' => [ 60 | 'length' => 1000, 61 | 'width' => 990, 62 | 'height' => 990, 63 | 'weight' => 30000, 64 | 'price' => [ 65 | self::ZONE_INTERNATIONAL_A => 5900, 66 | ], 67 | ], 68 | ]; 69 | } 70 | } 71 | -------------------------------------------------------------------------------- /src/rates/colissimo/DomEconomiqueOutremer.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_DOM => 880, 21 | ], 22 | ], 23 | 'pack-1000' => [ 24 | 'length' => 1000, 25 | 'width' => 500, 26 | 'height' => 500, 27 | 'weight' => 1000, 28 | 'price' => [ 29 | self::ZONE_DOM => 1150, 30 | ], 31 | ], 32 | 'pack-2000' => [ 33 | 'length' => 1000, 34 | 'width' => 500, 35 | 'height' => 500, 36 | 'weight' => 2000, 37 | 'price' => [ 38 | self::ZONE_DOM => 1400, 39 | ], 40 | ], 41 | 'pack-5000' => [ 42 | 'length' => 1000, 43 | 'width' => 500, 44 | 'height' => 500, 45 | 'weight' => 5000, 46 | 'price' => [ 47 | self::ZONE_DOM => 2500, 48 | ], 49 | ], 50 | 'pack-10000' => [ 51 | 'length' => 1000, 52 | 'width' => 500, 53 | 'height' => 500, 54 | 'weight' => 10000, 55 | 'price' => [ 56 | self::ZONE_DOM => 3500, 57 | ], 58 | ], 59 | 'pack-20000' => [ 60 | 'length' => 1000, 61 | 'width' => 500, 62 | 'height' => 500, 63 | 'weight' => 30000, 64 | 'price' => [ 65 | self::ZONE_DOM => 6500, 66 | ], 67 | ], 68 | 'pack-30000' => [ 69 | 'length' => 1000, 70 | 'width' => 500, 71 | 'height' => 500, 72 | 'weight' => 30000, 73 | 'price' => [ 74 | self::ZONE_DOM => 9000, 75 | ], 76 | ], 77 | ]; 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/rates/colissimo/International.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 990, 17 | 'height' => 990, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_INTERNATIONAL_B => 1640, 21 | self::ZONE_INTERNATIONAL_C => 2400, 22 | ], 23 | ], 24 | 'pack-1000' => [ 25 | 'length' => 1000, 26 | 'width' => 990, 27 | 'height' => 990, 28 | 'weight' => 1000, 29 | 'price' => [ 30 | self::ZONE_INTERNATIONAL_B => 1960, 31 | self::ZONE_INTERNATIONAL_C => 2670, 32 | ], 33 | ], 34 | 'pack-2000' => [ 35 | 'length' => 1000, 36 | 'width' => 990, 37 | 'height' => 990, 38 | 'weight' => 2000, 39 | 'price' => [ 40 | self::ZONE_INTERNATIONAL_B => 2140, 41 | self::ZONE_INTERNATIONAL_C => 3670, 42 | ], 43 | ], 44 | 'pack-5000' => [ 45 | 'length' => 1000, 46 | 'width' => 990, 47 | 'height' => 990, 48 | 'weight' => 5000, 49 | 'price' => [ 50 | self::ZONE_INTERNATIONAL_B => 2750, 51 | self::ZONE_INTERNATIONAL_C => 5370, 52 | ], 53 | ], 54 | 'pack-10000' => [ 55 | 'length' => 1000, 56 | 'width' => 990, 57 | 'height' => 990, 58 | 'weight' => 10000, 59 | 'price' => [ 60 | self::ZONE_INTERNATIONAL_B => 4550, 61 | self::ZONE_INTERNATIONAL_C => 10150, 62 | ], 63 | ], 64 | 'pack-20000' => [ 65 | 'length' => 1000, 66 | 'width' => 990, 67 | 'height' => 990, 68 | 'weight' => 10000, 69 | 'price' => [ 70 | self::ZONE_INTERNATIONAL_B => 7100, 71 | self::ZONE_INTERNATIONAL_C => 16200, 72 | ], 73 | ], 74 | ]; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/rates/colissimo/EmballageInternational.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 500, 16 | 'width' => 250, 17 | 'height' => 250, 18 | 'weight' => 500, 19 | 'price' => [ 20 | self::ZONE_INTERNATIONAL_B => 1620, 21 | self::ZONE_INTERNATIONAL_C => 2370, 22 | ], 23 | ], 24 | 'pack-1000' => [ 25 | 'length' => 500, 26 | 'width' => 250, 27 | 'height' => 250, 28 | 'weight' => 1000, 29 | 'price' => [ 30 | self::ZONE_INTERNATIONAL_B => 1935, 31 | self::ZONE_INTERNATIONAL_C => 2630, 32 | ], 33 | ], 34 | 'pack-2000' => [ 35 | 'length' => 500, 36 | 'width' => 250, 37 | 'height' => 250, 38 | 'weight' => 2000, 39 | 'price' => [ 40 | self::ZONE_INTERNATIONAL_B => 2105, 41 | self::ZONE_INTERNATIONAL_C => 3610, 42 | ], 43 | ], 44 | 'pack-5000' => [ 45 | 'length' => 500, 46 | 'width' => 250, 47 | 'height' => 250, 48 | 'weight' => 5000, 49 | 'price' => [ 50 | self::ZONE_INTERNATIONAL_B => 2700, 51 | self::ZONE_INTERNATIONAL_C => 5300, 52 | ], 53 | ], 54 | 'pack-10000' => [ 55 | 'length' => 500, 56 | 'width' => 250, 57 | 'height' => 250, 58 | 'weight' => 10000, 59 | 'price' => [ 60 | self::ZONE_INTERNATIONAL_B => 4500, 61 | self::ZONE_INTERNATIONAL_C => 10000, 62 | ], 63 | ], 64 | 'pack-20000' => [ 65 | 'length' => 500, 66 | 'width' => 250, 67 | 'height' => 250, 68 | 'weight' => 10000, 69 | 'price' => [ 70 | self::ZONE_INTERNATIONAL_B => 7000, 71 | self::ZONE_INTERNATIONAL_C => 16000, 72 | ], 73 | ], 74 | ]; 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /src/rates/colissimo/FrFrance.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 990, 17 | 'height' => 990, 18 | 'weight' => 250, 19 | 'price' => [ 20 | self::ZONE_FR => 495, 21 | ], 22 | ], 23 | 'pack-500' => [ 24 | 'length' => 1000, 25 | 'width' => 990, 26 | 'height' => 990, 27 | 'weight' => 500, 28 | 'price' => [ 29 | self::ZONE_FR => 615, 30 | ], 31 | ], 32 | 'pack-750' => [ 33 | 'length' => 1000, 34 | 'width' => 990, 35 | 'height' => 990, 36 | 'weight' => 750, 37 | 'price' => [ 38 | self::ZONE_FR => 700, 39 | ], 40 | ], 41 | 'pack-1000' => [ 42 | 'length' => 1000, 43 | 'width' => 990, 44 | 'height' => 990, 45 | 'weight' => 1000, 46 | 'price' => [ 47 | self::ZONE_FR => 765, 48 | ], 49 | ], 50 | 'pack-2000' => [ 51 | 'length' => 1000, 52 | 'width' => 990, 53 | 'height' => 990, 54 | 'weight' => 2000, 55 | 'price' => [ 56 | self::ZONE_FR => 865, 57 | ], 58 | ], 59 | 'pack-5000' => [ 60 | 'length' => 1000, 61 | 'width' => 990, 62 | 'height' => 990, 63 | 'weight' => 5000, 64 | 'price' => [ 65 | self::ZONE_FR => 1315, 66 | ], 67 | ], 68 | 'pack-10000' => [ 69 | 'length' => 1000, 70 | 'width' => 990, 71 | 'height' => 990, 72 | 'weight' => 10000, 73 | 'price' => [ 74 | self::ZONE_FR => 1920, 75 | ], 76 | ], 77 | 'pack-30000' => [ 78 | 'length' => 1000, 79 | 'width' => 990, 80 | 'height' => 990, 81 | 'weight' => 30000, 82 | 'price' => [ 83 | self::ZONE_FR => 2730, 84 | ], 85 | ], 86 | ]; 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/InternationalStandard.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => [280, 280, 280, 280, 280, 280], 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => [325, 325, 325, 420, 420, 420], 26 | 250 => [475, 475, 475, 635, 755, 650], 27 | 500 => [585, 585, 585, 885, 1090, 920], 28 | 750 => [695, 695, 695, 1180, 1500, 1230], 29 | ], 30 | self::PACKET => [ 31 | 100 => [555, 605, 645, 745, 850, 820], 32 | 250 => [555, 605, 645, 900, 960, 985], 33 | 500 => [735, 815, 890, 1310, 1480, 1580], 34 | 750 => [860, 950, 1060, 1615, 1820, 1870], 35 | 1000 => [990, 1075, 1230, 1915, 2180, 2260], 36 | 1250 => [1035, 1230, 1360, 2135, 2510, 2615], 37 | 1500 => [1035, 1230, 1570, 2330, 2850, 2895], 38 | 2000 => [1200, 1400, 1825, 2450, 3035, 3025], 39 | ], 40 | ], 41 | '2025' => [ 42 | self::LETTER => [ 43 | 100 => [320, 320, 320, 320, 320, 320], 44 | ], 45 | self::LARGE_LETTER => [ 46 | 100 => [340, 340, 340, 420, 420, 420], 47 | 250 => [505, 505, 505, 695, 825, 720], 48 | 500 => [645, 645, 645, 1000, 1230, 1070], 49 | 750 => [870, 870, 870, 1510, 1710, 1620], 50 | ], 51 | self::PACKET => [ 52 | 100 => [580, 630, 675, 780, 890, 1175], 53 | 250 => [580, 630, 675, 940, 1005, 1175], 54 | 500 => [770, 850, 930, 1370, 1545, 1685], 55 | 750 => [900, 995, 1110, 1690, 1900, 1990], 56 | 1000 => [1035, 1125, 1285, 2000, 2280, 2285], 57 | 1250 => [1080, 1285, 1420, 2230, 2625, 2675], 58 | 1500 => [1080, 1285, 1640, 2435, 2980, 3040], 59 | 2000 => [1255, 1465, 1905, 2560, 3170, 3175], 60 | ], 61 | ], 62 | ]; 63 | 64 | return self::getInternationalBoxPricing($bands, $countryCode, 20); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/rates/postnl/InternationalBrief.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 380, 16 | 'width' => 265, 17 | 'height' => 32, 18 | 'weight' => 20, 19 | 'price' => [ 20 | self::ZONE_NL => false, 21 | self::ZONE_EU1 => 140, 22 | self::ZONE_EU2 => 140, 23 | self::ZONE_EU3 => false, 24 | self::ZONE_WORLD => 140, 25 | ], 26 | ], 27 | 'brief-50g' => [ 28 | 'length' => 380, 29 | 'width' => 265, 30 | 'height' => 32, 31 | 'weight' => 50, 32 | 'price' => [ 33 | self::ZONE_NL => false, 34 | self::ZONE_EU1 => 280, 35 | self::ZONE_EU2 => 280, 36 | self::ZONE_EU3 => false, 37 | self::ZONE_WORLD => 280, 38 | ], 39 | ], 40 | 'brief-100g' => [ 41 | 'length' => 380, 42 | 'width' => 265, 43 | 'height' => 32, 44 | 'weight' => 100, 45 | 'price' => [ 46 | self::ZONE_NL => false, 47 | self::ZONE_EU1 => 420, 48 | self::ZONE_EU2 => 420, 49 | self::ZONE_EU3 => false, 50 | self::ZONE_WORLD => 420, 51 | ], 52 | ], 53 | 'brief-250g' => [ 54 | 'length' => 380, 55 | 'width' => 265, 56 | 'height' => 32, 57 | 'weight' => 250, 58 | 'price' => [ 59 | self::ZONE_NL => false, 60 | self::ZONE_EU1 => 840, 61 | self::ZONE_EU2 => 840, 62 | self::ZONE_EU3 => false, 63 | self::ZONE_WORLD => 840, 64 | ], 65 | ], 66 | 'brief-2000g' => [ 67 | 'length' => 380, 68 | 'width' => 265, 69 | 'height' => 32, 70 | 'weight' => 2000, 71 | 'price' => [ 72 | self::ZONE_NL => false, 73 | self::ZONE_EU1 => 980, 74 | self::ZONE_EU2 => 1260, 75 | self::ZONE_EU3 => false, 76 | self::ZONE_WORLD => 1540, 77 | ], 78 | ], 79 | ]; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/InternationalStandard.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => [280, 280, 280, 280, 280, 280], 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => [325, 325, 325, 420, 420, 420], 26 | 250 => [545, 545, 545, 705, 825, 720], 27 | 500 => [655, 655, 655, 955, 1160, 990], 28 | 750 => [765, 765, 765, 1250, 1570, 1300], 29 | ], 30 | self::PACKET => [ 31 | 100 => [830, 845, 925, 1100, 1245, 1250], 32 | 250 => [830, 845, 925, 1250, 1350, 1425], 33 | 500 => [1040, 1075, 1140, 1700, 1870, 2045], 34 | 750 => [1170, 1210, 1295, 2000, 2210, 2350], 35 | 1000 => [1305, 1335, 1445, 2310, 2570, 2750], 36 | 1250 => [1415, 1470, 1575, 2575, 2900, 3130], 37 | 1500 => [1415, 1470, 1700, 2820, 3240, 3430], 38 | 2000 => [1580, 1635, 1850, 2955, 3425, 3570], 39 | ], 40 | ], 41 | '2025' => [ 42 | self::LETTER => [ 43 | 100 => [320, 320, 320, 320, 320, 320], 44 | ], 45 | self::LARGE_LETTER => [ 46 | 100 => [350, 350, 350, 430, 430, 430], 47 | 250 => [580, 580, 580, 770, 900, 800], 48 | 500 => [720, 720, 720, 1080, 1310, 1150], 49 | 750 => [955, 955, 955, 1600, 2010, 1710], 50 | ], 51 | self::PACKET => [ 52 | 100 => [895, 970, 1065, 1305, 1455, 1695], 53 | 250 => [895, 970, 1065, 1405, 1520, 1695], 54 | 500 => [1125, 1235, 1310, 1930, 2120, 2385], 55 | 750 => [1240, 1390, 1490, 2270, 2510, 2695], 56 | 1000 => [1355, 1535, 1660, 2620, 2915, 3005], 57 | 1250 => [1425, 1690, 1810, 2925, 3290, 3415], 58 | 1500 => [1425, 1690, 1955, 3200, 3675, 3415], 59 | 2000 => [1625, 1880, 2125, 3355, 3885, 3570], 60 | ], 61 | ], 62 | ]; 63 | 64 | return self::getInternationalBoxPricing($bands, $countryCode, 20); 65 | } 66 | } 67 | -------------------------------------------------------------------------------- /src/rates/postnl/InternationalPakket.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => false, 21 | self::ZONE_EU1 => 1300, 22 | self::ZONE_EU2 => 1850, 23 | self::ZONE_EU3 => false, 24 | self::ZONE_WORLD => 2430, 25 | ], 26 | ], 27 | 'pakket-5kg' => [ 28 | 'length' => 1000, 29 | 'width' => 500, 30 | 'height' => 500, 31 | 'weight' => 5000, 32 | 'price' => [ 33 | self::ZONE_NL => false, 34 | self::ZONE_EU1 => 1950, 35 | self::ZONE_EU2 => 2500, 36 | self::ZONE_EU3 => false, 37 | self::ZONE_WORLD => 3430, 38 | ], 39 | ], 40 | 'pakket-10kg' => [ 41 | 'length' => 1000, 42 | 'width' => 500, 43 | 'height' => 500, 44 | 'weight' => 10000, 45 | 'price' => [ 46 | self::ZONE_NL => false, 47 | self::ZONE_EU1 => 2500, 48 | self::ZONE_EU2 => 3100, 49 | self::ZONE_EU3 => false, 50 | self::ZONE_WORLD => 5830, 51 | ], 52 | ], 53 | 'pakket-20kg' => [ 54 | 'length' => 1000, 55 | 'width' => 500, 56 | 'height' => 500, 57 | 'weight' => 20000, 58 | 'price' => [ 59 | self::ZONE_NL => false, 60 | self::ZONE_EU1 => 3400, 61 | self::ZONE_EU2 => 4000, 62 | self::ZONE_EU3 => false, 63 | self::ZONE_WORLD => 10530, 64 | ], 65 | ], 66 | 'pakket-30kg' => [ 67 | 'length' => 1000, 68 | 'width' => 500, 69 | 'height' => 500, 70 | 'weight' => 30000, 71 | 'price' => [ 72 | self::ZONE_NL => false, 73 | self::ZONE_EU1 => 4500, 74 | self::ZONE_EU2 => 5500, 75 | self::ZONE_EU3 => false, 76 | self::ZONE_WORLD => false, 77 | ], 78 | ], 79 | ]; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/models/Label.php: -------------------------------------------------------------------------------- 1 | carrier; 26 | } 27 | 28 | public function setCarrier(CarrierInterface $carrier): Label 29 | { 30 | $this->carrier = $carrier; 31 | return $this; 32 | } 33 | 34 | public function getRate(): Rate 35 | { 36 | return $this->rate; 37 | } 38 | 39 | public function setRate(Rate $rate): Label 40 | { 41 | $this->rate = $rate; 42 | return $this; 43 | } 44 | 45 | public function getTrackingNumber(): string 46 | { 47 | return (string)$this->trackingNumber; 48 | } 49 | 50 | public function setTrackingNumber(string $trackingNumber): Label 51 | { 52 | $this->trackingNumber = $trackingNumber; 53 | return $this; 54 | } 55 | 56 | public function getLabelId(): string 57 | { 58 | return (string)$this->labelId; 59 | } 60 | 61 | public function setLabelId(string $labelId): Label 62 | { 63 | $this->labelId = $labelId; 64 | return $this; 65 | } 66 | 67 | public function getLabelData(): string 68 | { 69 | return (string)$this->labelData; 70 | } 71 | 72 | public function setLabelData(string $labelData): Label 73 | { 74 | $this->labelData = $labelData; 75 | return $this; 76 | } 77 | 78 | public function getLabelMime(): string 79 | { 80 | return (string)$this->labelMime; 81 | } 82 | 83 | public function setLabelMime(string $labelMime): Label 84 | { 85 | $this->labelMime = $labelMime; 86 | return $this; 87 | } 88 | 89 | public function getResponse(): array 90 | { 91 | return $this->response; 92 | } 93 | 94 | public function setResponse(array $response): Label 95 | { 96 | $this->response = $response; 97 | return $this; 98 | } 99 | 100 | public function toArray(): array 101 | { 102 | // Remove debug/info attributes 103 | $vars = parent::toArray(); 104 | unset($vars['carrier'], $vars['response']); 105 | 106 | return $vars; 107 | } 108 | 109 | } -------------------------------------------------------------------------------- /src/rates/postnl/InternationalAangetekend.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => false, 21 | self::ZONE_EU1 => 1550, 22 | self::ZONE_EU2 => 2100, 23 | self::ZONE_EU3 => false, 24 | self::ZONE_WORLD => 2680, 25 | ], 26 | ], 27 | 'pakket-5kg' => [ 28 | 'length' => 1000, 29 | 'width' => 500, 30 | 'height' => 500, 31 | 'weight' => 5000, 32 | 'price' => [ 33 | self::ZONE_NL => false, 34 | self::ZONE_EU1 => 2200, 35 | self::ZONE_EU2 => 2750, 36 | self::ZONE_EU3 => false, 37 | self::ZONE_WORLD => 3680, 38 | ], 39 | ], 40 | 'pakket-10kg' => [ 41 | 'length' => 1000, 42 | 'width' => 500, 43 | 'height' => 500, 44 | 'weight' => 10000, 45 | 'price' => [ 46 | self::ZONE_NL => false, 47 | self::ZONE_EU1 => 2750, 48 | self::ZONE_EU2 => 3350, 49 | self::ZONE_EU3 => false, 50 | self::ZONE_WORLD => 6080, 51 | ], 52 | ], 53 | 'pakket-20kg' => [ 54 | 'length' => 1000, 55 | 'width' => 500, 56 | 'height' => 500, 57 | 'weight' => 20000, 58 | 'price' => [ 59 | self::ZONE_NL => false, 60 | self::ZONE_EU1 => 3650, 61 | self::ZONE_EU2 => 4250, 62 | self::ZONE_EU3 => false, 63 | self::ZONE_WORLD => 10780, 64 | ], 65 | ], 66 | 'pakket-30kg' => [ 67 | 'length' => 1000, 68 | 'width' => 500, 69 | 'height' => 500, 70 | 'weight' => 30000, 71 | 'price' => [ 72 | self::ZONE_NL => false, 73 | self::ZONE_EU1 => 4750, 74 | self::ZONE_EU2 => 5750, 75 | self::ZONE_EU3 => false, 76 | self::ZONE_WORLD => false, 77 | ], 78 | ], 79 | ]; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/rates/postnl/InternationalVerzekerservice.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 1000, 16 | 'width' => 500, 17 | 'height' => 500, 18 | 'weight' => 2000, 19 | 'price' => [ 20 | self::ZONE_NL => false, 21 | self::ZONE_EU1 => 2300, 22 | self::ZONE_EU2 => 2850, 23 | self::ZONE_EU3 => false, 24 | self::ZONE_WORLD => 3430, 25 | ], 26 | ], 27 | 'pakket-5kg' => [ 28 | 'length' => 1000, 29 | 'width' => 500, 30 | 'height' => 500, 31 | 'weight' => 5000, 32 | 'price' => [ 33 | self::ZONE_NL => false, 34 | self::ZONE_EU1 => 2950, 35 | self::ZONE_EU2 => 3500, 36 | self::ZONE_EU3 => false, 37 | self::ZONE_WORLD => 4430, 38 | ], 39 | ], 40 | 'pakket-10kg' => [ 41 | 'length' => 1000, 42 | 'width' => 500, 43 | 'height' => 500, 44 | 'weight' => 10000, 45 | 'price' => [ 46 | self::ZONE_NL => false, 47 | self::ZONE_EU1 => 3500, 48 | self::ZONE_EU2 => 4100, 49 | self::ZONE_EU3 => false, 50 | self::ZONE_WORLD => 6830, 51 | ], 52 | ], 53 | 'pakket-20kg' => [ 54 | 'length' => 1000, 55 | 'width' => 500, 56 | 'height' => 500, 57 | 'weight' => 20000, 58 | 'price' => [ 59 | self::ZONE_NL => false, 60 | self::ZONE_EU1 => 4400, 61 | self::ZONE_EU2 => 5000, 62 | self::ZONE_EU3 => false, 63 | self::ZONE_WORLD => 11530, 64 | ], 65 | ], 66 | 'pakket-30kg' => [ 67 | 'length' => 1000, 68 | 'width' => 500, 69 | 'height' => 500, 70 | 'weight' => 30000, 71 | 'price' => [ 72 | self::ZONE_NL => false, 73 | self::ZONE_EU1 => 5500, 74 | self::ZONE_EU2 => 6500, 75 | self::ZONE_EU3 => false, 76 | self::ZONE_WORLD => false, 77 | ], 78 | ], 79 | ]; 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/InternationalTrackedSigned.php: -------------------------------------------------------------------------------- 1 | [ 27 | self::LETTER => [ 28 | 100 => [815, 815, 815, 815, 815, 815], 29 | ], 30 | self::LARGE_LETTER => [ 31 | 100 => [965, 965, 965, 1065, 1080, 1075], 32 | 250 => [1090, 1090, 1090, 1230, 1350, 1250], 33 | 500 => [1170, 1170, 1170, 1430, 1630, 1465], 34 | 750 => [1215, 1215, 1215, 1635, 1935, 1685], 35 | ], 36 | self::PACKET => [ 37 | 100 => [1375, 1390, 1530, 1770, 1900, 1845], 38 | 250 => [1375, 1390, 1530, 1810, 1935, 2020], 39 | 500 => [1520, 1560, 1700, 2240, 2430, 2615], 40 | 750 => [1635, 1670, 1825, 2500, 2740, 2835], 41 | 1000 => [1740, 1770, 1955, 2795, 3085, 3235], 42 | 1250 => [1800, 1805, 2025, 3015, 3355, 3615], 43 | 1500 => [1810, 1830, 2090, 3170, 3630, 3915], 44 | 2000 => [1825, 1880, 2140, 3220, 3745, 3970], 45 | ], 46 | self::PRINTED_PAPERS => [ 47 | 100 => [1375, 1390, 1530, 1770, 1900, 1845], 48 | 250 => [1375, 1390, 1530, 1810, 1935, 2020], 49 | 500 => [1520, 1560, 1700, 2240, 2430, 2615], 50 | 750 => [1635, 1670, 1825, 2500, 2740, 2835], 51 | 1000 => [1740, 1770, 1955, 2795, 3085, 3235], 52 | 1250 => [1800, 1805, 2025, 3015, 3355, 3615], 53 | 1500 => [1810, 1830, 2090, 3170, 3630, 3915], 54 | 2000 => [1825, 1880, 2140, 3220, 3745, 3970], 55 | ], 56 | ], 57 | ]; 58 | 59 | return self::getInternationalBoxPricing($bands, $countryCode); 60 | } 61 | } 62 | -------------------------------------------------------------------------------- /src/models/PackageItem.php: -------------------------------------------------------------------------------- 1 | description = $description; 26 | $this->width = $width; 27 | $this->length = $length; 28 | $this->depth = $depth; 29 | $this->weight = $weight; 30 | $this->keepFlat = false; 31 | } 32 | 33 | public function getDescription(): string 34 | { 35 | return (string)$this->description; 36 | } 37 | 38 | public function setDescription($value): void 39 | { 40 | $this->description = $value; 41 | } 42 | 43 | public function getWidth(): int 44 | { 45 | return (int)$this->width; 46 | } 47 | 48 | public function setWidth($value): void 49 | { 50 | $this->width = $value; 51 | } 52 | 53 | public function getLength(): int 54 | { 55 | return (int)$this->length; 56 | } 57 | 58 | public function setLength($value): void 59 | { 60 | $this->length = $value; 61 | } 62 | 63 | public function getDepth(): int 64 | { 65 | return (int)$this->depth; 66 | } 67 | 68 | public function setDepth($value): void 69 | { 70 | $this->depth = $value; 71 | } 72 | 73 | public function getWeight(): int 74 | { 75 | return (int)$this->weight; 76 | } 77 | 78 | public function setWeight($value): void 79 | { 80 | $this->weight = $value; 81 | } 82 | 83 | public function getKeepFlat(): bool 84 | { 85 | return $this->keepFlat; 86 | } 87 | 88 | public function setKeepFlat($value): void 89 | { 90 | $this->keepFlat = $value; 91 | } 92 | 93 | public function getItemValue(): float 94 | { 95 | return (float)$this->itemValue; 96 | } 97 | 98 | public function setItemValue($value): void 99 | { 100 | $this->itemValue = $value; 101 | } 102 | 103 | public function getAllowedRotation(): \DVDoug\BoxPacker\Rotation 104 | { 105 | if ($this->keepFlat) { 106 | return \DVDoug\BoxPacker\Rotation::KeepFlat; 107 | } 108 | return \DVDoug\BoxPacker\Rotation::BestFit; 109 | } 110 | } 111 | -------------------------------------------------------------------------------- /src/carriers/PostNL.php: -------------------------------------------------------------------------------- 1 | 'Brief', 41 | 'brievenbuspakje' => 'Brievenbuspakje', 42 | 'pakket-no-track-and-trace' => 'Pakket no Track & Trace', 43 | 'pakket' => 'Pakket', 44 | 'aangetekend' => 'Aangetekend', 45 | 'verzekerservice' => 'Verzekerservice', 46 | 'betaalservice' => 'Betaalservice', 47 | ]; 48 | } 49 | 50 | public static function supportsTrackingStatus(): bool 51 | { 52 | return false; 53 | } 54 | 55 | public static function supportsLabels(): bool 56 | { 57 | return false; 58 | } 59 | 60 | 61 | // Public Methods 62 | // ========================================================================= 63 | 64 | public function getRates(Shipment $shipment): ?RateResponse 65 | { 66 | $rates = []; 67 | 68 | foreach (self::getServiceCodes() as $serviceCode => $serviceName) { 69 | if ($rate = PostNLRates::getRate($serviceCode, $this, $shipment)) { 70 | $rates[] = $rate; 71 | } 72 | } 73 | 74 | return new RateResponse([ 75 | 'rates' => $rates, 76 | ]); 77 | } 78 | 79 | /** 80 | * @throws Exception 81 | */ 82 | public function getTrackingStatus(array $trackingNumbers, array $options = []): ?TrackingResponse 83 | { 84 | throw new Exception('Not implemented.'); 85 | } 86 | 87 | /** 88 | * @throws Exception 89 | */ 90 | public function getLabels(Shipment $shipment, Rate $rate, array $options = []): ?LabelResponse 91 | { 92 | throw new Exception('Not implemented.'); 93 | } 94 | 95 | public function getHttpClient(): HttpClient 96 | { 97 | return new HttpClient(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/models/Model.php: -------------------------------------------------------------------------------- 1 | $value) { 22 | $this->__set($name, $value); 23 | } 24 | } 25 | 26 | $this->init(); 27 | } 28 | 29 | public function __get($name) 30 | { 31 | $getter = 'get' . ucfirst($name); 32 | 33 | if (method_exists($this, $getter)) { 34 | return $this->$getter(); 35 | } 36 | } 37 | 38 | public function __set($name, $value) 39 | { 40 | $setter = 'set' . ucfirst($name); 41 | 42 | if (method_exists($this, $setter)) { 43 | $this->$setter($value); 44 | } 45 | } 46 | 47 | public function __isset($name) 48 | { 49 | $getter = 'get' . ucfirst($name); 50 | 51 | if (method_exists($this, $getter)) { 52 | return $this->$getter() !== null; 53 | } 54 | 55 | return false; 56 | } 57 | 58 | public function __unset($name) 59 | { 60 | $setter = 'set' . ucfirst($name); 61 | 62 | if (method_exists($this, $setter)) { 63 | $this->$setter(null); 64 | } 65 | } 66 | 67 | public function __debugInfo() 68 | { 69 | return $this->toArray(); 70 | } 71 | 72 | public function __sleep(): array 73 | { 74 | // Ensure that any `serialize()` calls respect `toArray()`. 75 | return array_keys($this->toArray()); 76 | } 77 | 78 | public function init(): void 79 | { 80 | $this->events = new EventDispatcher(); 81 | } 82 | 83 | public function jsonSerialize() 84 | { 85 | return $this->toArray(); 86 | } 87 | 88 | public function displayName(): string 89 | { 90 | $classNameParts = explode('\\', static::class); 91 | return array_pop($classNameParts); 92 | } 93 | 94 | public function on(string $eventName, callable|array $listener, int $priority = 0): void 95 | { 96 | $this->events->addListener($eventName, $listener, $priority); 97 | } 98 | 99 | public function trigger(string $eventName, object $event): void 100 | { 101 | $this->events->dispatch($event, $eventName); 102 | } 103 | 104 | public function toArray(): array 105 | { 106 | $vars = get_object_vars($this); 107 | unset($vars['events']); 108 | 109 | return $vars; 110 | } 111 | } -------------------------------------------------------------------------------- /src/carriers/Colissimo.php: -------------------------------------------------------------------------------- 1 | 'France', 41 | 'emballage-france' => 'Emballage France', 42 | 'outremer' => 'Outre-Mer', 43 | 'europe' => 'Europe', 44 | 'economique-outremer' => 'Economique Outre-Mer', 45 | 'international' => 'International', 46 | 'emballage-international' => 'Emballage International', 47 | ]; 48 | } 49 | 50 | public static function supportsTrackingStatus(): bool 51 | { 52 | return false; 53 | } 54 | 55 | public static function supportsLabels(): bool 56 | { 57 | return false; 58 | } 59 | 60 | 61 | // Public Methods 62 | // ========================================================================= 63 | 64 | public function getRates(Shipment $shipment): ?RateResponse 65 | { 66 | $rates = []; 67 | 68 | foreach (self::getServiceCodes() as $serviceCode => $serviceName) { 69 | if ($rate = ColissimoRates::getRate($serviceCode, $this, $shipment)) { 70 | $rates[] = $rate; 71 | } 72 | } 73 | 74 | return new RateResponse([ 75 | 'rates' => $rates, 76 | ]); 77 | } 78 | 79 | /** 80 | * @throws Exception 81 | */ 82 | public function getTrackingStatus(array $trackingNumbers, array $options = []): ?TrackingResponse 83 | { 84 | throw new Exception('Not implemented.'); 85 | } 86 | 87 | /** 88 | * @throws Exception 89 | */ 90 | public function getLabels(Shipment $shipment, Rate $rate, array $options = []): ?LabelResponse 91 | { 92 | throw new Exception('Not implemented.'); 93 | } 94 | 95 | public function getHttpClient(): HttpClient 96 | { 97 | return new HttpClient(); 98 | } 99 | } 100 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/ParcelforceIrelandexpress.php: -------------------------------------------------------------------------------- 1 | [ 21 | '5' => [ 22 | 500 => 2754, 23 | 1000 => 2754, 24 | 1500 => 2754, 25 | 2000 => 2754, 26 | 2500 => 2754, 27 | 3000 => 2754, 28 | 3500 => 2754, 29 | 4000 => 2754, 30 | 4500 => 2754, 31 | 5000 => 2754, 32 | 5500 => 2886, 33 | 6000 => 3018, 34 | 6500 => 3150, 35 | 7000 => 3282, 36 | 7500 => 3414, 37 | 8000 => 3546, 38 | 8500 => 3678, 39 | 9000 => 3810, 40 | 9500 => 3942, 41 | 10000 => 4074, 42 | 10500 => 4158, 43 | 11000 => 4242, 44 | 11500 => 4326, 45 | 12000 => 4410, 46 | 12500 => 4494, 47 | 13000 => 4578, 48 | 13500 => 4662, 49 | 14000 => 4746, 50 | 14500 => 4830, 51 | 15000 => 4914, 52 | 15500 => 5022, 53 | 16000 => 5130, 54 | 16500 => 5238, 55 | 17000 => 5346, 56 | 17500 => 5454, 57 | 18000 => 5562, 58 | 18500 => 5670, 59 | 19000 => 5778, 60 | 19500 => 5886, 61 | 20000 => 5994, 62 | 20500 => 6102, 63 | 21000 => 6210, 64 | 21500 => 6318, 65 | 22000 => 6426, 66 | 22500 => 6534, 67 | 23000 => 6642, 68 | 23500 => 6750, 69 | 24000 => 6858, 70 | 24500 => 6966, 71 | 25000 => 7074, 72 | 25500 => 7182, 73 | 26000 => 7290, 74 | 26500 => 7398, 75 | 27000 => 7506, 76 | 27500 => 7614, 77 | 28000 => 7722, 78 | 28500 => 7830, 79 | 29000 => 7938, 80 | 29500 => 8046, 81 | 30000 => 8154, 82 | ], 83 | ], 84 | ]; 85 | 86 | return self::getParcelforceBoxPricing($bands, $countryCode, [ 87 | 'maximumInclusiveCompensation' => 200, 88 | 'maximumTotalCover' => 2500, 89 | ]); 90 | } 91 | } 92 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/SpecialDelivery9am.php: -------------------------------------------------------------------------------- 1 | [ 31 | 'packet-50' => [ 32 | 100 => 3195, 33 | 500 => 3695, 34 | 1000 => 4195, 35 | 2000 => 5295, 36 | ], 37 | 'packet-1000' => [ 38 | 100 => 3895, 39 | 500 => 4395, 40 | 1000 => 4895, 41 | 2000 => 5995, 42 | ], 43 | 'packet-2500' => [ 44 | 100 => 4695, 45 | 500 => 5195, 46 | 1000 => 5695, 47 | 2000 => 6795, 48 | ], 49 | ], 50 | '2025' => [ 51 | 'packet-50' => [ 52 | 100 => 3895, 53 | 500 => 4395, 54 | 1000 => 4895, 55 | 2000 => 6095, 56 | ], 57 | 'packet-1000' => [ 58 | 100 => 4595, 59 | 500 => 5095, 60 | 1000 => 5595, 61 | 2000 => 6795, 62 | ], 63 | 'packet-2500' => [ 64 | 100 => 5395, 65 | 500 => 5895, 66 | 1000 => 6395, 67 | 2000 => 7595, 68 | ], 69 | ], 70 | ]; 71 | 72 | $boxes = [ 73 | 'packet-50' => [ 74 | 'length' => 610, 75 | 'width' => 460, 76 | 'height' => 460, 77 | 'weight' => 2000, 78 | ], 79 | 'packet-1000' => [ 80 | 'length' => 610, 81 | 'width' => 460, 82 | 'height' => 460, 83 | 'weight' => 2000, 84 | ], 85 | 'packet-2500' => [ 86 | 'length' => 610, 87 | 'width' => 460, 88 | 'height' => 460, 89 | 'weight' => 2000, 90 | ], 91 | ]; 92 | 93 | $boxPricing = self::getBoxPricing($boxes, $bands); 94 | 95 | foreach ($boxPricing as $key => $box) { 96 | // 20% VAT 97 | if (!self::$includeVat) { 98 | $boxPricing[$key]['price'] = $box['price'] / 1.2; 99 | } 100 | } 101 | 102 | return $boxPricing; 103 | } 104 | } 105 | -------------------------------------------------------------------------------- /src/models/StaticRates.php: -------------------------------------------------------------------------------- 1 | $b['price']; 22 | }); 23 | 24 | // For each package, find the cheapest box that fits. We'll use that price for the rate for each package. 25 | foreach ($shipment->getPackages() as $package) { 26 | foreach ($boxRates as $name => $boxRate) { 27 | $box = new PackageBox([ 28 | 'reference' => $name, 29 | 'outerWidth' => $boxRate['width'], 30 | 'outerLength' => $boxRate['length'], 31 | 'outerDepth' => $boxRate['height'], 32 | 'emptyWeight' => 0, 33 | 'innerWidth' => $boxRate['width'], 34 | 'innerLength' => $boxRate['length'], 35 | 'innerDepth' => $boxRate['height'], 36 | 'maxWeight' => $boxRate['weight'], 37 | 'price' => $boxRate['price'], 38 | 'currency' => $boxRate['currency'] ?? null, 39 | 'maxItemValue' => $boxRate['itemValue'] ?? null, 40 | ]); 41 | 42 | // Allow the boxes currency to set the overall rate currency 43 | $currency = $boxRate['currency'] ?? null; 44 | 45 | $items = new ItemList(); 46 | 47 | $items->insert(new PackageItem([ 48 | 'width' => $package->getWidth(), 49 | 'length' => $package->getLength(), 50 | 'depth' => $package->getHeight(), 51 | 'weight' => $package->getWeight(), 52 | 'itemValue' => $package->getPrice(), 53 | 'keepFlat' => false, 54 | ])); 55 | 56 | $volumePacker = new VolumePacker($box, $items); 57 | $packedBox = $volumePacker->pack(); 58 | 59 | if ($packedBox->getItems()->count()) { 60 | // Accumulate the price of each box from the carrier to handle multiple packages. 61 | $rate += $packedBox->getBox()->getPrice(); 62 | 63 | // Quit looking through boxes that are suitable, we've got one. 64 | break; 65 | } 66 | } 67 | } 68 | 69 | if (!$rate) { 70 | return null; 71 | } 72 | 73 | return new Rate([ 74 | 'carrier' => $carrier, 75 | 'serviceName' => Arr::get($carrier::getServiceCodes(), $serviceCode, ''), 76 | 'serviceCode' => $serviceCode, 77 | 'rate' => $rate, 78 | 'currency' => $currency, 79 | ]); 80 | } 81 | 82 | } 83 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/SpecialDelivery1pm.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-750' => [ 22 | 100 => 775, 23 | 500 => 875, 24 | 1000 => 975, 25 | 2000 => 1275, 26 | 10000 => 1735, 27 | 20000 => 2135, 28 | ], 29 | 'packet-1000' => [ 30 | 100 => 1075, 31 | 500 => 1175, 32 | 1000 => 1275, 33 | 2000 => 1575, 34 | 10000 => 2035, 35 | 20000 => 2435, 36 | ], 37 | 'packet-2500' => [ 38 | 100 => 1775, 39 | 500 => 1875, 40 | 1000 => 1975, 41 | 2000 => 2275, 42 | 10000 => 2735, 43 | 20000 => 3135, 44 | ], 45 | ], 46 | '2025' => [ 47 | 'packet-750' => [ 48 | 100 => 815, 49 | 500 => 925, 50 | 1000 => 1035, 51 | 2000 => 1345, 52 | 10000 => 1835, 53 | 20000 => 2255, 54 | ], 55 | 'packet-1000' => [ 56 | 100 => 1115, 57 | 500 => 1225, 58 | 1000 => 1335, 59 | 2000 => 1645, 60 | 10000 => 2135, 61 | 20000 => 2555, 62 | ], 63 | 'packet-2500' => [ 64 | 100 => 1815, 65 | 500 => 1925, 66 | 1000 => 2035, 67 | 2000 => 2345, 68 | 10000 => 2835, 69 | 20000 => 3255, 70 | ], 71 | ], 72 | ]; 73 | 74 | $boxes = [ 75 | 'packet-750' => [ 76 | 'length' => 610, 77 | 'width' => 460, 78 | 'height' => 460, 79 | 'weight' => 20000, 80 | 'itemValue' => 750, 81 | ], 82 | 'packet-1000' => [ 83 | 'length' => 610, 84 | 'width' => 460, 85 | 'height' => 460, 86 | 'weight' => 20000, 87 | 'itemValue' => 1000, 88 | ], 89 | 'packet-2500' => [ 90 | 'length' => 610, 91 | 'width' => 460, 92 | 'height' => 460, 93 | 'weight' => 20000, 94 | 'itemValue' => 2500, 95 | ], 96 | ]; 97 | 98 | return self::getBoxPricing($boxes, $bands); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/SpecialDelivery1pm.php: -------------------------------------------------------------------------------- 1 | [ 21 | 'packet-750' => [ 22 | 100 => 835, 23 | 500 => 935, 24 | 1000 => 1035, 25 | 2000 => 1335, 26 | 10000 => 1855, 27 | 20000 => 2255, 28 | ], 29 | 'packet-1000' => [ 30 | 100 => 1135, 31 | 500 => 1235, 32 | 1000 => 1335, 33 | 2000 => 1635, 34 | 10000 => 2155, 35 | 20000 => 2555, 36 | ], 37 | 'packet-2500' => [ 38 | 100 => 1835, 39 | 500 => 1935, 40 | 1000 => 2035, 41 | 2000 => 2335, 42 | 10000 => 2855, 43 | 20000 => 3255, 44 | ], 45 | ], 46 | '2025' => [ 47 | 'packet-750' => [ 48 | 100 => 875, 49 | 500 => 985, 50 | 1000 => 1095, 51 | 2000 => 1405, 52 | 10000 => 1955, 53 | 20000 => 2375, 54 | ], 55 | 'packet-1000' => [ 56 | 100 => 1175, 57 | 500 => 1285, 58 | 1000 => 1395, 59 | 2000 => 1705, 60 | 10000 => 2255, 61 | 20000 => 2675, 62 | ], 63 | 'packet-2500' => [ 64 | 100 => 1875, 65 | 500 => 1985, 66 | 1000 => 2095, 67 | 2000 => 2405, 68 | 10000 => 2955, 69 | 20000 => 3375, 70 | ], 71 | ], 72 | ]; 73 | 74 | $boxes = [ 75 | 'packet-750' => [ 76 | 'length' => 610, 77 | 'width' => 460, 78 | 'height' => 460, 79 | 'weight' => 20000, 80 | 'itemValue' => 750, 81 | ], 82 | 'packet-1000' => [ 83 | 'length' => 610, 84 | 'width' => 460, 85 | 'height' => 460, 86 | 'weight' => 20000, 87 | 'itemValue' => 1000, 88 | ], 89 | 'packet-2500' => [ 90 | 'length' => 610, 91 | 'width' => 460, 92 | 'height' => 460, 93 | 'weight' => 20000, 94 | 'itemValue' => 2500, 95 | ], 96 | ]; 97 | 98 | return self::getBoxPricing($boxes, $bands); 99 | } 100 | } 101 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/Tracked24.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LARGE_LETTER => [ 22 | 750 => 350, 23 | ], 24 | self::SMALL_PARCEL_WIDE => [ 25 | 2000 => 425, 26 | ], 27 | self::SMALL_PARCEL_DEEP => [ 28 | 2000 => 425, 29 | ], 30 | self::SMALL_PARCEL_BIGGER => [ 31 | 2000 => 425, 32 | ], 33 | self::MEDIUM_PARCEL => [ 34 | 2000 => 599, 35 | 10000 => 769, 36 | 20000 => 1219, 37 | ], 38 | self::TUBE => [ 39 | 2000 => 599, 40 | 10000 => 769, 41 | 20000 => 1219, 42 | ], 43 | ], 44 | '2025' => [ 45 | self::LARGE_LETTER => [ 46 | 750 => 360, 47 | ], 48 | self::SMALL_PARCEL_WIDE => [ 49 | 2000 => 429, 50 | ], 51 | self::SMALL_PARCEL_DEEP => [ 52 | 2000 => 429, 53 | ], 54 | self::SMALL_PARCEL_BIGGER => [ 55 | 2000 => 429, 56 | ], 57 | self::MEDIUM_PARCEL => [ 58 | 2000 => 605, 59 | 10000 => 790, 60 | 20000 => 1260, 61 | ], 62 | self::TUBE => [ 63 | 2000 => 605, 64 | 10000 => 790, 65 | 20000 => 1260, 66 | ], 67 | ], 68 | ]; 69 | 70 | $boxes = [ 71 | self::LARGE_LETTER => [ 72 | 'length' => 353, 73 | 'width' => 250, 74 | 'height' => 25, 75 | 'weight' => 750, 76 | ], 77 | self::SMALL_PARCEL_WIDE => [ 78 | 'length' => 450, 79 | 'width' => 350, 80 | 'height' => 160, 81 | 'weight' => 2000, 82 | ], 83 | self::SMALL_PARCEL_DEEP => [ 84 | 'length' => 350, 85 | 'width' => 250, 86 | 'height' => 160, 87 | 'weight' => 2000, 88 | ], 89 | self::SMALL_PARCEL_BIGGER => [ 90 | 'length' => 450, 91 | 'width' => 350, 92 | 'height' => 160, 93 | 'weight' => 2000, 94 | ], 95 | self::MEDIUM_PARCEL => [ 96 | 'length' => 610, 97 | 'width' => 460, 98 | 'height' => 460, 99 | 'weight' => 20000, 100 | ], 101 | self::TUBE => [ 102 | 'length' => 900, 103 | 'width' => 70, 104 | 'height' => 70, 105 | 'weight' => 2000, 106 | ], 107 | ]; 108 | 109 | return self::getBoxPricing($boxes, $bands, 150); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/Tracked48.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LARGE_LETTER => [ 22 | 750 => 270, 23 | ], 24 | self::SMALL_PARCEL_WIDE => [ 25 | 2000 => 339, 26 | ], 27 | self::SMALL_PARCEL_DEEP => [ 28 | 2000 => 339, 29 | ], 30 | self::SMALL_PARCEL_BIGGER => [ 31 | 2000 => 339, 32 | ], 33 | self::MEDIUM_PARCEL => [ 34 | 2000 => 515, 35 | 10000 => 665, 36 | 20000 => 1055, 37 | ], 38 | self::TUBE => [ 39 | 2000 => 515, 40 | 10000 => 665, 41 | 20000 => 1055, 42 | ], 43 | ], 44 | '2025' => [ 45 | self::LARGE_LETTER => [ 46 | 750 => 270, 47 | ], 48 | self::SMALL_PARCEL_WIDE => [ 49 | 2000 => 345, 50 | ], 51 | self::SMALL_PARCEL_DEEP => [ 52 | 2000 => 345, 53 | ], 54 | self::SMALL_PARCEL_BIGGER => [ 55 | 2000 => 345, 56 | ], 57 | self::MEDIUM_PARCEL => [ 58 | 2000 => 515, 59 | 10000 => 680, 60 | 20000 => 1080, 61 | ], 62 | self::TUBE => [ 63 | 2000 => 515, 64 | 10000 => 680, 65 | 20000 => 1080, 66 | ], 67 | ], 68 | ]; 69 | 70 | $boxes = [ 71 | self::LARGE_LETTER => [ 72 | 'length' => 353, 73 | 'width' => 250, 74 | 'height' => 25, 75 | 'weight' => 750, 76 | ], 77 | self::SMALL_PARCEL_WIDE => [ 78 | 'length' => 450, 79 | 'width' => 350, 80 | 'height' => 160, 81 | 'weight' => 2000, 82 | ], 83 | self::SMALL_PARCEL_DEEP => [ 84 | 'length' => 350, 85 | 'width' => 250, 86 | 'height' => 160, 87 | 'weight' => 2000, 88 | ], 89 | self::SMALL_PARCEL_BIGGER => [ 90 | 'length' => 450, 91 | 'width' => 350, 92 | 'height' => 160, 93 | 'weight' => 2000, 94 | ], 95 | self::MEDIUM_PARCEL => [ 96 | 'length' => 610, 97 | 'width' => 460, 98 | 'height' => 460, 99 | 'weight' => 20000, 100 | ], 101 | self::TUBE => [ 102 | 'length' => 900, 103 | 'width' => 70, 104 | 'height' => 70, 105 | 'weight' => 2000, 106 | ], 107 | ]; 108 | 109 | return self::getBoxPricing($boxes, $bands, 150); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/Tracked24.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LARGE_LETTER => [ 22 | 750 => 360, 23 | ], 24 | self::SMALL_PARCEL_WIDE => [ 25 | 2000 => 499, 26 | ], 27 | self::SMALL_PARCEL_DEEP => [ 28 | 2000 => 499, 29 | ], 30 | self::SMALL_PARCEL_BIGGER => [ 31 | 2000 => 499, 32 | ], 33 | self::MEDIUM_PARCEL => [ 34 | 2000 => 729, 35 | 10000 => 899, 36 | 20000 => 1349, 37 | ], 38 | self::TUBE => [ 39 | 2000 => 729, 40 | 10000 => 899, 41 | 20000 => 1349, 42 | ], 43 | ], 44 | '2025' => [ 45 | self::LARGE_LETTER => [ 46 | 750 => 370, 47 | ], 48 | self::SMALL_PARCEL_WIDE => [ 49 | 2000 => 515, 50 | ], 51 | self::SMALL_PARCEL_DEEP => [ 52 | 2000 => 515, 53 | ], 54 | self::SMALL_PARCEL_BIGGER => [ 55 | 2000 => 515, 56 | ], 57 | self::MEDIUM_PARCEL => [ 58 | 2000 => 745, 59 | 10000 => 929, 60 | 20000 => 1399, 61 | ], 62 | self::TUBE => [ 63 | 2000 => 745, 64 | 10000 => 929, 65 | 20000 => 1399, 66 | ], 67 | ], 68 | ]; 69 | 70 | $boxes = [ 71 | self::LARGE_LETTER => [ 72 | 'length' => 353, 73 | 'width' => 250, 74 | 'height' => 25, 75 | 'weight' => 750, 76 | ], 77 | self::SMALL_PARCEL_WIDE => [ 78 | 'length' => 450, 79 | 'width' => 350, 80 | 'height' => 160, 81 | 'weight' => 2000, 82 | ], 83 | self::SMALL_PARCEL_DEEP => [ 84 | 'length' => 350, 85 | 'width' => 250, 86 | 'height' => 160, 87 | 'weight' => 2000, 88 | ], 89 | self::SMALL_PARCEL_BIGGER => [ 90 | 'length' => 450, 91 | 'width' => 350, 92 | 'height' => 160, 93 | 'weight' => 2000, 94 | ], 95 | self::MEDIUM_PARCEL => [ 96 | 'length' => 610, 97 | 'width' => 460, 98 | 'height' => 460, 99 | 'weight' => 20000, 100 | ], 101 | self::TUBE => [ 102 | 'length' => 900, 103 | 'width' => 70, 104 | 'height' => 70, 105 | 'weight' => 2000, 106 | ], 107 | ]; 108 | 109 | return self::getBoxPricing($boxes, $bands, 100); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/Tracked48.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LARGE_LETTER => [ 22 | 750 => 280, 23 | ], 24 | self::SMALL_PARCEL_WIDE => [ 25 | 2000 => 395, 26 | ], 27 | self::SMALL_PARCEL_DEEP => [ 28 | 2000 => 395, 29 | ], 30 | self::SMALL_PARCEL_BIGGER => [ 31 | 2000 => 395, 32 | ], 33 | self::MEDIUM_PARCEL => [ 34 | 2000 => 645, 35 | 10000 => 795, 36 | 20000 => 1185, 37 | ], 38 | self::TUBE => [ 39 | 2000 => 645, 40 | 10000 => 795, 41 | 20000 => 1185, 42 | ], 43 | ], 44 | '2025' => [ 45 | self::LARGE_LETTER => [ 46 | 750 => 280, 47 | ], 48 | self::SMALL_PARCEL_WIDE => [ 49 | 2000 => 405, 50 | ], 51 | self::SMALL_PARCEL_DEEP => [ 52 | 2000 => 405, 53 | ], 54 | self::SMALL_PARCEL_BIGGER => [ 55 | 2000 => 405, 56 | ], 57 | self::MEDIUM_PARCEL => [ 58 | 2000 => 655, 59 | 10000 => 819, 60 | 20000 => 1219, 61 | ], 62 | self::TUBE => [ 63 | 2000 => 655, 64 | 10000 => 819, 65 | 20000 => 1219, 66 | ], 67 | ], 68 | ]; 69 | 70 | $boxes = [ 71 | self::LARGE_LETTER => [ 72 | 'length' => 353, 73 | 'width' => 250, 74 | 'height' => 25, 75 | 'weight' => 750, 76 | ], 77 | self::SMALL_PARCEL_WIDE => [ 78 | 'length' => 450, 79 | 'width' => 350, 80 | 'height' => 160, 81 | 'weight' => 2000, 82 | ], 83 | self::SMALL_PARCEL_DEEP => [ 84 | 'length' => 350, 85 | 'width' => 250, 86 | 'height' => 160, 87 | 'weight' => 2000, 88 | ], 89 | self::SMALL_PARCEL_BIGGER => [ 90 | 'length' => 450, 91 | 'width' => 350, 92 | 'height' => 160, 93 | 'weight' => 2000, 94 | ], 95 | self::MEDIUM_PARCEL => [ 96 | 'length' => 610, 97 | 'width' => 460, 98 | 'height' => 460, 99 | 'weight' => 20000, 100 | ], 101 | self::TUBE => [ 102 | 'length' => 900, 103 | 'width' => 70, 104 | 'height' => 70, 105 | 'weight' => 2000, 106 | ], 107 | ]; 108 | 109 | return self::getBoxPricing($boxes, $bands, 100); 110 | } 111 | } 112 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/InternationalTracked.php: -------------------------------------------------------------------------------- 1 | [ 27 | self::LETTER => [ 28 | 100 => [790, 790, 790, 790, 790, 790], 29 | ], 30 | self::LARGE_LETTER => [ 31 | 100 => [950, 950, 950, 1055, 1060, 1060], 32 | 250 => [1050, 1050, 1050, 1215, 1335, 1240], 33 | 500 => [1160, 1160, 1160, 1420, 1615, 1450], 34 | 750 => [1205, 1205, 1205, 1625, 1925, 1670], 35 | ], 36 | self::PACKET => [ 37 | 250 => [1205, 1240, 1325, 1525, 1670, 1720], 38 | 500 => [1335, 1370, 1500, 1970, 2180, 2185], 39 | 750 => [1435, 1475, 1595, 2240, 2485, 2470], 40 | 1000 => [1500, 1545, 1670, 2530, 2810, 2765], 41 | 1250 => [1550, 1590, 1755, 2745, 3120, 3185], 42 | 1500 => [1550, 1590, 1845, 2900, 3395, 3185], 43 | 2000 => [1550, 1745, 1920, 3020, 3580, 3185], 44 | ], 45 | self::PRINTED_PAPERS => [ 46 | 250 => [1205, 1240, 1325, 1525, 1670, 1720], 47 | 500 => [1335, 1370, 1500, 1970, 2180, 2185], 48 | 750 => [1435, 1475, 1595, 2240, 2485, 2470], 49 | 1000 => [1500, 1545, 1670, 2530, 2810, 2765], 50 | 1250 => [1550, 1590, 1755, 2745, 3120, 3185], 51 | 1500 => [1550, 1590, 1845, 2900, 3395, 3185], 52 | 2000 => [1550, 1745, 1920, 3020, 3580, 3185], 53 | ], 54 | ], 55 | '2025' => [ 56 | self::LETTER => [ 57 | 100 => [810, 810, 810, 810, 810, 810], 58 | ], 59 | self::LARGE_LETTER => [ 60 | 100 => [975, 975, 975, 1080, 1085, 1070], 61 | 250 => [1075, 1075, 1075, 1245, 1370, 1250], 62 | 500 => [1190, 1190, 1190, 1455, 1655, 1465], 63 | 750 => [1235, 1235, 1235, 1665, 1975, 1690], 64 | ], 65 | self::PACKET => [ 66 | 250 => [1240, 1270, 1390, 1600, 1755, 1685], 67 | 500 => [1370, 1405, 1575, 2070, 2290, 2185], 68 | 750 => [1425, 1510, 1675, 2350, 2610, 2495], 69 | 1000 => [1500, 1585, 1755, 2655, 2950, 2805], 70 | 1250 => [1550, 1630, 1845, 2880, 3275, 3235], 71 | 1500 => [1550, 1630, 1935, 3045, 3565, 3235], 72 | 2000 => [1550, 1790, 2015, 3170, 3760, 3235], 73 | ], 74 | ], 75 | ]; 76 | 77 | return self::getInternationalBoxPricing($bands, $countryCode); 78 | } 79 | } 80 | -------------------------------------------------------------------------------- /src/models/Rate.php: -------------------------------------------------------------------------------- 1 | carrier; 30 | } 31 | 32 | public function setCarrier(CarrierInterface $carrier): Rate 33 | { 34 | $this->carrier = $carrier; 35 | return $this; 36 | } 37 | 38 | public function getServiceName(): ?string 39 | { 40 | return $this->serviceName; 41 | } 42 | 43 | public function setServiceName(?string $serviceName): Rate 44 | { 45 | $this->serviceName = $serviceName; 46 | return $this; 47 | } 48 | 49 | public function getServiceCode(): ?string 50 | { 51 | return $this->serviceCode; 52 | } 53 | 54 | public function setServiceCode(?string $serviceCode): Rate 55 | { 56 | $this->serviceCode = $serviceCode; 57 | return $this; 58 | } 59 | 60 | public function getRate(): ?string 61 | { 62 | return $this->rate; 63 | } 64 | 65 | public function setRate(?string $rate): Rate 66 | { 67 | $this->rate = $rate; 68 | return $this; 69 | } 70 | 71 | public function getCurrency(): ?string 72 | { 73 | return $this->currency; 74 | } 75 | 76 | public function setCurrency(?string $currency): Rate 77 | { 78 | $this->currency = $currency; 79 | return $this; 80 | } 81 | 82 | public function getDeliveryDays(): ?int 83 | { 84 | return $this->deliveryDays; 85 | } 86 | 87 | public function setDeliveryDays(?int $deliveryDays): Rate 88 | { 89 | $this->deliveryDays = $deliveryDays; 90 | return $this; 91 | } 92 | 93 | public function getDeliveryDate(): ?DateTime 94 | { 95 | return $this->deliveryDate; 96 | } 97 | 98 | public function setDeliveryDate(DateTime|string|null $deliveryDate): Rate 99 | { 100 | $this->deliveryDate = DateTimeHelper::toDateTime($deliveryDate); 101 | return $this; 102 | } 103 | 104 | public function getDeliveryDateGuaranteed(): ?bool 105 | { 106 | return $this->deliveryDateGuaranteed; 107 | } 108 | 109 | public function setDeliveryDateGuaranteed(?bool $deliveryDateGuaranteed): Rate 110 | { 111 | $this->deliveryDateGuaranteed = $deliveryDateGuaranteed; 112 | return $this; 113 | } 114 | 115 | public function getResponse(): array 116 | { 117 | return $this->response; 118 | } 119 | 120 | public function setResponse(array $response): Rate 121 | { 122 | $this->response = $response; 123 | return $this; 124 | } 125 | 126 | public function toArray(): array 127 | { 128 | // Remove debug/info attributes 129 | $vars = parent::toArray(); 130 | unset($vars['carrier'], $vars['response']); 131 | 132 | return $vars; 133 | } 134 | } 135 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/FirstClass.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 165, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 250, 26 | 750 => 330, 27 | ], 28 | self::SMALL_PARCEL_WIDE => [ 29 | 2000 => 409, 30 | ], 31 | self::SMALL_PARCEL_DEEP => [ 32 | 2000 => 409, 33 | ], 34 | self::SMALL_PARCEL_BIGGER => [ 35 | 2000 => 409, 36 | ], 37 | self::MEDIUM_PARCEL => [ 38 | 2000 => 569, 39 | 10000 => 739, 40 | 20000 => 1189, 41 | ], 42 | ], 43 | '2025' => [ 44 | self::LETTER => [ 45 | 100 => 170, 46 | ], 47 | self::LARGE_LETTER => [ 48 | 100 => 305, 49 | 750 => 330, 50 | ], 51 | self::SMALL_PARCEL_WIDE => [ 52 | 2000 => 419, 53 | ], 54 | self::SMALL_PARCEL_DEEP => [ 55 | 2000 => 419, 56 | ], 57 | self::SMALL_PARCEL_BIGGER => [ 58 | 2000 => 419, 59 | ], 60 | self::MEDIUM_PARCEL => [ 61 | 2000 => 585, 62 | 10000 => 765, 63 | 20000 => 1235, 64 | ], 65 | ], 66 | ]; 67 | 68 | $boxes = [ 69 | self::LETTER => [ 70 | 'length' => 240, 71 | 'width' => 165, 72 | 'height' => 5, 73 | 'weight' => 100, 74 | ], 75 | self::LARGE_LETTER => [ 76 | 'length' => 353, 77 | 'width' => 250, 78 | 'height' => 25, 79 | 'weight' => 750, 80 | ], 81 | self::SMALL_PARCEL_WIDE => [ 82 | 'length' => 450, 83 | 'width' => 350, 84 | 'height' => 160, 85 | 'weight' => 2000, 86 | ], 87 | self::SMALL_PARCEL_DEEP => [ 88 | 'length' => 350, 89 | 'width' => 250, 90 | 'height' => 160, 91 | 'weight' => 2000, 92 | ], 93 | self::SMALL_PARCEL_BIGGER => [ 94 | 'length' => 450, 95 | 'width' => 350, 96 | 'height' => 160, 97 | 'weight' => 2000, 98 | ], 99 | self::MEDIUM_PARCEL => [ 100 | 'length' => 610, 101 | 'width' => 460, 102 | 'height' => 460, 103 | 'weight' => 20000, 104 | ], 105 | self::TUBE => [ 106 | 'length' => 900, 107 | 'width' => 70, 108 | 'height' => 70, 109 | 'weight' => 2000, 110 | ], 111 | ]; 112 | 113 | return self::getBoxPricing($boxes, $bands, 20); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/InternationalSigned.php: -------------------------------------------------------------------------------- 1 | [ 27 | self::LETTER => [ 28 | 100 => [815, 815, 815, 815, 815], 29 | ], 30 | self::LARGE_LETTER => [ 31 | 100 => [965, 965, 965, 1065, 1080], 32 | 250 => [1020, 1020, 1020, 1160, 1280], 33 | 500 => [1100, 1100, 1100, 1360, 1560], 34 | 750 => [1145, 1145, 1145, 1565, 1865], 35 | ], 36 | self::PACKET => [ 37 | 100 => [1015, 970, 1095, 1540, 1330], 38 | 250 => [1015, 970, 1095, 1575, 1365], 39 | 500 => [1135, 1125, 1250, 1665, 1815], 40 | 750 => [1240, 1225, 1365, 1905, 2095], 41 | 1000 => [1335, 1315, 1490, 2170, 2410], 42 | 1250 => [1390, 1345, 1645, 2370, 2705], 43 | 1500 => [1400, 1370, 1755, 2550, 3005], 44 | 2000 => [1415, 1415, 2135, 2655, 3210], 45 | ], 46 | ], 47 | '2025' => [ 48 | self::LETTER => [ 49 | 100 => [850, 850, 850, 850, 850], 50 | ], 51 | self::LARGE_LETTER => [ 52 | 100 => [995, 995, 995, 1100, 1115], 53 | 250 => [1040, 1040, 1040, 1185, 1305], 54 | 500 => [1120, 1120, 1120, 1385, 1590], 55 | 750 => [1170, 1170, 1170, 1595, 1900], 56 | ], 57 | self::PACKET => [ 58 | 100 => [1065, 1020, 1150, 1615, 1395], 59 | 250 => [1065, 1020, 1150, 1655, 1435], 60 | 500 => [1190, 1180, 1315, 1750, 1905], 61 | 750 => [1300, 1285, 1435, 2000, 2200], 62 | 1000 => [1400, 1380, 1565, 2280, 2530], 63 | 1250 => [1460, 1410, 1725, 2490, 2840], 64 | 1500 => [1470, 1440, 1845, 2675, 3155], 65 | 2000 => [1485, 1485, 2240, 2790, 3370], 66 | ], 67 | ], 68 | ]; 69 | 70 | return self::getInternationalBoxPricing($bands, $countryCode); 71 | } 72 | } 73 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/FirstClass.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 165, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 260, 26 | 750 => 350, 27 | ], 28 | self::SMALL_PARCEL_WIDE => [ 29 | 2000 => 479, 30 | ], 31 | self::SMALL_PARCEL_DEEP => [ 32 | 2000 => 479, 33 | ], 34 | self::SMALL_PARCEL_BIGGER => [ 35 | 2000 => 479, 36 | ], 37 | self::MEDIUM_PARCEL => [ 38 | 2000 => 699, 39 | 10000 => 869, 40 | 20000 => 1319, 41 | ], 42 | ], 43 | '2025' => [ 44 | self::LETTER => [ 45 | 100 => 170, 46 | ], 47 | self::LARGE_LETTER => [ 48 | 100 => 315, 49 | 750 => 360, 50 | ], 51 | self::SMALL_PARCEL_WIDE => [ 52 | 2000 => 499, 53 | ], 54 | self::SMALL_PARCEL_DEEP => [ 55 | 2000 => 499, 56 | ], 57 | self::SMALL_PARCEL_BIGGER => [ 58 | 2000 => 499, 59 | ], 60 | self::MEDIUM_PARCEL => [ 61 | 2000 => 719, 62 | 10000 => 899, 63 | 20000 => 1369, 64 | ], 65 | ], 66 | ]; 67 | 68 | $boxes = [ 69 | self::LETTER => [ 70 | 'length' => 240, 71 | 'width' => 165, 72 | 'height' => 5, 73 | 'weight' => 100, 74 | ], 75 | self::LARGE_LETTER => [ 76 | 'length' => 353, 77 | 'width' => 250, 78 | 'height' => 25, 79 | 'weight' => 750, 80 | ], 81 | self::SMALL_PARCEL_WIDE => [ 82 | 'length' => 450, 83 | 'width' => 350, 84 | 'height' => 160, 85 | 'weight' => 2000, 86 | ], 87 | self::SMALL_PARCEL_DEEP => [ 88 | 'length' => 350, 89 | 'width' => 250, 90 | 'height' => 160, 91 | 'weight' => 2000, 92 | ], 93 | self::SMALL_PARCEL_BIGGER => [ 94 | 'length' => 450, 95 | 'width' => 350, 96 | 'height' => 160, 97 | 'weight' => 2000, 98 | ], 99 | self::MEDIUM_PARCEL => [ 100 | 'length' => 610, 101 | 'width' => 460, 102 | 'height' => 460, 103 | 'weight' => 20000, 104 | ], 105 | self::TUBE => [ 106 | 'length' => 900, 107 | 'width' => 70, 108 | 'height' => 70, 109 | 'weight' => 2000, 110 | ], 111 | ]; 112 | 113 | return self::getBoxPricing($boxes, $bands, 20); 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/rates/colissimo/FrEmballageFrance.php: -------------------------------------------------------------------------------- 1 | [ 15 | 'length' => 180, 16 | 'width' => 230, 17 | 'height' => 20, 18 | 'weight' => 1000, 19 | 'price' => [ 20 | self::ZONE_FR => 1000, 21 | ], 22 | ], 23 | 'bubble-bag-S' => [ 24 | 'length' => 290, 25 | 'width' => 330, 26 | 'height' => 20, 27 | 'weight' => 3000, 28 | 'price' => [ 29 | self::ZONE_FR => 1000, 30 | ], 31 | ], 32 | 'cardboard-sleeve-XS' => [ 33 | 'length' => 220, 34 | 'width' => 140, 35 | 'height' => 50, 36 | 'weight' => 1000, 37 | 'price' => [ 38 | self::ZONE_FR => 1000, 39 | ], 40 | ], 41 | 'cardboard-sleeve-S' => [ 42 | 'length' => 335, 43 | 'width' => 215, 44 | 'height' => 60, 45 | 'weight' => 3000, 46 | 'price' => [ 47 | self::ZONE_FR => 1000, 48 | ], 49 | ], 50 | 'box-S' => [ 51 | 'length' => 280, 52 | 'width' => 210, 53 | 'height' => 20, 54 | 'weight' => 1000, 55 | 'price' => [ 56 | self::ZONE_FR => 895, 57 | ], 58 | ], 59 | 'box-M' => [ 60 | 'length' => 230, 61 | 'width' => 130, 62 | 'height' => 100, 63 | 'weight' => 3000, 64 | 'price' => [ 65 | self::ZONE_FR => 800, 66 | ], 67 | ], 68 | 'box-L' => [ 69 | 'length' => 315, 70 | 'width' => 210, 71 | 'height' => 157, 72 | 'weight' => 5000, 73 | 'price' => [ 74 | self::ZONE_FR => 1200, 75 | ], 76 | ], 77 | 'CD' => [ 78 | 'length' => 217, 79 | 'width' => 140, 80 | 'height' => 60, 81 | 'weight' => 1000, 82 | 'price' => [ 83 | self::ZONE_FR => 790, 84 | ], 85 | ], 86 | '1-Bottle' => [ 87 | 'length' => 390, 88 | 'width' => 168, 89 | 'height' => 104, 90 | 'weight' => 2000, 91 | 'price' => [ 92 | self::ZONE_FR => 1110, 93 | ], 94 | ], 95 | '2-Bottles' => [ 96 | 'length' => 390, 97 | 'width' => 297, 98 | 'height' => 106, 99 | 'weight' => 5000, 100 | 'price' => [ 101 | self::ZONE_FR => 1360, 102 | ], 103 | ], 104 | '3-Bottles' => [ 105 | 'length' => 390, 106 | 'width' => 425, 107 | 'height' => 106, 108 | 'weight' => 7000, 109 | 'price' => [ 110 | self::ZONE_FR => 1460, 111 | ], 112 | ], 113 | ]; 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /src/rates/royalmail/online/SecondClass.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 85, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 155, 26 | 250 => 190, 27 | 500 => 230, 28 | 750 => 250, 29 | ], 30 | self::SMALL_PARCEL_WIDE => [ 31 | 2000 => 325, 32 | ], 33 | self::SMALL_PARCEL_DEEP => [ 34 | 2000 => 325, 35 | ], 36 | self::SMALL_PARCEL_BIGGER => [ 37 | 2000 => 325, 38 | ], 39 | self::MEDIUM_PARCEL => [ 40 | 2000 => 485, 41 | 10000 => 635, 42 | 20000 => 1025, 43 | ], 44 | ], 45 | '2025' => [ 46 | self::LETTER => [ 47 | 100 => 87, 48 | ], 49 | self::LARGE_LETTER => [ 50 | 100 => 155, 51 | 250 => 180, 52 | 500 => 220, 53 | 750 => 250, 54 | ], 55 | self::SMALL_PARCEL_WIDE => [ 56 | 2000 => 335, 57 | ], 58 | self::SMALL_PARCEL_DEEP => [ 59 | 2000 => 335, 60 | ], 61 | self::SMALL_PARCEL_BIGGER => [ 62 | 2000 => 335, 63 | ], 64 | self::MEDIUM_PARCEL => [ 65 | 2000 => 495, 66 | 10000 => 655, 67 | 20000 => 1055, 68 | ], 69 | ], 70 | ]; 71 | 72 | $boxes = [ 73 | self::LETTER => [ 74 | 'length' => 240, 75 | 'width' => 165, 76 | 'height' => 5, 77 | 'weight' => 100, 78 | ], 79 | self::LARGE_LETTER => [ 80 | 'length' => 353, 81 | 'width' => 250, 82 | 'height' => 25, 83 | 'weight' => 750, 84 | ], 85 | self::SMALL_PARCEL_WIDE => [ 86 | 'length' => 450, 87 | 'width' => 350, 88 | 'height' => 160, 89 | 'weight' => 2000, 90 | ], 91 | self::SMALL_PARCEL_DEEP => [ 92 | 'length' => 350, 93 | 'width' => 250, 94 | 'height' => 160, 95 | 'weight' => 2000, 96 | ], 97 | self::SMALL_PARCEL_BIGGER => [ 98 | 'length' => 450, 99 | 'width' => 350, 100 | 'height' => 160, 101 | 'weight' => 2000, 102 | ], 103 | self::MEDIUM_PARCEL => [ 104 | 'length' => 610, 105 | 'width' => 460, 106 | 'height' => 460, 107 | 'weight' => 20000, 108 | ], 109 | self::TUBE => [ 110 | 'length' => 900, 111 | 'width' => 70, 112 | 'height' => 70, 113 | 'weight' => 2000, 114 | ], 115 | ]; 116 | 117 | return self::getBoxPricing($boxes, $bands, 20); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/SecondClass.php: -------------------------------------------------------------------------------- 1 | [ 21 | self::LETTER => [ 22 | 100 => 85, 23 | ], 24 | self::LARGE_LETTER => [ 25 | 100 => 155, 26 | 250 => 210, 27 | 500 => 250, 28 | 750 => 270, 29 | ], 30 | self::SMALL_PARCEL_WIDE => [ 31 | 2000 => 375, 32 | ], 33 | self::SMALL_PARCEL_DEEP => [ 34 | 2000 => 375, 35 | ], 36 | self::SMALL_PARCEL_BIGGER => [ 37 | 2000 => 375, 38 | ], 39 | self::MEDIUM_PARCEL => [ 40 | 2000 => 615, 41 | 10000 => 765, 42 | 20000 => 1155, 43 | ], 44 | ], 45 | '2025' => [ 46 | self::LETTER => [ 47 | 100 => 87, 48 | ], 49 | self::LARGE_LETTER => [ 50 | 100 => 155, 51 | 250 => 200, 52 | 500 => 240, 53 | 750 => 270, 54 | ], 55 | self::SMALL_PARCEL_WIDE => [ 56 | 2000 => 390, 57 | ], 58 | self::SMALL_PARCEL_DEEP => [ 59 | 2000 => 390, 60 | ], 61 | self::SMALL_PARCEL_BIGGER => [ 62 | 2000 => 390, 63 | ], 64 | self::MEDIUM_PARCEL => [ 65 | 2000 => 629, 66 | 10000 => 789, 67 | 20000 => 1189, 68 | ], 69 | ], 70 | ]; 71 | 72 | $boxes = [ 73 | self::LETTER => [ 74 | 'length' => 240, 75 | 'width' => 165, 76 | 'height' => 5, 77 | 'weight' => 100, 78 | ], 79 | self::LARGE_LETTER => [ 80 | 'length' => 353, 81 | 'width' => 250, 82 | 'height' => 25, 83 | 'weight' => 750, 84 | ], 85 | self::SMALL_PARCEL_WIDE => [ 86 | 'length' => 450, 87 | 'width' => 350, 88 | 'height' => 160, 89 | 'weight' => 2000, 90 | ], 91 | self::SMALL_PARCEL_DEEP => [ 92 | 'length' => 350, 93 | 'width' => 250, 94 | 'height' => 160, 95 | 'weight' => 2000, 96 | ], 97 | self::SMALL_PARCEL_BIGGER => [ 98 | 'length' => 450, 99 | 'width' => 350, 100 | 'height' => 160, 101 | 'weight' => 2000, 102 | ], 103 | self::MEDIUM_PARCEL => [ 104 | 'length' => 610, 105 | 'width' => 460, 106 | 'height' => 460, 107 | 'weight' => 20000, 108 | ], 109 | self::TUBE => [ 110 | 'length' => 900, 111 | 'width' => 70, 112 | 'height' => 70, 113 | 'weight' => 2000, 114 | ], 115 | ]; 116 | 117 | return self::getBoxPricing($boxes, $bands, 20); 118 | } 119 | } 120 | -------------------------------------------------------------------------------- /docs/get-started/core-concepts.md: -------------------------------------------------------------------------------- 1 | # Core Concepts 2 | 3 | ## A unified API 4 | Shipping carriers come in all shapes and sizes. Some use JSON, XML or even SOAP for data. Some have simple authentication, others use OAuth. But every carrier will require the payloads sent to their APIs to be formatted in a specific way — likewise, their responses back will be unique. 5 | 6 | The goal of Shippy is to provide a unified API that abstracts away having to deal with multiple carrier APIs, or their API's themselves as they change with time. To achieve this, Shippy provides a range of classes to represent some of the consistent data that are common across tasks like fetching rates and printing labels. 7 | 8 | ## Models 9 | Shippy supplies several object classes to abstract things. Most notable are: 10 | 11 | ### Rates 12 | - [Address](docs:models/address) 13 | - [Shipment](docs:models/shipment) 14 | - [Package](docs:models/package) 15 | - [Rate](docs:models/rate) 16 | 17 | ### Tracking 18 | - [Tracking](docs:models/tracking) 19 | 20 | ### Labels 21 | - [Shipment](docs:models/shipment) 22 | - [Label](docs:models/label) 23 | 24 | See the [Models](docs:models) section for a full list of models. 25 | 26 | Any Shippy model can be initialized in the following ways — depending on your preference. In all cases, you're free to mix and match, which might be beneficial depending on the logic of your app. 27 | 28 | ### Array-based Syntax 29 | Classes can be created by passing an array into the constructor. For example: 30 | 31 | ```php 32 | use verbb\shippy\models\Address; 33 | 34 | new Address([ 35 | 'street1' => 'One Infinite Loop', 36 | 'city' => 'Cupertino', 37 | 'stateProvince' => 'CA', 38 | 'postalCode' => '95014', 39 | 'countryCode' => 'US', 40 | ]); 41 | ``` 42 | 43 | ### Fluent-based Syntax 44 | Classes can be created, and then configured by chaining setter methods. For example: 45 | 46 | ```php 47 | use verbb\shippy\models\Address; 48 | 49 | $toAddress = new Address() 50 | ->setStreet1('One Infinite Loop') 51 | ->setCity('Cupertino') 52 | ->setStateProvince('CA') 53 | ->setPostalCode('95014') 54 | ->setCountryCode('US'); 55 | ``` 56 | 57 | ### Method-based Syntax 58 | Classes can be created using the "usual" approach with non-chained setter methods. For example: 59 | 60 | ```php 61 | use verbb\shippy\models\Address; 62 | 63 | $toAddress = new Address(); 64 | $toAddress->setStreet1('One Infinite Loop'); 65 | $toAddress->setCity('Cupertino'); 66 | $toAddress->setStateProvince('CA'); 67 | $toAddress->setPostalCode('95014'); 68 | $toAddress->setCountryCode('US'); 69 | ``` 70 | 71 | ### Hybrid-based Syntax 72 | You're able to mix and match these syntaxes as you see fit. 73 | 74 | ```php 75 | use verbb\shippy\models\Package; 76 | 77 | $package = new Package([ 78 | 'length' => 300, 79 | 'width' => 100, 80 | 'height' => 80, 81 | 'weight' => 2000, 82 | ]); 83 | 84 | if ($isPriced) { 85 | $package->setPrice(20); 86 | } 87 | 88 | if ($isMetric) { 89 | $package 90 | ->setDimensionUnit('mm') 91 | ->setWeightUnit('g'); 92 | } 93 | ``` 94 | 95 | ## Packages 96 | [Package](docs:models/package) models define the items we want to fetch rates for or generate labels for. They have defined dimensions and weight values. 97 | 98 | Alongside these values, we also define the units used. Shippy will handle all the converting for the carrier. 99 | 100 | For example, USPS as a carrier uses pounds (`lbs`) and inches (`in`) for units, and their API requires values to be sent in those units. But you might like to define your packages in kilograms (`kg`) and millimetres (`mm`). Just be sure to set the appropriate units for what you _provide_ and Shippy and the carrier implementation will take care of the rest. 101 | 102 | ```php 103 | use verbb\shippy\models\Package; 104 | 105 | $package = new Package([ 106 | 'length' => 3000, 107 | 'width' => 1000, 108 | 'height' => 800, 109 | 'weight' => 2, 110 | 'dimensionUnit' => 'mm', 111 | 'weightUnit' => 'kg', 112 | ]); 113 | ``` -------------------------------------------------------------------------------- /docs/api/events.md: -------------------------------------------------------------------------------- 1 | # Events 2 | Shippy raises some events when communicating with carrier APIs. This can be useful not only for knowing before or after requests are raised, but for manipulating them as well. 3 | 4 | For example, we might like to modify something about the payload sent to carrier APIs before it's sent. Here, we can call `on()` on an instance of a carrier, and which event we'd like to be notified on. 5 | 6 | ```php 7 | use verbb\shippy\carriers\AustraliaPost; 8 | use verbb\shippy\events\RateEvent; 9 | 10 | $carrier = new AustraliaPost([ 11 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 12 | ]); 13 | 14 | $carrier->on(AustraliaPost::EVENT_BEFORE_FETCH_RATES, function(RateEvent $event) { 15 | // Change the endpoint for the request 16 | $event->getRequest()->setEndpoint('my/alternative/endpoint'); 17 | 18 | // Change some data about the payload 19 | $payload = $event->getRequest()->getPayload(); 20 | $payload['my-data'] = 'my-value'; 21 | 22 | $event->getRequest()->setPayload($payload); 23 | }); 24 | ``` 25 | 26 | This would alter the [Request](docs:models/request) object's `endpoint` and `payload` properties to our custom values. 27 | 28 | ## Rate related events 29 | 30 | ### The `beforeFetchRates` event 31 | The event raised before the rates are fetched from the carrier's API. 32 | 33 | ```php 34 | use verbb\shippy\carriers\AustraliaPost; 35 | use verbb\shippy\events\RateEvent; 36 | 37 | $carrier = new AustraliaPost([ 38 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 39 | ]); 40 | 41 | $carrier->on(AustraliaPost::EVENT_BEFORE_FETCH_RATES, function(RateEvent $event) { 42 | // ... 43 | }); 44 | ``` 45 | 46 | ### The `afterFetchRates` event 47 | The event raised after the rates are fetched from the carrier's API, and parsed by the carrier class. 48 | 49 | ```php 50 | use verbb\shippy\carriers\AustraliaPost; 51 | use verbb\shippy\events\RateEvent; 52 | 53 | $carrier = new AustraliaPost([ 54 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 55 | ]); 56 | 57 | $carrier->on(AustraliaPost::EVENT_AFTER_FETCH_RATES, function(RateEvent $event) { 58 | // ... 59 | }); 60 | ``` 61 | 62 | ## Tracking related events 63 | 64 | ### The `beforeFetchTracking` event 65 | The event raised before the tracking information is fetched from the carrier's API. 66 | 67 | ```php 68 | use verbb\shippy\carriers\AustraliaPost; 69 | use verbb\shippy\events\TrackingEvent; 70 | 71 | $carrier = new AustraliaPost([ 72 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 73 | ]); 74 | 75 | $carrier->on(AustraliaPost::EVENT_BEFORE_FETCH_TRACKING, function(TrackingEvent $event) { 76 | // ... 77 | }); 78 | ``` 79 | 80 | ### The `afterFetchTracking` event 81 | The event raised after the tracking information is fetched from the carrier's API, and parsed by the carrier class. 82 | 83 | ```php 84 | use verbb\shippy\carriers\AustraliaPost; 85 | use verbb\shippy\events\TrackingEvent; 86 | 87 | $carrier = new AustraliaPost([ 88 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 89 | ]); 90 | 91 | $carrier->on(AustraliaPost::EVENT_AFTER_FETCH_TRACKING, function(TrackingEvent $event) { 92 | // ... 93 | }); 94 | ``` 95 | 96 | ## Label related events 97 | 98 | ### The `beforeFetchLabels` event 99 | The event raised before the labels are fetched from the carrier's API. 100 | 101 | ```php 102 | use verbb\shippy\carriers\AustraliaPost; 103 | use verbb\shippy\events\LabelEvent; 104 | 105 | $carrier = new AustraliaPost([ 106 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 107 | ]); 108 | 109 | $carrier->on(AustraliaPost::EVENT_BEFORE_FETCH_LABELS, function(LabelEvent $event) { 110 | // ... 111 | }); 112 | ``` 113 | 114 | ### The `afterFetchLabels` event 115 | The event raised after the labels are fetched from the carrier's API, and parsed by the carrier class. 116 | 117 | ```php 118 | use verbb\shippy\carriers\AustraliaPost; 119 | use verbb\shippy\events\LabelEvent; 120 | 121 | $carrier = new AustraliaPost([ 122 | 'apiKey' => '•••••••••••••••••••••••••••••••••••', 123 | ]); 124 | 125 | $carrier->on(AustraliaPost::EVENT_AFTER_FETCH_LABELS, function(LabelEvent $event) { 126 | // ... 127 | }); 128 | ``` 129 | -------------------------------------------------------------------------------- /src/models/PackageBox.php: -------------------------------------------------------------------------------- 1 | reference = $reference; 31 | $this->outerWidth = $width; 32 | $this->outerLength = $length; 33 | $this->outerDepth = $depth; 34 | $this->emptyWeight = 0; 35 | $this->innerWidth = $width; 36 | $this->innerLength = $length; 37 | $this->innerDepth = $depth; 38 | $this->maxWeight = $weight; 39 | } 40 | 41 | public function getReference(): string 42 | { 43 | return (string)$this->reference; 44 | } 45 | 46 | public function setReference($value): void 47 | { 48 | $this->reference = $value; 49 | } 50 | 51 | public function getOuterWidth(): int 52 | { 53 | return (int)$this->outerWidth; 54 | } 55 | 56 | public function setOuterWidth($value): void 57 | { 58 | $this->outerWidth = $value; 59 | } 60 | 61 | public function getOuterLength(): int 62 | { 63 | return (int)$this->outerLength; 64 | } 65 | 66 | public function setOuterLength($value): void 67 | { 68 | $this->outerLength = $value; 69 | } 70 | 71 | public function getOuterDepth(): int 72 | { 73 | return (int)$this->outerDepth; 74 | } 75 | 76 | public function setOuterDepth($value): void 77 | { 78 | $this->outerDepth = $value; 79 | } 80 | 81 | public function getEmptyWeight(): int 82 | { 83 | return (int)$this->emptyWeight; 84 | } 85 | 86 | public function setEmptyWeight($value): void 87 | { 88 | $this->emptyWeight = $value; 89 | } 90 | 91 | public function getInnerWidth(): int 92 | { 93 | return (int)$this->innerWidth; 94 | } 95 | 96 | public function setInnerWidth($value): void 97 | { 98 | $this->innerWidth = $value; 99 | } 100 | 101 | public function getInnerLength(): int 102 | { 103 | return (int)$this->innerLength; 104 | } 105 | 106 | public function setInnerLength($value): void 107 | { 108 | $this->innerLength = $value; 109 | } 110 | 111 | public function getInnerDepth(): int 112 | { 113 | return (int)$this->innerDepth; 114 | } 115 | 116 | public function setInnerDepth($value): void 117 | { 118 | $this->innerDepth = $value; 119 | } 120 | 121 | public function getMaxWeight(): int 122 | { 123 | return (int)$this->maxWeight; 124 | } 125 | 126 | public function setMaxWeight($value): void 127 | { 128 | $this->maxWeight = $value; 129 | } 130 | 131 | public function getType(): string 132 | { 133 | return (string)$this->type; 134 | } 135 | 136 | public function setType($value): void 137 | { 138 | $this->type = $value; 139 | } 140 | 141 | public function getPrice(): float 142 | { 143 | return (float)$this->price; 144 | } 145 | 146 | public function setPrice($value): void 147 | { 148 | $this->price = $value; 149 | } 150 | 151 | public function getCurrency(): string 152 | { 153 | return (string)$this->currency; 154 | } 155 | 156 | public function setCurrency($value): void 157 | { 158 | $this->currency = $value; 159 | } 160 | } 161 | -------------------------------------------------------------------------------- /src/rates/royalmail/postoffice/InternationalSigned.php: -------------------------------------------------------------------------------- 1 | [ 27 | self::LETTER => [ 28 | 100 => [815, 815, 815, 815, 815], 29 | ], 30 | self::LARGE_LETTER => [ 31 | 100 => [965, 965, 965, 1065, 1080], 32 | 250 => [1090, 1090, 1090, 1230, 1350], 33 | 500 => [1170, 1170, 1170, 1430, 1630], 34 | 750 => [1215, 1215, 1215, 1635, 1935], 35 | ], 36 | self::PACKET => [ 37 | 100 => [1375, 1390, 1530, 1770, 1900], 38 | 250 => [1375, 1390, 1530, 1810, 1935], 39 | 500 => [1520, 1560, 1700, 2240, 2430], 40 | 750 => [1635, 1670, 1825, 2500, 2740], 41 | 1000 => [1740, 1770, 1955, 2795, 3085], 42 | 1250 => [1800, 1805, 2025, 3015, 3355], 43 | 1500 => [1810, 1830, 2090, 3170, 3630], 44 | 2000 => [1825, 1880, 2140, 3220, 3745], 45 | ], 46 | self::PRINTED_PAPERS => [ 47 | 100 => [1375, 1390, 1530, 1770, 1900], 48 | 250 => [1375, 1390, 1530, 1810, 1935], 49 | 500 => [1520, 1560, 1700, 2240, 2430], 50 | 750 => [1635, 1670, 1825, 2500, 2740], 51 | 1000 => [1740, 1770, 1955, 2795, 3085], 52 | 1250 => [1800, 1805, 2025, 3015, 3355], 53 | 1500 => [1810, 1830, 2090, 3170, 3630], 54 | 2000 => [1825, 1880, 2140, 3220, 3745], 55 | ], 56 | ], 57 | '2025' => [ 58 | self::LETTER => [ 59 | 100 => [850, 850, 850, 850, 850], 60 | ], 61 | self::LARGE_LETTER => [ 62 | 100 => [1005, 1005, 1005, 1110, 1125], 63 | 250 => [1135, 1135, 1135, 1280, 1405], 64 | 500 => [1215, 1215, 1215, 1485, 1695], 65 | 750 => [1265, 1265, 1265, 1700, 2010], 66 | ], 67 | self::PACKET => [ 68 | 100 => [1425, 1460, 1635, 1895, 1995], 69 | 250 => [1425, 1460, 1635, 1895, 1995], 70 | 500 => [1580, 1640, 1820, 2350, 2550], 71 | 750 => [1700, 1755, 1955, 2625, 2875], 72 | 1000 => [1810, 1860, 2090, 2935, 3240], 73 | 1250 => [1870, 1895, 2165, 3165, 3525], 74 | 1500 => [1880, 1920, 2235, 3330, 3810], 75 | 2000 => [1900, 1975, 2290, 3380, 3930], 76 | ], 77 | ], 78 | ]; 79 | 80 | return self::getInternationalBoxPricing($bands, $countryCode); 81 | } 82 | } 83 | --------------------------------------------------------------------------------