diff --git a/.editorconfig b/.editorconfig new file mode 100755 index 0000000..cd8eb86 --- /dev/null +++ b/.editorconfig @@ -0,0 +1,15 @@ +; This file is for unifying the coding style for different editors and IDEs. +; More information at http://editorconfig.org + +root = true + +[*] +charset = utf-8 +indent_size = 4 +indent_style = space +end_of_line = lf +insert_final_newline = true +trim_trailing_whitespace = true + +[*.md] +trim_trailing_whitespace = false diff --git a/.gitattributes b/.gitattributes new file mode 100755 index 0000000..e722e49 --- /dev/null +++ b/.gitattributes @@ -0,0 +1,18 @@ +# Path-based git attributes +# https://www.kernel.org/pub/software/scm/git/docs/gitattributes.html + +# Ignore all test and documentation with "export-ignore". +/.github export-ignore +/bin export-ignore +/docs export-ignore +/tests export-ignore +/.editorconfig export-ignore +/.gitattributes export-ignore +/.gitignore export-ignore +/.scrutinizer.yml export-ignore +/.styleci.yml export-ignore +/.travis.yml export-ignore +/CHANGELOG.md export-ignore +/phpstan.neon.dist export-ignore +/phpunit.xml.dist export-ignore +/ruleset.xml export-ignore diff --git a/.github/ISSUE_TEMPLATE.md b/.github/ISSUE_TEMPLATE.md new file mode 100755 index 0000000..eb0d8e9 --- /dev/null +++ b/.github/ISSUE_TEMPLATE.md @@ -0,0 +1,27 @@ + + +## Detailed description + +Provide a detailed description of the change or addition you are proposing. + +Make it clear if the issue is a bug, an enhancement or just a question. + +## Context + +Why is this change important to you? How would you use it? + +How can it benefit other users? + +## Possible implementation + +Not obligatory, but suggest an idea for implementing addition or change. + +## Your environment + +Include as many relevant details about the environment you experienced the bug in and how to reproduce it. + +* Version used (e.g. PHP 7.1, HHVM 3): +* Operating system and version (e.g. Ubuntu 16.04, Windows 10): +* Link to your project: +* ... +* ... diff --git a/.github/PULL_REQUEST_TEMPLATE.md b/.github/PULL_REQUEST_TEMPLATE.md new file mode 100755 index 0000000..0d25c25 --- /dev/null +++ b/.github/PULL_REQUEST_TEMPLATE.md @@ -0,0 +1,43 @@ + + +## Description + +Describe your changes in detail. + +## Motivation and context + +Why is this change required? What problem does it solve? + +If it fixes an open issue, please link to the issue here (if you write `fixes #num` +or `closes #num`, the issue will be automatically closed when the pull is accepted.) + +## How has this been tested? + +Please describe in detail how you tested your changes. + +Include details of your testing environment, and the tests you ran to +see how your change affects other areas of the code, etc. + +## Screenshots (if appropriate) + +## Types of changes + +What types of changes does your code introduce? Put an `x` in all the boxes that apply: +- [ ] Bug fix (non-breaking change which fixes an issue) +- [ ] New feature (non-breaking change which adds functionality) +- [ ] Breaking change (fix or feature that would cause existing functionality to change) + +## Checklist: + +Go over all the following points, and put an `x` in all the boxes that apply. + +Please, please, please, don't send your pull request until all of the boxes are ticked. Once your pull request is created, it will trigger a build on our [continuous integration](http://www.phptherightway.com/#continuous-integration) server to make sure your [tests and code style pass](https://help.github.com/articles/about-required-status-checks/). + +- [ ] I have read the **[CONTRIBUTING](../docs/CONTRIBUTING.md)** document. +- [ ] My pull request addresses exactly one patch/feature. +- [ ] I have created a branch for this patch/feature. +- [ ] Each individual commit in the pull request is meaningful. +- [ ] I have added tests to cover my changes. +- [ ] If my change requires a change to the documentation, I have updated it accordingly. + +If you're unsure about any of these, don't hesitate to ask. We're here to help! diff --git a/.gitignore b/.gitignore new file mode 100755 index 0000000..491e242 --- /dev/null +++ b/.gitignore @@ -0,0 +1,6 @@ +build +composer.lock +vendor +coverage.clover +phpunit.xml +.idea diff --git a/.scrutinizer.yml b/.scrutinizer.yml new file mode 100644 index 0000000..c63b89b --- /dev/null +++ b/.scrutinizer.yml @@ -0,0 +1,143 @@ +filter: + excluded_paths: + - 'tests/*' + +checks: + php: + code_rating: true + duplication: true + remove_extra_empty_lines: true + remove_php_closing_tag: true + remove_trailing_whitespace: true + fix_use_statements: + remove_unused: true + preserve_multiple: false + preserve_blanklines: true + order_alphabetically: true + fix_php_opening_tag: true + fix_linefeed: true + fix_line_ending: true + fix_identation_4spaces: true + fix_doc_comments: true + newline_at_end_of_file: true + naming_conventions: + local_variable: '^[a-z][a-zA-Z0-9]*$' + utility_class_name: '^[A-Z][a-zA-Z0-9]*$' + constant_name: '^[A-Z][A-Z0-9]*(?:_[A-Z0-9]+)*$' + property_name: '^[a-z][a-zA-Z0-9]*$' + method_name: '^((?:[a-z]|__)[a-zA-Z0-9]*|test[A-Z][_a-zA-Z0-9]*)$' + parameter_name: '^[a-z][a-zA-Z0-9]*$' + interface_name: '^[A-Z][a-zA-Z0-9]*Interface$' + type_name: '^(m[0-9a-z_]+|[A-Z][a-zA-Z0-9]*)$' + exception_name: '^[A-Z][a-zA-Z0-9]*Exception$' + isser_method_name: '^(?:is|can|has|should|may|supports)' + +coding_style: + php: + indentation: + general: + use_tabs: false + size: 4 + switch: + indent_case: true + spaces: + general: + linefeed_character: newline + before_parentheses: + function_declaration: false + closure_definition: true + function_call: false + if: true + for: true + while: true + switch: true + catch: true + array_initializer: false + around_operators: + assignment: true + logical: true + equality: true + relational: true + bitwise: true + additive: true + multiplicative: true + shift: true + unary_additive: false + concatenation: true + negation: false + before_left_brace: + class: true + function: true + if: true + else: true + for: true + while: true + do: true + switch: true + try: true + catch: true + finally: true + before_keywords: + else: true + while: true + catch: true + finally: true + within: + brackets: false + array_initializer: false + grouping: false + function_call: false + function_declaration: false + if: false + for: false + while: false + switch: false + catch: false + type_cast: false + ternary_operator: + before_condition: true + after_condition: true + before_alternative: true + after_alternative: true + in_short_version: false + other: + before_comma: false + after_comma: true + before_semicolon: false + after_semicolon: true + after_type_cast: true + braces: + classes_functions: + class: new-line + function: new-line + closure: end-of-line + if: + opening: end-of-line + always: true + else_on_new_line: false + for: + opening: end-of-line + always: true + while: + opening: end-of-line + always: true + do_while: + opening: end-of-line + always: true + while_on_new_line: false + switch: + opening: end-of-line + try: + opening: end-of-line + catch_on_new_line: false + finally_on_new_line: false + upper_lower_casing: + keywords: + general: lower + constants: + true_false_null: lower + +tools: + external_code_coverage: + timeout: 2400 + runs: 1 \ No newline at end of file diff --git a/.styleci.yml b/.styleci.yml new file mode 100755 index 0000000..1027d9e --- /dev/null +++ b/.styleci.yml @@ -0,0 +1,11 @@ +preset: psr2 + +enabled: + - blank_line_before_try + - blank_line_before_catch + - blank_line_before_return + - no_spaces_after_function_name + +finder: + name: + - "*.sphp" \ No newline at end of file diff --git a/.travis.yml b/.travis.yml new file mode 100644 index 0000000..7b1a6b4 --- /dev/null +++ b/.travis.yml @@ -0,0 +1,28 @@ +dist: trusty +language: php + +php: + - 7.1 + - 7.2 + - 7.3 + +sudo: false + +cache: + directories: + - $HOME/.composer/cache + +before_script: + - travis_retry composer update ${COMPOSER_FLAGS} --no-interaction --prefer-dist + +script: + - vendor/bin/phpcs --standard=./ruleset.xml src/ + - vendor/bin/phpstan analyse -l 7 -c phpstan.neon.dist src/ + - vendor/bin/phpunit --coverage-text --coverage-clover=coverage.clover + +after_script: + - | + if [[ "$TRAVIS_PHP_VERSION" != '7.3' ]]; then + wget https://scrutinizer-ci.com/ocular.phar + php ocular.phar code-coverage:upload --format=php-clover coverage.clover + fi diff --git a/CHANGELOG.md b/CHANGELOG.md new file mode 100755 index 0000000..2209f07 --- /dev/null +++ b/CHANGELOG.md @@ -0,0 +1,10 @@ +# Changelog + +All notable changes to this project will be documented in this file. + +The format is based on [Keep a Changelog](http://keepachangelog.com/en/1.0.0/) +and this project adheres to [Semantic Versioning](http://semver.org/spec/v2.0.0.html). + +## [1.0.0] - 2018-12-26 +### Added +- Full support for all requests and options in documentation **v1.845** (2018-11-29) diff --git a/LICENSE.md b/LICENSE.md new file mode 100755 index 0000000..96aedd1 --- /dev/null +++ b/LICENSE.md @@ -0,0 +1,21 @@ +# The MIT License (MIT) + +Copyright (c) 2018 Tomáš Novotný + +> 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: +> +> The above copyright notice and this permission notice shall be included in +> all copies or substantial portions of the Software. +> +> 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. diff --git a/README.md b/README.md new file mode 100755 index 0000000..042eaec --- /dev/null +++ b/README.md @@ -0,0 +1,187 @@ +# Balikobot API + +**Created as part of [inspishop][link-inspishop] e-commerce platform by [inspirum][link-inspirum] team.** + +[![Latest Stable Version][ico-packagist-stable]][link-packagist-stable] +[![Build Status][ico-travis]][link-travis] +[![Coverage Status][ico-scrutinizer]][link-scrutinizer] +[![Quality Score][ico-code-quality]][link-code-quality] +[![PHPStan][ico-phpstan]][link-phpstan] +[![Total Downloads][ico-packagist-download]][link-packagist-download] +[![Software License][ico-license]][link-licence] + +Offers implementation of Balikobot API described in the [documentation](#version) + +- Support for all API [requests](./src/Services/Client.php) +- Simple add/track/drop package [methods](./src/Services/Balikobot.php) +- All package options are accessible via setter/getter methods +- The entire code is covered by unit tests +- Customizable [**Requester**](./src/Contracts/RequesterInterface.php) for easy functionality expandability (caching, etc.) + + +## Usage example + +*All the code snippets shown here are modified for clarity, so they may not be executable.* + +```php +// init balikobot class +$requester = new Requester($user, $key); +$balikobot = new Balikobot($requester); +$data = []; + +// create new package collection for specific shipper +$packages = new PackageCollection(Shipper::CP); + +// create new package +$package = new Package(); +$package->setServiceType(ServiceType::CP_NP); +$package->setRecName("Josef Novák"); +$package->setRecZip("11000"); +$package->setRecCountry(Country::CZECH_REPUBLIC); +$package->setRecPhone("776555888"); +$package->setCodPrice(1399.00); +$package->setCodCurrency(Currency::CZK); + +// add package to collection +$packages->add($package); + +// upload packages to balikobot +$orderedPackages = $balikobot->addPackages($packages); + +// save package IDs +$data["packages"] = $orderedPackages->getPackageIds(); + +// save track URL for each package +foreach($orderedPackages as $orderedPackage) { + $data["trackUrl"][] = $orderedPackage->getTrackUrl(); +} + +// order shipment for packages +$orderedShipment = $balikobot->orderShipment($orderedPackages); + +// save order ID and labels URL +$data["orderId"] = $orderedShipment->getOrderId(); +$data["labelsUrl"] = $orderedShipment->getLabelsUrl(); +$data["handoverUrl"] = $orderedShipment->getHandoverUrl(); + +/* +var_dump($data); +[ + "packages" => [ + 0 => 42719 + 1 => 42720 + ] + "trackUrl" => [ + 0 => "https://www.postaonline.cz/trackandtrace/-/zasilka/cislo?parcelNumbers=DR00112233M" + 1 => "https://www.postaonline.cz/trackandtrace/-/zasilka/cislo?parcelNumbers=DR00112234M" + ] + "orderId" => 2757 + "labelsUrl" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwM76cMBAXAn4." + "handoverUrl" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawtARcMBAhAoU." +] +*/ +``` + + +## System requirements + +* [PHP 7.1](http://php.net/releases/7_1_0.php) +* [ext-curl](http://php.net/curl) +* [ext-json](http://php.net/json) + + +## Installation + +```bash +$ composer require inspirum/php-balikobot +``` + + +## Version + +Support all options for Balikobot API described in the [documentation][link-api] (v1.845, 2018-11-29). + + +## Usage + + +### [**Definitons**](./docs/definitions.md) + +The module contains several helper classes that contain most of the constants needed to work with the Balikobot API. + + +### [**Client**](./docs/client.md) + +Support all options for Balikobot API described in given documentation. + +### [**Balikobot**](./docs/balikobot.md) + +Extension over Client that uses custom DTO classes as an input and output for its methods. + + +## Testing + +To run unit tests, run: + +```bash +$ composer test +``` + +To show coverage, run: + +```bash +$ composer test-coverage +``` + +For testing purposes, you can use these credentials: + +- **API username:** balikobot_test2cztest +- **API key:** #lS1tBVo + + +## Contributing + +Please see [CONTRIBUTING][link-contributing] and [CODE_OF_CONDUCT][link-code-of-conduct] for details. + + +## Security + +If you discover any security related issues, please email tomas.novotny@inspirum.cz instead of using the issue tracker. + + +## Credits + +- [Tomáš Novotný][link-author] +- [All Contributors][link-contributors] + + +## License + +The MIT License (MIT). Please see [License File][link-licence] for more information. + + +[ico-license]: https://img.shields.io/github/license/tomas-novotny/php-balikobot.svg?style=flat-square&color=6EC83F +[ico-travis]: https://img.shields.io/travis/tomas-novotny/php-balikobot/master.svg?branch=master&style=flat-square +[ico-scrutinizer]: https://img.shields.io/scrutinizer/coverage/g/tomas-novotny/php-balikobot/master.svg?style=flat-square +[ico-code-quality]: https://img.shields.io/scrutinizer/g/tomas-novotny/php-balikobot.svg?style=flat-square +[ico-packagist-stable]: https://img.shields.io/packagist/v/inspirum/php-balikobot.svg?style=flat-square&colorB=007EC6 +[ico-packagist-download]: https://img.shields.io/packagist/dt/inspirum/php-balikobot.svg?style=flat-square&colorB=007EC6 +[ico-phpstan]: https://img.shields.io/badge/style-level%207-brightgreen.svg?style=flat-square&label=phpstan + +[link-author]: https://github.com/tomas-novotny +[link-contributors]: https://github.com/tomas-novotny/php-balikobot/contributors +[link-licence]: ./LICENSE.md +[link-changelog]: ./CHANGELOG.md +[link-contributing]: ./docs/CONTRIBUTING.md +[link-code-of-conduct]: ./docs/CODE_OF_CONDUCT.md +[link-packagist]: https://packagist.org/packages/tomas-novotny/php-balikobot +[link-travis]: https://travis-ci.org/tomas-novotny/php-balikobot +[link-scrutinizer]: https://scrutinizer-ci.com/g/tomas-novotny/php-balikobot/code-structure +[link-code-quality]: https://scrutinizer-ci.com/g/tomas-novotny/php-balikobot +[link-downloads]: https://packagist.org/packages/tomas-novotny/php-balikobot +[link-api]: https://www.balikobot.cz/dokumentace/Balikobot-dokumentace-API.pdf +[link-inspishop]: https://www.inspishop.cz/ +[link-inspirum]: https://www.inspirum.cz/ +[link-packagist-stable]: https://packagist.org/packages/inspirum/php-balikobot +[link-packagist-download]: https://packagist.org/packages/inspirum/php-balikobot +[link-phpstan]: https://github.com/phpstan/phpstan diff --git a/composer.json b/composer.json new file mode 100755 index 0000000..64bf8b2 --- /dev/null +++ b/composer.json @@ -0,0 +1,49 @@ +{ + "name": "inspirum/php-balikobot", + "description": "", + "keywords": [ + "inspirum", + "inspishop", + "balikobot" + ], + "homepage": "https://github.com/tomas-novotny/php-balikobot", + "license": "MIT", + "type": "library", + "authors": [ + { + "name": "Tomáš Novotný", + "email": "tomas.novotny@inspirum.cz", + "role": "Developer" + } + ], + "require": { + "php": ">=7.1.3", + "ext-curl": "*", + "ext-json": "*", + "psr/http-message": "^1.0", + "guzzlehttp/psr7": "^1.5" + }, + "require-dev": { + "phpunit/phpunit": "~7.0", + "squizlabs/php_codesniffer": "^3.3", + "mockery/mockery": "^1.2", + "phpstan/phpstan": "^0.10.6", + "phpstan/phpstan-mockery": "^0.10.2" + }, + "autoload": { + "psr-4": { + "Inspirum\\Balikobot\\": "src" + } + }, + "autoload-dev": { + "psr-4": { + "Inspirum\\Balikobot\\Tests\\": "tests" + } + }, + "scripts": { + "test": "vendor/bin/phpunit", + "test-coverage": "vendor/bin/phpunit --coverage-html=./build/coverage", + "check-style": "vendor/bin/phpcs -p -s --extensions=php --standard=./ruleset.xml --colors --report-width=140 --runtime-set ignore_errors_on_exit 1 src tests && vendor/bin/phpstan analyse -l 7 -c phpstan.neon.dist src", + "fix-style": "vendor/bin/phpcbf -p --standard=./ruleset.xml --runtime-set ignore_errors_on_exit 1 src tests" + } +} diff --git a/docs/CODE_OF_CONDUCT.md b/docs/CODE_OF_CONDUCT.md new file mode 100755 index 0000000..806dc24 --- /dev/null +++ b/docs/CODE_OF_CONDUCT.md @@ -0,0 +1,74 @@ +# Contributor Code of Conduct + +## Our Pledge + +In the interest of fostering an open and welcoming environment, we as +contributors and maintainers pledge to make participation in our project and +our community a harassment-free experience for everyone, regardless of age, body +size, disability, ethnicity, gender identity and expression, level of experience, +nationality, personal appearance, race, religion, or sexual identity and +orientation. + +## Our Standards + +Examples of behavior that contributes to creating a positive environment +include: + +* Using welcoming and inclusive language +* Being respectful of differing viewpoints and experiences +* Gracefully accepting constructive criticism +* Focusing on what is best for the community +* Showing empathy towards other community members + +Examples of unacceptable behavior by participants include: + +* The use of sexualized language or imagery and unwelcome sexual attention or +advances +* Trolling, insulting/derogatory comments, and personal or political attacks +* Public or private harassment +* Publishing others' private information, such as a physical or electronic + address, without explicit permission +* Other conduct which could reasonably be considered inappropriate in a + professional setting + +## Our Responsibilities + +Project maintainers are responsible for clarifying the standards of acceptable +behavior and are expected to take appropriate and fair corrective action in +response to any instances of unacceptable behavior. + +Project maintainers have the right and responsibility to remove, edit, or +reject comments, commits, code, wiki edits, issues, and other contributions +that are not aligned to this Code of Conduct, or to ban temporarily or +permanently any contributor for other behaviors that they deem inappropriate, +threatening, offensive, or harmful. + +## Scope + +This Code of Conduct applies both within project spaces and in public spaces +when an individual is representing the project or its community. Examples of +representing a project or community include using an official project e-mail +address, posting via an official social media account, or acting as an appointed +representative at an online or offline event. Representation of a project may be +further defined and clarified by project maintainers. + +## Enforcement + +Instances of abusive, harassing, or otherwise unacceptable behavior may be +reported by contacting the project team at `tomas.novotny@inspirum.cz`. All +complaints will be reviewed and investigated and will result in a response that +is deemed necessary and appropriate to the circumstances. The project team is +obligated to maintain confidentiality with regard to the reporter of an incident. +Further details of specific enforcement policies may be posted separately. + +Project maintainers who do not follow or enforce the Code of Conduct in good +faith may face temporary or permanent repercussions as determined by other +members of the project's leadership. + +## Attribution + +This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4, +available at [http://contributor-covenant.org/version/1/4][version] + +[homepage]: http://contributor-covenant.org +[version]: http://contributor-covenant.org/version/1/4/ diff --git a/docs/CONTRIBUTING.md b/docs/CONTRIBUTING.md new file mode 100755 index 0000000..45ce390 --- /dev/null +++ b/docs/CONTRIBUTING.md @@ -0,0 +1,30 @@ +# Contributing + +Contributions are **welcome** and will be fully **credited**. + + +## Pull Requests + +- **[PSR-2 Coding Standard](https://github.com/php-fig/fig-standards/blob/master/accepted/PSR-2-coding-style-guide.md)** - Check the code style with ``$ composer check-style`` and fix it with ``$ composer fix-style``. + +- **Add tests!** - Your patch won't be accepted if it doesn't have tests. + +- **Document any change in behaviour** - Make sure the `README.md` and any other relevant documentation are kept up-to-date. + +- **Consider our release cycle** - We try to follow [SemVer v2.0.0](http://semver.org/). Randomly breaking public APIs is not an option. + +- **Create feature branches** - Don't ask us to pull from your master branch. + +- **One pull request per feature** - If you want to do more than one thing, send multiple pull requests. + +- **Send coherent history** - Make sure each individual commit in your pull request is meaningful. If you had to make multiple intermediate commits while developing, please [squash them](http://www.git-scm.com/book/en/v2/Git-Tools-Rewriting-History#Changing-Multiple-Commit-Messages) before submitting. + + +## Running Tests + +```bash +$ composer test +``` + + +**Happy coding**! diff --git a/docs/balikobot.md b/docs/balikobot.md new file mode 100755 index 0000000..6e549ec --- /dev/null +++ b/docs/balikobot.md @@ -0,0 +1,216 @@ +# Balikobot + +Service [**Inspirum\Balikobot\Services\Balikobot**](../src/Services/Balikobot.php) is extension over [Client](./client.md#client) that uses custom [DTO](https://en.wikipedia.org/wiki/Data_transfer_object) classes as an input and output for its methods. + + +## Packages + +Using plain API with [Client](./client.md#client) can be very difficult even with normalized return format. + +**Balikobot** service add DTO classes to ease to use with simple interfaces and user-friendly *getter* and *setter* methods. + +- [**Inspirum\Model\Values\Branch**](../src/Model/Values/Branch.php) +- [**Inspirum\Model\Values\OrderedPackage**](../src/Model/Values/OrderedPackage.php) +- [**Inspirum\Model\Values\OrderedShipment**](../src/Model/Values/OrderedShipment.php) +- [**Inspirum\Model\Values\Package**](../src/Model/Values/Package.php) +- [**Inspirum\Model\Values\PackageStatus**](../src/Model/Values/PackageStatus.php) +- [**Inspirum\Model\Values\PostCode**](../src/Model/Values/PostCode.php) +- [**Inspirum\Model\Aggregates\OrderedPackageCollection**](../src/Model/Aggregates/OrderedPackageCollection.php) +- [**Inspirum\Model\Aggregates\PackageCollection**](../src/Model/Aggregates/PackageCollection.php) + + +### Add packages + +The **addPackages** method is used to add new packages for given shipper. +Individual packages are created as instances of the class [**Package**](../src/Model/Values/Package.php), and they are transfered in [**PackageCollection**](../src/Model/Aggregates/PackageCollection.php). +All available options for packages are accessible by setter methods in [**Package**](../src/Model/Values/Package.php) class. + +The service normalizes the response by returning [**OrderedPackageCollection**](../src/Model/Aggregates/OrderedPackageCollection.php) which encapsulate data returned from [Client](./client.md#client). + +```php +use Inspirum\Balikobot\Definitions\Country; +use Inspirum\Balikobot\Definitions\ServiceType; +use Inspirum\Balikobot\Definitions\Shipper; +use Inspirum\Balikobot\Model\Aggregates\PackageCollection; +use Inspirum\Balikobot\Model\Values\Package; +use Inspirum\Balikobot\Services\Balikobot; + +$balikobot = new Balikobot($user, $key); + +$packages = new PackageCollection(Shipper::CP); + +$package = new Package(); +$package->setServiceType(ServiceType::CP_NP); +$package->setRecName("Josef Novák"); +$package->setPrice(1500); +$package->setRecStreet("Ulice 123"); +$package->setRecCity("Praha"); +$package->setRecZip("11000"); +$package->setRecCountry(Country::CZECH_REPUBLIC); +$package->setReturnFullErrors(); + +$packages->add($package); + +$orderedPackages = $balikobot->addPackages($packages); + +/* +var_dump($orderedPackages); +Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection { + private $shipper => "cp" + private $packages => [ + 0 => Inspirum\Balikobot\Model\Values\OrderedPackage { + private $shipper => "cp" + private $packageId => "42718" + private $carrierId => "NP1504102232M" + private $trackUrl => NULL + private $labelUrl => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwVcMBAXAn4." + ... + } + ] +} +*/ +``` + + +### Drop packages + +Drop created packages from Balikobot with **dropPackage** or **dropPackages** method. + +These methods has no return value, only throws exception on error, same as [**DROP**](./client.md#drop) request. + +```php +$orderedPackages = $balikobot->addPackages($packages); + +$balikobot->dropPackage($orderedPackages[0]); +``` + +or dropping all packages in collection + +```php +$balikobot->dropPackages($orderedPackages); +``` + + +### Order shipment + +To order shipment for packages use **orderShipment** method. + +The service normalizes the response by returning [**OrderedShipment.php**](../src/Model/Values/OrderedShipment.php) which encapsulate data returned from [Client](./client.md#client). + +```php +$orderedShipment = $balikobot->orderShipment($orderedPackages); + +/* +var_dump($orderedPackages); +Inspirum\Balikobot\Model\Values\OrderedShipment { + private $orderId => "42718" + private $handoverUrl => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NTW1MAVcMBAaAn4." + private $labelsUrl => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwVcMBAXAn4." + private $fileUrl => "https://csv.balikobot.cz/cp/eNorMTIwt9A1sjAyB1wwDZECRr.." + private $date => NULL + private $shipper => "cp" + private $packageIds => [ + "43619" + ] +} +*/ +``` + + +### Track packages + +Track added package status with **trackPackage method**. + +The service normalizes the response by returning [**PackageStatus.php**](../src/Model/Values/PackageStatus.php) which encapsulate data returned from [Client](./client.md#client). + +```php +$statuses = $balikobot->trackPackage($orderedPackages[0]); + +/* +var_dump($statuses); +[ + 0 => Inspirum\Balikobot\Model\Values\PackageStatus { + private $date => DateTime { + public $date => "2018-07-02 00:00:00.000000" + } + private $id => 2 + private $name => "Dodání zásilky. 10003 Depo Praha 701" + } + 1 => Inspirum\Balikobot\Model\Values\PackageStatus { + private $date => DateTime { + public $date => "2018-07-02 00:00:00.000000" + } + private $id => 1 + private $name => "Doručování zásilky. 10003 Depo Praha 701" + } + ... +] +*/ +``` + + +## Branches + +Several methods can be used to obtain branches for supported shippers. +- Method **getBranchesForShipperService** returns branches for specific shipper and service type. +- Method **getBranchesForShipper** returns branches for all service types for specific shipper. +- Method **getBranches** returns branches for all supported shippers. + +These methods return a large amount of data, therefore, these methods use [Generator](http://php.net/manual/en/class.generator.php) via [`yield`](http://php.net/manual/en/language.generators.syntax.php) keyword for returned data. +It saves a lot of memory and allows you to iterate all branches at one time in one cycle. + +```php +$shippers = $balikobot->getBranches(): +$shippers = $balikobot->getBranchesForShipper(Shipper::CP); +$shippers = $balikobot->getBranchesForShipperService(Shipper::CP, ServiceType::CP_NP); + +/* +var_dump($shippers); +Generator {} +*/ +``` + +Branch contains all possible attributes from [**FULLBRANCH**](./client.md#fullbranches) request. +Different shippers use different attribute as **branch_id** in [**ADD**](./client.md#add) request, therefore [**Branch**](../src/Model/Values/Branch.php) class already set proper **branch_id** for given shipper type. + +```php +$shippers = $balikobot->getBranchesForShipper(Shipper::CP): +í +foreach($shippers as $shipper) { + + /* + var_dump($shipper); + Inspirum\Balikobot\Model\Values\Branch { + private $shipper => "cp" + private $service => "NB" + private $branchId => "10003" + private $id => NULL + private $type => "branch" + private $name => "Depo Praha 701" + private $city => "" + private $street => "Sazečská 598/7, Malešice, 10003, Praha" + private $zip => "10003" + private $cityPart => NULL + private $district => NULL + private $region => NULL + private $country => "CZ" + ... + } + */ +} +``` + +*** + + +## More usage + + +### [**Definitons**](./definitions.md) + +The module contains several helper classes that contain most of the constants needed to work with the Balikobot API. + + +### [**Client**](./client.md) + +Support all options for Balikobot API described in given documentation. diff --git a/docs/client.md b/docs/client.md new file mode 100755 index 0000000..6f265d7 --- /dev/null +++ b/docs/client.md @@ -0,0 +1,672 @@ +# Client + +Support all options for Balikobot API described in given [documentation version](../README.md#version). + +Class [**Inspirum\Balikobot\Services\Client**](../src/Services/Client.php) is wrapper for all available requests in Balikobot API. Every method is documented in the next [section](#requests). + +Client class has two required arguments – API user and API key. +These credentials can be found in the Balikobot administration (section *"Profil expedičního místa"*). + +```php +use Inspirum\Balikobot\Services\Client; + +$user = getenv("BALIKOBOT_API_USER"); +$key = getenv("BALIKOBOT_API_KEY"); + +$client = new Client($user, $key); +``` + + +## Exceptions + +The client handles the API responses and throws an exception when an error occurs. +All thrown exceptions implement [**Inspirum\Balikobot\Contracts\ExceptionInterface**](../src/Contracts/ExceptionInterface.php) interface. +Thrown exception include error message, API response and any validation messages (even if **return_full_errors** option is not set). + +```php +// unhandled client call with wrong data +$client->getOverview(Shipper::CP); + +/* +PHP Fatal error: Uncaught Inspirum\Balikobot\Exceptions\UnauthorizedException: +"Unauthorized - nejspíš chyba na straně Balikobotu" + +"statusCode" => 401 +"errors" => [] +"response" => [] +*/ +``` + +Usually you will get [**Inspirum\Balikobot\Exceptions\BadRequestException**](../src/Exceptions/BadRequestException.php) + +```php +// unhandled client call with wrong data +$orderedPackages = $client->addPackages(Shipper::CP, $packages); + +/* +PHP Fatal error: Uncaught Inspirum\Balikobot\Exceptions\BadRequestException: +"Operace neproběhla v pořádku, zkontrolujte konkrétní data" + +"statusCode" => 400 +"errors" => [ + 0 => [ + "rec_email" => "Nedorazil email příjemce." + "rec_phone" => "Nedorazilo telefonní číslo příjemce." + ] + 1 => [ + "service_type" => "Neznámé ID služby přepravce." + ] +] +"response" => [ + 0 => [ + "rec_email" => "406" + "rec_phone" => "406" + ] + 1 => [ + "service_type" => "413" + ] + "status" => "400" +] +*/ +``` + +**Recommended**: Every client API call should be wrap in `try/catch` block to handle thrown exceptions. + +```php +use Inspirum\Balikobot\Contracts\ExceptionInterface; + +try { + // handled client call with wrong data + $orderedPackages = $client->addPackages(Shipper::CP, $packages); + // more logic ... +} catch(ExceptionInterface $exception) { + // handle exception ... +} +``` + + +## Requests + +Client normalize Balikobot API response output to use the same format for any shipper (for example different response type for [**ZIPCODE**](#zipcodes) or [**BRANCHES**](#branches) requests). + + +### **ADD** + +The **addPackages** method is used to add new packages for given shipper. All available options are in [**Inspirum\Balikobot\Definitions\Option**](../src/Definitions/Option.php) class. + +The client normalizes the response by returning only added packages data (drop **status** and **labels_url** attribute). + +```php +use Inspirum\Balikobot\Definitions\Option; +use Inspirum\Balikobot\Definitions\ServiceType; +use Inspirum\Balikobot\Definitions\Shipper; + +$orderedPackages = $client->addPackages(Shipper::CP, [ + [ + Options::SERVICE_TYPE => ServiceType::CP_NP, + Options::ORDER_ID => "180001", + Options::ORDER_NUMBER => 1, + Options::CUSTOMER_NAME => "Josef Novák", + Options::PRICE => 1500, + // ... + ], + [ + Options::SERVICE_TYPE => ServiceType::CP_NP, + Options::ORDER_ID => "180001", + Options::ORDER_NUMBER => 2, + Options::CUSTOMER_NAME => "Josef Novák", + Options::PRICE => 2000, + // ... + ], + // ... +]); + +/* +var_dump($orderedPackages); +[ + 0 => [ + "carrier_id" => "NP1504102246M" + "package_id" => 42719 + "label_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA." + "status" => "200" + ] + 1 => [ + "carrier_id" => "NP1504102247M" + "package_id" => 42720 + "label_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB." + "status" => "200" + ] +] +*/ +``` + + +### **DROP** + +Drop created packages from Balikobot with **dropPackage** or **dropPackages** method. + +These methods has no return value, only throws exception on error. + +```php +use Inspirum\Balikobot\Definitions\Shipper; + +$client->dropPackage(Shipper::CP, 42719); +``` + +```php +use Inspirum\Balikobot\Definitions\Shipper; + +$client->dropPackages(Shipper::CP, [42719, 42720]); +``` + + +### **TRACK** + +Track added package status with **trackPackage** method. This method has shipper code and carrier ID as arguments. +Carrier ID is from [**ADD**](#add) request response. + +This method internally uses new **TRACK V2** request with better response data format. + +Older version (**TRACK V1**) is not longer available via this client. + +```php +use Inspirum\Balikobot\Definitions\Shipper; + +$statuses = $client->trackPackage(Shipper::CP, "NP1504102246M"); + +/* +var_dump($statuses); +[ + 0 => [ + "date" => "2018-07-02 00:00:00" + "name" => "Dodání zásilky. 10003 Depo Praha 701" + "status_id" => 2 + ] + 1 => [ + "date" => "2018-07-02 00:00:00" + "name" => "Doručování zásilky. 10003 Depo Praha 701" + "status_id" => 1 + ] + 2 => [ + "date" => "2018-07-02 00:00:00" + "name" => "Příprava zásilky k doručení. 10003 Depo Praha 701" + "status_id" => 1 + ] + ... +] +*/ +``` + +### **TRACKSTATUS** + +Use the **trackPackageLastStatus** method to get last package status. + +Client normalize response format to match new [**TRACK V2**](#track) response. + +```php +$status = $client->trackPackageLastStatus(Shipper::CP, "NP1504102246M"); + +/* +var_dump($status); +[ + "date" => "2018-07-02 00:00:00" + "name" => "Zásilka zatím nebyla předána přepravci." + "status_id" => -1 +] +*/ +``` + + +### **OVERVIEW** + +To view added packages (with no ordered shipment) for given shipper use **getOverview** method. + +It has the same response data format as [**ADD**](#add) request. + +```php +$orderedPackages = $client->getOverview(Shipper::CP); + +/* +var_dump($orderedPackages); +[ + 0 => [ + "eshop_id" => "567A2889" + "carrier_id" => "NP1504102246M" + "package_id" => 42719 + "label_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA." + ] + 1 => [ + "eshop_id" => "567A2890" + "carrier_id" => "NP1504102247M" + "package_id" => 42720 + "label_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB." + ] + ... +] +*/ +``` + + +### **LABELS** + +Method **getLabels** return link to labels PDF file for given packages. + +The client normalizes the response by returning only **labels_url** string. + +```php +$labelsUrl = $client->getLabels(Shipper::CP, [42717, 42719]); + +/* +var_dump($labelsUrl); +"https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawNAdcMBAfAoM." +*/ +``` + + +### **PACKAGE** + +To get full info about added package use **getPackageInfo()** method. + +Response contains all options from request and all response data from [**ADD**](#add) request for each package. + +```php +$package = $client->getPackageInfo(Shipper::CP, 42717); + +/* +var_dump($package); +[ + "service_type" => "NP" + "vs" => "" + "cod_price" => 0.00 + "rec_firm" => "" + "rec_zip" => "17000" + "rec_phone" => "777555666" + + ... + + "eshop_id" => "15431025445bf9e0509a87d" + "carrier_id" => "NP1504102229M" + "package_id" => 42717 + "label_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwZcMBAVAnw." +] +*/ +``` + + +### **ORDER** + +To order shipment for packages use **orderShipment** method. + +The client normalizes the response by removing the status code (drop **status** attribute). + +```php +$orderedShipment = $client->orderShipment(Shipper::CP, [42717, 42718]); + +/* +var_dump($orderedShipment); +[ + "order_id" => 2757 + "file_url" => "https://csv.balikobot.cz/cp/eNorMTIwt9A1MjczAlwwDZECRA.." + "handover_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawtARcMBAhAoU." + "labels_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawtFwwXDAQIAKE" +] +*/ +``` + + +### **ORDERVIEW** + +To get ordered shipment data by order ID use **getOrder** method. +It has shipper code and order ID (**order_id** attribute from [**ORDER**](#order) request) as arguments. + +The client normalizes the response by removing the status code (drop **status** attribute). + +```php +$orderedShipment = $client->getOrder(Shipper::CP, 2757); + +/* +var_dump($orderedShipment); +[ + "order_id" => 2757 + "file_url" => "https://csv.balikobot.cz/cp/eNorMTIwt9A1MjczAlwwDZECRA.." + "handover_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawtARcMBAhAoU." + "labels_url" => "https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbawtFwwXDAQIAKE" + "package_ids" => [ + 0 => 42717 + 1 => 42718 + ] +] +*/ +``` + + +### **ORDERPICKUP** + +To order pickup for packages use **orderPickup** method. + +```php +$orderedPickup = $client->orderPickup( + Shipper::CP, + new \DateTime("2018-12-01 14:00"), + new \DateTime("2018-12-01 18:00"), + 5.2, + 3 +); +``` + + +### **SERVICES** + +Method **getServices** returns a list of services that can be used by the shipper. + +The client normalizes the response by returning only **service_type** array. + +```php +$services = $client->getServices("cp"); + +/* +var_dump($services); +[ + "DR" => "DR - Balík Do ruky" + "RR" => "RR - Doporučená zásilka" + "SR" => "RR - Doporučená zásilka - standard" + "NP" => "NP - Balík Na poštu" + "VL" => "VL - Cenné psaní" + ... +] +*/ +``` + + +### **MANIPULATIONUNITS** + +Method **getManipulationUnits** returns a list of possible manipulation units for pallet transport. + +The client normalizes the response by returning unit ID and value from as associative array `[id => value]`. + +This units are used as **mu_type** option in [**ADD**](#add) request. + +```php +$units = $client->getManipulationUnits(Shipper::TOP_TRANS); + +/* +var_dump($units); +[ + "KARTON" => "KARTON" + "KUS" => "KUS" + "PALETA" => "PALETA" + "EPAL" => "EPAL" + "SKLPAL" => "SKLPAL" + "OBALKA" => "OBALKA" + "PYTEL" => "PYTEL" + ... +] +*/ +``` + + +### **BRANCHES** + +Method **getBranches** returns available branches for given shipper and its service type. + +The client normalizes the response by returning only **branches** array. + +```php +$branches = $client->getBranches(Shipper::CP, ServiceType::CP_NP); + +/* +var_dump($shippers); +[ + 0 => [ + "name" => "Kojetice u Prahy" + "city" => "Kojetice" + "street" => "Lipová 75" + "zip" => "25072" + "country" => "CZ" + "type" => "branch" + ] + 1 => [ + ... + ] + ... +] +*/ +``` + + +### **FULLBRANCHES** + +Method **getBranches** returns available branches for given shipper and its service type. + +The client normalizes the response by returning only **branches** array. + +```php +$branches = $client->getBranches(Shipper::ZASILKOVNA, null, true); + +/* +var_dump($shippers); +[ + 0 => [ + "id" => "2859" + "name" => "OMURTAG,ZAVODSKA OMURTAG" + "city" => "OMURTAG" + "street" => "ul. ZAVODSKA 1" + "zip" => "7900" + "district" => "" + "region" => "България" + "country" => "BG" + "currency" => "BGN" + "type" => "branch" + "photo_small" => "https://www.zasilkovna.cz/images/branch/thumb/stub.jpg" + "photo_big" => "https://www.zasilkovna.cz/images/branch/normal/stub.jpg" + "url" => "https://www.zasilkovna.cz/pobocky/omurtag-zavodska" + "latitude" => 43.11715 + "longitude" => 26.42129 + ... + ] + 1 => [ + ... + ] + ... +] +*/ +``` + + +### **COUNTRIES4SERVICE** + +Method **getCountries** returns available countries for service types from given shipper. + +The client normalizes the response by returning only countries for service type as associative array `[service_type => countries]`. + +```php +$countries = $client->getCountries(Shipper::PBH); + +/* +var_dump($countries); +[ + "1" => [ + 0 => "SE" + 1 => "FI" + 2 => "PT" + 3 => "DK" + 4 => "BG" + 5 => "LT" + 6 => "LV" + ... + ] + ... + + "4" => [ + 0 => "SK" + ] + "5" => [ + 0 => "HU" + 1 => "DE" + ] + ... +] +*/ +``` + + +### **ZIPCODES** + +Method **getPostCodes** returns available zipcodes for given shipper, service types and country. + +The client normalizes the response by returning same data format for original **zip**, **zip_range** or **city** response formats. +Use **postcode** instead of **zip** or **zip_start**, **postcode_end** instead of **zipcode_end**, the other attributes remain the same (with `null` value if missing in API response). + +```php +$postcodes = $client->getPostCodes(Shipper::PPL, ServiceType::PPL_BUSINESS); + +/* +var_dump($postcodes); +[ + 0 => [ + "postcode" => "10000" + "postcode_end' => NULL + "city" => NULL + "county" => "CZ" + "1B" => false + ] + 1 => [ + "postcode" => "10003" + "postcode_end' => NULL + "city" => NULL + "county" => "CZ" + "1B" => false + ] + ... +] +*/ +``` + +```php +$postcodes = $client->getPostCodes(Shipper::GEIS, ServiceType::GEIS_PARCEL_PRIVATE)); + +/* +var_dump($postcodes); +[ + 0 => [ + "postcode" => "50755" + "postcode_end' => "50773" + "city" => NULL + "county" => "CZ" + "1B" => false + ] + 1 => [ + "postcode" => "50781" + "postcode_end' => "50792 + "city" => NULL + "county" => "CZ" + "1B" => false + ] + ... +] +*/ +``` + +```php +$postcodes = $client->getPostCodes(Shipper::DHL, ServiceType::DHL_WORLDWIDE, Country::ANDORRA); + +/* +var_dump($postcodes); +[ + 0 => [ + "postcode" => "25999" + "postcode_end' => "25999" + "city" => "AIXIRIVALL" + "county" => "AD" + ] + ... +] +*/ +``` + + +### **CHECK** + +The **checkPackages** method is used to validate data for [**ADD**](#add) request. + +This method has no return value if give data is valid, and it throws exception on error same as **addPackage** request. + + +```php +$client->checkPackages(Shipper::CP, [ + [ + Options::SERVICE_TYPE => ServiceType::CP_NP, + Options::ORDER_ID => "180001", + Options::CUSTOMER_NAME => "Josef Novák", + Options::PRICE => 1500, + ... + ], +]); +``` + +```php +$client->checkPackages(Shipper::CP, [ + [ + // Options::SERVICE_TYPE => ServiceType::CP_NP, + Options::ORDER_ID => "180001", + Options::CUSTOMER_NAME => "Josef Novák", + Options::PRICE => 1500, + ... + ] +]); + +/* +PHP Fatal error: Uncaught Inspirum\Balikobot\Exceptions\BadRequestException: +"Operace neproběhla v pořádku, zkontrolujte konkrétní data" + +"statusCode" => 400 +"errors => [ + 0 => [ + "service_type" => "Nedorazilo ID vybrané služby přepravce." + ] +] +*/ +``` + + +### **ADRUNITS** + +Method **getAdrUnits** returns a list of possible manipulation units for pallet transport. + +The client normalizes the response by returning unit ID and value from as associative array `[id => value]`. + +This units are used as **adr_un** option in [**ADD**](#add) request. + +```php +$units = $client->getAdrUnits(Shipper::TOP_TRANS, ServiceType::TOP_TRANS_STANDARD); + +/* +var_dump($units); +[ + 432 => "PŘEDMĚTY PYROTECHNICKÉ pro technické účely" + 1001 => "ACETYLÉN, ROZPUŠTĚNÝ" + 1002 => "VZDUCH, STLAČENÝ" + 1003 => "VZDUCH, HLUBOCE ZCHLAZENÝ, KAPALNÝ" + 1005 => "AMONIAK (ČPAVEK), BEZVODÝ" + 1006 => "ARGON, STLAČENÝ" + 1008 => "FLUORID BORITÝ" + 1009 => "BROMTRIFLUORMETHAN (PLYN JAKO CHLADICÍ PROSTŘEDEK R 13B1)" + ... +] +*/ +``` + +*** + + +## More usage + + +### [**Definitons**](./definitions.md) + +The module contains several helper classes that contain most of the constants needed to work with the Balikobot API. + + +### [**Balikobot**](./balikobot.md) + +Extension over Client that uses custom DTO classes as an input and output for its methods. diff --git a/docs/definitions.md b/docs/definitions.md new file mode 100755 index 0000000..f6a694f --- /dev/null +++ b/docs/definitions.md @@ -0,0 +1,178 @@ +# Definitons + +The module contains several helper classes that contain most of the constants needed to work with the Balikobot API. + +There are classes for country codes, currency codes, package options, shipper codes and service types: + +- [**Inspirum\Balikobot\Definitions\Country**](../src/Definitions/Country.php) +- [**Inspirum\Balikobot\Definitions\Currency**](../src/Definitions/Currency.php) +- [**Inspirum\Balikobot\Definitions\Option**](../src/Definitions/Option.php) +- [**Inspirum\Balikobot\Definitions\ServiceType**](../src/Definitions/ServiceType.php) +- [**Inspirum\Balikobot\Definitions\Shipper**](../src/Definitions/Shipper.php) + +```php +use Inspirum\Balikobot\Definitions\Shipper; + +var_dump(Shipper::CP); +/* + "cp" +*/ + +var_dump(Shipper::TOP_TRANS); +/* + "toptrans" +*/ + +``` + +```php +use Inspirum\Balikobot\Definitions\ServiceType; + +var_dump(ServiceType::DHL_EXPRESS_WORLDWIDE_12); +/* + "4" +*/ + +var_dump(ServiceType::CP_NP); +/* + "NP" +*/ + +var_dump(ServiceType::DPD_PRIVATE_SATURDAY); +/* + "8" +*/ +``` + +```php +use Inspirum\Balikobot\Definitions\Option; + +var_dump(Option::ORDER_ID); +/* + "real_order_id" +*/ + +var_dump(Option::CUSTOMER_NAME); +/* + "rec_name" +*/ +``` + +```php +use Inspirum\Balikobot\Definitions\Country; + +var_dump(Country::AUSTRIA); +/* + "AT" +*/ +``` + +```php +use Inspirum\Balikobot\Definitions\Currency; + +var_dump(Currency::PLN); +/* + "PLN" +*/ +``` + +These classes also contain static methods for accessing all constants for given type. + +```php +use Inspirum\Balikobot\Definitions\Shipper; + +$shippers = Shipper::all(); + +/* +var_dump($shippers); +[ + 0 => "cp" + 1 => "dhl" + 2 => "dpd" + 3 => "geis" + 4 => "gls" + 5 => "intime" + 6 => "pbh" + 7 => "ppl" + 8 => "sp" + 9 => "toptrans" + 10 => "ulozenka" + 11 => "zasilkovna" +] +*/ +``` + + +```php +use Inspirum\Balikobot\Definitions\ServiceType; + +$services = ServiceType::all(); + +/* +var_dump($services); +[ + "cp" => [ + 0 => "DR" + 1 => "RR" + 2 => "NP" + 3 => "DV" + 4 => "VL" + ... + ] + "dpd" => [ + 0 => "1" + 1 => "2" + ... + ] + ... +] +*/ +``` + +```php +use Inspirum\Balikobot\Definitions\ServiceType; + +$services = ServiceType::topTrans(); + +/* +var_dump($services); +[ + 0 => "1" + 1 => "2" + 2 => "3" + 3 => "4" + 4 => "5" + 5 => "6" +] +*/ +``` + +Other, less used available methods: + +```php +Country::all(); +Country::validateCode("CZE"); +Currency::all(); +Currency::validateCode("RUB"); +Shipper::validateCode("dpd"); +Shipper::hasFullBranchesSupport("cp"); +ServiceType::cp(); +ServiceType::intime(); + +// and more ... +``` + +*** + + +## More usage + + +### [**Client**](./client.md) + +Support all options for Balikobot API described in given documentation. + + +### [**Balikobot**](./balikobot.md) + +Extension over Client that uses custom DTO classes as an input and output for its methods. diff --git a/phpstan.neon.dist b/phpstan.neon.dist new file mode 100644 index 0000000..028f5d3 --- /dev/null +++ b/phpstan.neon.dist @@ -0,0 +1,2 @@ +includes: + - vendor/phpstan/phpstan-mockery/extension.neon \ No newline at end of file diff --git a/phpunit.xml.dist b/phpunit.xml.dist new file mode 100644 index 0000000..fb19951 --- /dev/null +++ b/phpunit.xml.dist @@ -0,0 +1,39 @@ + + + + + ./tests/Integration/ + + + ./tests/Unit/ + + + + + ./src + + src/ + src/Definitions + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/ruleset.xml b/ruleset.xml new file mode 100644 index 0000000..0204244 --- /dev/null +++ b/ruleset.xml @@ -0,0 +1,4 @@ + + + + \ No newline at end of file diff --git a/src/Contracts/ExceptionInterface.php b/src/Contracts/ExceptionInterface.php new file mode 100644 index 0000000..a033453 --- /dev/null +++ b/src/Contracts/ExceptionInterface.php @@ -0,0 +1,36 @@ + 'OK, operace proběhla v pořádku.', + 208 => 'Položka s doloženým ID již existuje. Data, která jsou navrácena, patří k původnímu záznamu.', + 400 => 'Operace neproběhla v pořádku, zkontrolujte konkrétní data.', + 401 => 'Unauthorized - nejspíš chyba na straně Balikobotu', + 403 => 'Přepravce není pro použité klíče aktivovaný.', + 404 => 'Zásilka neexistuje, nebo již byla zpracována.', + 406 => 'Nedorazila žádná data ke zpracování nebo nemůžou být akceptována.', + 409 => 'Konfigurační soubor daného dopravce nebo profil není vyplněn/konflikt mezi přijatými daty u zásilky.', + 413 => 'Špatný formát dat.', + 423 => 'Tato funkce je dostupná jen pro "živé klíče".', + 501 => 'Technologie toho dopravce ještě není implementována, pro bližší informace sledujte web balikobot.cz.', + 503 => 'Technologie dopravce není dostupná, požadavek bude vyřízen později.', + 500 => 'Nepodařilo se rozeznat chybový stav.', + ]; + + /** + * @var array + */ + public static $packageDataErrors = [ + 406 => 'Nedorazila žádná data ke zpracování.', + 409 => 'Nepovolená kombinace služeb dobírky a výměnné zásilky.', + 413 => 'Špatný formát dat.', + 416 => 'Datum má špatný formát nebo není povoleno.', + ]; + + /** + * @var array + */ + public static $packageDataKeyErrors = [ + 406 => [ + 'eid' => 'Nedorazilo eshop ID.', + 'service_type' => 'Nedorazilo ID vybrané služby přepravce.', + 'cod_currency' => 'Nedorazil ISO kód měny.', + 'branch_id' => 'Nedorazilo ID pobočky.', + 'rec_name' => 'Nedorazilo jméno příjemce.', + 'rec_street' => 'Nedorazila ulice s číslem popisným příjemce.', + 'rec_city' => 'Nedorazilo město příjemce.', + 'rec_zip' => 'Nedorazilo PSČ příjemce.', + 'rec_country' => 'Nedorazil ISO kód země příjemce.', + 'rec_phone' => 'Nedorazilo telefonní číslo příjemce.', + 'rec_email' => 'Nedorazil email příjemce.', + 'price' => 'Nedorazila udaná cena zásilky.', + 'vs' => 'Nedorazil variabilní symbol pro dobírkovou zásilku.', + 'service_range' => 'Balíček nelze přidat, protože není vyplněna číselná řada v klientské zóně.', + 'config_data' => 'Balíček nelze přidat, protože chybí potřebná data v klientské zóně.', + 'weight' => 'Nedorazil údaj o váze zásilky.', + ], + 409 => [ + 'cod_price' => 'Nepovolená kombinace služeb dobírky a výměnné zásilky.', + 'swap' => 'Nepovolená kombinace služeb dobírky a výměnné zásilky.', + ], + 413 => [ + 'eid' => 'Eshop ID je delší než je maximální povolená délka.', + 'service_type' => 'Neznámé ID služby přepravce.', + 'cod_price' => 'Nepovolená dobírka.', + 'cod_currency' => 'Nepovolený ISO kód měny.', + 'price' => 'Nepovolená částka udané ceny.', + 'branch_id' => 'Neznámé ID pobočky.', + 'rec_email' => 'Špatný formát emailu příjemce.', + 'order_number' => 'Sdružená zásilka není povolena.', + 'rec_country' => 'Nepovolený ISO kód země příjemce.', + 'rec_zip' => 'Nepovolené PSČ příjemce.', + 'weight' => 'Neplatný formát váhy/váha překračuje maximální povolenou hodnotu.', + 'swap' => 'Výměnná zásilka není pro vybranou službu povolena.', + 'rec_phone' => 'Špatný formát telefonního čísla.', + 'credit_card' => 'Platba kartou není pro tuto službu/pobočku povolena.', + 'service_range' => 'Balíček nelze přidat, protože číselná řada v klientské zóně je již přečerpaná.', + ], + 416 => [ + 'delivery_date' => 'Datum má špatný formát nebo není povoleno.' + ], + ]; +} diff --git a/src/Definitions/ServiceType.php b/src/Definitions/ServiceType.php new file mode 100644 index 0000000..291ebf6 --- /dev/null +++ b/src/Definitions/ServiceType.php @@ -0,0 +1,1062 @@ + self::cp(), + Shipper::DPD => self::dpd(), + Shipper::DHL => self::dhl(), + Shipper::GEIS => self::geis(), + Shipper::GLS => self::gls(), + Shipper::INTIME => self::intime(), + Shipper::PBH => self::pbh(), + Shipper::PPL => self::ppl(), + Shipper::SP => self::sp(), + Shipper::TOP_TRANS => self::topTrans(), + Shipper::ULOZENKA => self::ulozenka(), + Shipper::UPS => self::ups(), + Shipper::ZASILKOVNA => self::zasilkovna(), + ]; + } +} diff --git a/src/Definitions/Shipper.php b/src/Definitions/Shipper.php new file mode 100644 index 0000000..87d9c1f --- /dev/null +++ b/src/Definitions/Shipper.php @@ -0,0 +1,165 @@ +response = $response; + + // overwrite default HTTP status code + $this->statusCode = $statusCode; + + // overwrite default message + if ($message === null) { + $message = Response::$statusCodesErrors[$statusCode] ?? 'Operace neproběhla v pořádku.'; + } + + // construct exception + parent::__construct($message, $statusCode, $previous); + } + + /** + * Get response HTTP status code. + * + * @return int + */ + public function getStatusCode(): int + { + return $this->statusCode; + } + + /** + * Get response as array. + * + * @return array + */ + public function getResponse(): array + { + return $this->response; + } + + /** + * Get response as string. + * + * @return string + */ + public function getResponseAsString(): string + { + return (string) json_encode($this->response); + } + + /** + * Get response errors. + * + * @return array + */ + public function getErrors(): array + { + return $this->errors; + } +} diff --git a/src/Exceptions/BadRequestException.php b/src/Exceptions/BadRequestException.php new file mode 100644 index 0000000..585365b --- /dev/null +++ b/src/Exceptions/BadRequestException.php @@ -0,0 +1,125 @@ +setErrors($response); + + parent::__construct($response, $statusCode, $previous, $message); + } + + /** + * Set errors from response. + * + * @param array $response + * + * @return void + */ + private function setErrors(array $response): void + { + $i = 0; + + // add erros from all packages + while (isset($response[$i])) { + // set errors for package + $this->setErrorsForPackage($i, $response[$i]); + + // try next package + $i++; + } + } + + /** + * @param int $number + * @param array $response + * + * @return void + */ + private function setErrorsForPackage(int $number, array $response): void + { + // response does not have full errors + if (isset($response['errors']) === false) { + // try to resolve errors from codes + $this->setErrorsFromResponseCodes($number, $response); + + return; + } + + // set erros for given package + foreach ($response['errors'] as $error) { + $this->setError($number, $error['attribute'], $error['message']); + } + } + + /** + * @param int $number + * @param array $response + * + * @return void + */ + private function setErrorsFromResponseCodes(int $number, array $response) + { + foreach ($response as $key => $code) { + // skip non-numeric codes + if (is_numeric($code) === false || $code < 400) { + continue; + } + + // get error message from code + $error = $this->getErrorMessage($key, (int) $code); + + // set erros fro given package from response codes + $this->setError($number, $key, $error); + } + } + + /** + * @param string $key + * @param int $code + * + * @return string + */ + private function getErrorMessage(string $key, int $code): string + { + // get error message from code + if ($key === 'status') { + return Response::$statusCodesErrors[$code] ?? Response::$statusCodesErrors[500]; + } + + if (isset(Response::$packageDataKeyErrors[$code][$key])) { + return Response::$packageDataKeyErrors[$code][$key]; + } + + return Response::$packageDataErrors[$code] ?? 'Nespecifikovaná chyba.'; + } + + /** + * @param int $number + * @param string $key + * @param string $error + * + * @return void + */ + private function setError(int $number, string $key, string $error): void + { + $this->errors[$number][$key] = $error; + } +} diff --git a/src/Exceptions/UnauthorizedException.php b/src/Exceptions/UnauthorizedException.php new file mode 100644 index 0000000..350f0ea --- /dev/null +++ b/src/Exceptions/UnauthorizedException.php @@ -0,0 +1,20 @@ +shipper = $shipper; + } + + /** + * Add package. + * + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @throws \InvalidArgumentException + */ + public function add(OrderedPackage $package): void + { + //validate package shipper + $this->validateShipper($package); + + // add package to collection + $this->packages[] = $package; + } + + /** + * Get shipper. + * + * @return string + */ + public function getShipper(): string + { + if ($this->shipper === null) { + throw new RuntimeException('No shipper is set.'); + } + + return $this->shipper; + } + + /** + * Get package IDs. + * + * @return int[] + */ + public function getPackageIds(): array + { + return array_map(function (OrderedPackage $package) { + return $package->getPackageId(); + }, $this->packages); + } + + /** + * Get carrier IDs. + * + * @return int[] + */ + public function getCarrierIds(): array + { + return array_map(function (OrderedPackage $package) { + return $package->getCarrierId(); + }, $this->packages); + } + + /** + * Validate shipper + * + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @return void + * + * @throws \InvalidArgumentException + */ + private function validateShipper(OrderedPackage $package): void + { + // set shipper if first package in collection + if ($this->shipper === null) { + $this->shipper = $package->getShipper(); + } + + // validate shipper + if ($this->shipper !== $package->getShipper()) { + throw new InvalidArgumentException( + sprintf( + 'Package is from different shipper ("%s" instead of "%s")', + $package->getShipper(), + $this->shipper + ) + ); + } + } + + /** + * Get an iterator for the items. + * + * @return \ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->packages); + } + + /** + * Determine if an item exists at an offset. + * + * @param string $key + * + * @return bool + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->packages); + } + + /** + * Get an item at a given offset. + * + * @param string $key + * + * @return \Inspirum\Balikobot\Model\Values\OrderedPackage + */ + public function offsetGet($key) + { + return $this->packages[$key]; + } + + /** + * Set the item at a given offset. + * + * @param string $key + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $value + * + * @return void + */ + public function offsetSet($key, $value) + { + $this->validateShipper($value); + + $this->packages[$key] = $value; + } + + /** + * Unset the item at a given offset. + * + * @param string $key + * + * @return void + */ + public function offsetUnset($key) + { + unset($this->packages[$key]); + } + + /** + * Count elements of an object + * + * @return int + */ + public function count(): int + { + return count($this->packages); + } +} diff --git a/src/Model/Aggregates/PackageCollection.php b/src/Model/Aggregates/PackageCollection.php new file mode 100644 index 0000000..2c826e0 --- /dev/null +++ b/src/Model/Aggregates/PackageCollection.php @@ -0,0 +1,123 @@ +shipper = $shipper; + $this->eid = $eid ?: $this->newEID(); + } + + /** + * Add package to collection. + * + * @param \Inspirum\Balikobot\Model\Values\Package $package + */ + public function add(Package $package): void + { + // clone package + $package = clone $package; + + // set collection EID + $package->setEID($this->eid); + + // add package to collection + $this->packages[] = $package; + } + + /** + * Get packages shipper. + * + * @return string + */ + public function getShipper(): string + { + return $this->shipper; + } + + /** + * Get packages EID. + * + * @return string + */ + public function getEid(): string + { + return $this->eid; + } + + /** + * Get an iterator for the items. + * + * @return \ArrayIterator + */ + public function getIterator(): ArrayIterator + { + return new ArrayIterator($this->packages); + } + + /** + * Get the collection of packages as a plain array. + * + * @return array[] + */ + public function toArray(): array + { + return array_map(function (Package $package) { + return $package->toArray(); + }, $this->packages); + } + + /** + * Count elements of an object + * + * @return int + */ + public function count(): int + { + return count($this->packages); + } + + /** + * Get new EID for package batch. + * + * @return string + */ + private function newEID(): string + { + return time() . uniqid(); + } +} diff --git a/src/Model/Values/AbstractPackage.php b/src/Model/Values/AbstractPackage.php new file mode 100644 index 0000000..013a212 --- /dev/null +++ b/src/Model/Values/AbstractPackage.php @@ -0,0 +1,87 @@ +data = $data; + } + + use CommonData; + + /** + * Determine if an item exists at an offset. + * + * @param string $key + * + * @return bool + */ + public function offsetExists($key) + { + return array_key_exists($key, $this->data); + } + + /** + * Get an item at a given offset. + * + * @param string $key + * + * @return mixed + */ + public function offsetGet($key) + { + return $this->data[$key]; + } + + /** + * Set the item at a given offset. + * + * @param string $key + * @param mixed $value + * + * @return void + */ + public function offsetSet($key, $value) + { + $this->data[$key] = $value; + } + + /** + * Unset the item at a given offset. + * + * @param string $key + * + * @return void + */ + public function offsetUnset($key) + { + unset($this->data[$key]); + } + + /** + * Get the collection of packages as a plain array. + * + * @return array + */ + public function toArray(): array + { + return $this->data; + } +} diff --git a/src/Model/Values/Branch.php b/src/Model/Values/Branch.php new file mode 100644 index 0000000..2caa737 --- /dev/null +++ b/src/Model/Values/Branch.php @@ -0,0 +1,612 @@ +shipper = $shipper; + $this->service = $service; + $this->id = $id; + $this->type = $type; + $this->name = $name; + $this->city = $city; + $this->street = $street; + $this->zip = $zip; + $this->cityPart = $cityPart; + $this->district = $district; + $this->region = $region; + $this->country = $country; + $this->currency = $currency; + $this->photoSmall = $photoSmall; + $this->photoBig = $photoBig; + $this->url = $url; + $this->latitude = $latitude; + $this->longitude = $longitude; + $this->directionsGlobal = $directionsGlobal; + $this->directionsCar = $directionsCar; + $this->directionsPublic = $directionsPublic; + $this->wheelchairAccessible = $wheelchairAccessible; + $this->claimAssistant = $claimAssistant; + $this->dressingRoom = $dressingRoom; + $this->openingMonday = $openingMonday; + $this->openingTuesday = $openingTuesday; + $this->openingWednesday = $openingWednesday; + $this->openingThursday = $openingThursday; + $this->openingFriday = $openingFriday; + $this->openingSaturday = $openingSaturday; + $this->openingSunday = $openingSunday; + + $this->setBranchId(); + } + + /** + * @return string + */ + public function getShipper(): string + { + return $this->shipper; + } + + /** + * @return string|null + */ + public function getServiceType(): ?string + { + return $this->service; + } + + /** + * @return string + */ + public function getBranchId(): string + { + return $this->branchId; + } + + /** + * @return string|null + */ + public function getId(): ?string + { + return $this->id; + } + + /** + * @return string + */ + public function getType(): string + { + return $this->type; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return string + */ + public function getCity(): string + { + return $this->city; + } + + /** + * @return string + */ + public function getStreet(): string + { + return $this->street; + } + + /** + * @return string + */ + public function getZip(): string + { + return $this->zip; + } + + /** + * @return string|null + */ + public function getCityPart(): ?string + { + return $this->cityPart; + } + + /** + * @return string|null + */ + public function getDistrict(): ?string + { + return $this->district; + } + + /** + * @return string|null + */ + public function getRegion(): ?string + { + return $this->region; + } + + /** + * @return string|null + */ + public function getCountry(): ?string + { + return $this->country; + } + + /** + * @return string|null + */ + public function getCurrency(): ?string + { + return $this->currency; + } + + /** + * @return string|null + */ + public function getPhotoSmall(): ?string + { + return $this->photoSmall; + } + + /** + * @return string|null + */ + public function getPhotoBig(): ?string + { + return $this->photoBig; + } + + /** + * @return string|null + */ + public function getUrl(): ?string + { + return $this->url; + } + + /** + * @return float|null + */ + public function getLatitude(): ?float + { + return $this->latitude; + } + + /** + * @return float|null + */ + public function getLongitude(): ?float + { + return $this->longitude; + } + + /** + * @return string|null + */ + public function getDirectionsGlobal(): ?string + { + return $this->directionsGlobal; + } + + /** + * @return string|null + */ + public function getDirectionsCar(): ?string + { + return $this->directionsCar; + } + + /** + * @return string|null + */ + public function getDirectionsPublic(): ?string + { + return $this->directionsPublic; + } + + /** + * @return bool|null + */ + public function getWheelchairAccessible(): ?bool + { + return $this->wheelchairAccessible; + } + + /** + * @return bool|null + */ + public function getClaimAssistant(): ?bool + { + return $this->claimAssistant; + } + + /** + * @return bool|null + */ + public function getDressingRoom(): ?bool + { + return $this->dressingRoom; + } + + /** + * @return string|null + */ + public function getOpeningMonday(): ?string + { + return $this->openingMonday; + } + + /** + * @return string|null + */ + public function getOpeningTuesday(): ?string + { + return $this->openingTuesday; + } + + /** + * @return string|null + */ + public function getOpeningWednesday(): ?string + { + return $this->openingWednesday; + } + + /** + * @return string|null + */ + public function getOpeningThursday(): ?string + { + return $this->openingThursday; + } + + /** + * @return string|null + */ + public function getOpeningFriday(): ?string + { + return $this->openingFriday; + } + + /** + * @return string|null + */ + public function getOpeningSaturday(): ?string + { + return $this->openingSaturday; + } + + /** + * @return string|null + */ + public function getOpeningSunday(): ?string + { + return $this->openingSunday; + } + + /** + * Set branch ID. + * + * @return void + */ + private function setBranchId(): void + { + $this->branchId = $this->resolveBranchId(); + } + + /** + * Resolve branch ID. + * + * @return string + */ + private function resolveBranchId(): string + { + // get key used in branch_id when calling add request + if ($this->shipper === Shipper::CP + || $this->shipper === Shipper::SP + || ($this->shipper === Shipper::ULOZENKA && $this->service === ServiceType::ULOZENKA_CP_NP) + ) { + return str_replace(' ', '', $this->zip); + } + + if ($this->shipper === Shipper::PPL) { + return str_replace('KM', '', (string) $this->id); + } + + if ($this->shipper === Shipper::INTIME) { + return $this->name; + } + + return (string) $this->id; + } + + /** + * New instance from data + * + * @param string $shipper + * @param string|null $service + * @param array $data + * + * @return \Inspirum\Balikobot\Model\Values\Branch + */ + public static function newInstanceFromData(string $shipper, ?string $service, array $data): self + { + return new self( + $shipper, + $service, + $data['id'] ?? null, + $data['type'] ?? 'branch', + $data['name'] ?? $data['zip'], + $data['city'] ?? '', + $data['street'] ?? ($data['address'] ?? ''), + $data['zip'], + $data['country'] ?? null, + $data['city_part'] ?? null, + $data['district'] ?? null, + $data['region'] ?? null, + $data['currency'] ?? null, + $data['photo_small'] ?? null, + $data['photo_big'] ?? null, + $data['url'] ?? null, + $data['latitude'] ?? null, + $data['longitude'] ?? null, + $data['directions_global'] ?? null, + $data['directions_car'] ?? null, + $data['directions_public'] ?? null, + $data['wheelchair_accessible'] ?? null, + $data['claim_assistant'] ?? null, + $data['dressing_room'] ?? null, + $data['opening_monday'] ?? null, + $data['opening_tuesday'] ?? null, + $data['opening_wednesday'] ?? null, + $data['opening_thursday'] ?? null, + $data['opening_friday'] ?? null, + $data['opening_saturday'] ?? null, + $data['opening_sunday'] ?? null + ); + } +} diff --git a/src/Model/Values/OrderedPackage.php b/src/Model/Values/OrderedPackage.php new file mode 100644 index 0000000..932efa6 --- /dev/null +++ b/src/Model/Values/OrderedPackage.php @@ -0,0 +1,179 @@ +packageId = $packageId; + $this->shipper = $shipper; + $this->batchId = $batchId; + $this->carrierId = $carrierId; + $this->trackUrl = $trackUrl; + $this->labelUrl = $labelUrl; + $this->carrierIdSwap = $carrierIdSwap; + $this->pieces = $pieces; + } + + /** + * @return int + */ + public function getPackageId(): int + { + return $this->packageId; + } + + /** + * @return string + */ + public function getBatchId(): string + { + return $this->batchId; + } + + /** + * @return string + */ + public function getCarrierId(): string + { + return $this->carrierId; + } + + /** + * @return string|null + */ + public function getTrackUrl(): ?string + { + return $this->trackUrl; + } + + /** + * @return string|null + */ + public function getLabelUrl(): ?string + { + return $this->labelUrl; + } + + /** + * @return string|null + */ + public function getCarrierIdSwap(): ?string + { + return $this->carrierIdSwap; + } + + /** + * @return array + */ + public function getPieces(): array + { + return $this->pieces; + } + + /** + * @return string + */ + public function getShipper(): string + { + return $this->shipper; + } + + /** + * @param string $shipper + * @param string $eid + * @param array $data + * + * @return \Inspirum\Balikobot\Model\Values\OrderedPackage + */ + public static function newInstanceFromData(string $shipper, string $eid, array $data): self + { + return new self( + $data['package_id'], + $shipper, + $eid, + $data['carrier_id'], + $data['track_url'] ?? null, + $data['label_url'], + $data['carrier_id_swap'] ?? null, + $data['pieces'] ?? [] + ); + } +} diff --git a/src/Model/Values/OrderedShipment.php b/src/Model/Values/OrderedShipment.php new file mode 100644 index 0000000..5d4b861 --- /dev/null +++ b/src/Model/Values/OrderedShipment.php @@ -0,0 +1,155 @@ +orderId = $orderId; + $this->shipper = $shipper; + $this->packageIds = $packageIds; + $this->handoverUrl = $handoverUrl; + $this->labelsUrl = $labelsUrl; + $this->date = $date; + $this->fileUrl = $fileUrl; + } + + /** + * @return string + */ + public function getOrderId(): string + { + return $this->orderId; + } + + /** + * @return string + */ + public function getHandoverUrl(): string + { + return $this->handoverUrl; + } + + /** + * @return string + */ + public function getLabelsUrl(): string + { + return $this->labelsUrl; + } + + /** + * @return string|null + */ + public function getFileUrl(): ?string + { + return $this->fileUrl; + } + + /** + * @return \DateTime|null + */ + public function getDate(): ?DateTime + { + return $this->date; + } + + /** + * @return string + */ + public function getShipper(): string + { + return $this->shipper; + } + + /** + * Get package IDs. + * + * @return int[] + */ + public function getPackageIds(): array + { + return $this->packageIds; + } + + /** + * @param string $shipper + * @param array $packageIds + * @param array $data + * @param \DateTime|null $date + * + * @return \Inspirum\Balikobot\Model\Values\OrderedShipment + */ + public static function newInstanceFromData( + string $shipper, + array $packageIds, + array $data, + DateTime $date = null + ): self { + return new self( + $data['order_id'], + $shipper, + $packageIds, + $data['handover_url'], + $data['labels_url'], + $date, + $data['file_url'] ?? null + ); + } +} diff --git a/src/Model/Values/Package.php b/src/Model/Values/Package.php new file mode 100644 index 0000000..31084ef --- /dev/null +++ b/src/Model/Values/Package.php @@ -0,0 +1,22 @@ +offsetSet(Option::COD_PRICE, $codPrice); + } + + /** + * @param string $codCurrency + * + * @return void + */ + public function setCodCurrency(string $codCurrency): void + { + $this->offsetSet(Option::COD_CURRENCY, $codCurrency); + } + + /** + * @param string $vs + * + * @return void + */ + public function setVS(string $vs): void + { + $this->offsetSet(Option::VS, $vs); + } + + /** + * @param bool $creditCard + * + * @return void + */ + public function setCreditCard(bool $creditCard = true): void + { + $this->offsetSet(Option::CREDIT_CARD, (int) $creditCard); + } +} diff --git a/src/Model/Values/Package/CommonData.php b/src/Model/Values/Package/CommonData.php new file mode 100644 index 0000000..1857aed --- /dev/null +++ b/src/Model/Values/Package/CommonData.php @@ -0,0 +1,121 @@ +offsetSet(Option::EID, $id); + } + + /** + * Get EID. + * + * @return string|null + */ + public function getEID(): ?string + { + return $this->offsetGet(Option::EID); + } + + /** + * @param int $orderNumber + * + * @return void + */ + public function setOrderNumber(int $orderNumber): void + { + $this->offsetSet(Option::ORDER_NUMBER, $orderNumber); + } + + /** + * @param string $realOrderId + * + * @return void + */ + public function setRealOrderId(string $realOrderId): void + { + $this->offsetSet(Option::REAL_ORDER_ID, $realOrderId); + } + + /** + * @param string $serviceType + * + * @return void + */ + public function setServiceType(string $serviceType): void + { + $this->offsetSet(Option::SERVICE_TYPE, $serviceType); + } + + /** + * @param array $services + * + * @return void + */ + public function setServices(array $services): void + { + // TODO: add validation + + $this->offsetSet(Option::SERVICES, implode('+', $services)); + } + + /** + * @param string $branchId + * + * @return void + */ + public function setBranchId(string $branchId): void + { + $this->offsetSet(Option::BRANCH_ID, $branchId); + } + + /** + * @param bool $fullErrors + * + * @return void + */ + public function setReturnFullErrors(bool $fullErrors = true): void + { + $this->offsetSet(Option::RETURN_FULL_ERRORS, (int) $fullErrors); + } + + /** + * @param bool $returnTrack + * + * @return void + */ + public function setReturnTrack(bool $returnTrack = true): void + { + $this->offsetSet(Option::RETURN_TRACK, (int) $returnTrack); + } +} diff --git a/src/Model/Values/Package/CustomerData.php b/src/Model/Values/Package/CustomerData.php new file mode 100644 index 0000000..4194212 --- /dev/null +++ b/src/Model/Values/Package/CustomerData.php @@ -0,0 +1,118 @@ +offsetSet(Option::REC_NAME, $name); + } + + /** + * @param string $firm + * + * @return void + */ + public function setRecFirm(string $firm): void + { + $this->offsetSet(Option::REC_FIRM, $firm); + } + + /** + * @param string $street + * + * @return void + */ + public function setRecStreet(string $street): void + { + $this->offsetSet(Option::REC_STREET, $street); + } + + /** + * @param string $city + * + * @return void + */ + public function setRecCity(string $city): void + { + $this->offsetSet(Option::REC_CITY, $city); + } + + /** + * @param string $zip + * + * @return void + */ + public function setRecZip(string $zip): void + { + $this->offsetSet(Option::REC_ZIP, $zip); + } + + /** + * @param string $recRegion + * + * @return void + */ + public function setRecRegion(string $recRegion): void + { + $this->offsetSet(Option::REC_REGION, $recRegion); + } + + /** + * @param string $country + * + * @return void + */ + public function setRecCountry(string $country): void + { + $this->offsetSet(Option::REC_COUNTRY, $country); + } + + /** + * @param string $email + * + * @return void + */ + public function setRecEmail(string $email): void + { + $this->offsetSet(Option::REC_EMAIL, $email); + } + + /** + * @param string $phone + * + * @return void + */ + public function setRecPhone(string $phone): void + { + $this->offsetSet(Option::REC_PHONE, $phone); + } + + /** + * @param string $bankAccount + * + * @return void + */ + public function setBankAccountNumber(string $bankAccount): void + { + $this->offsetSet(Option::BANK_ACCOUNT_NUMBER, $bankAccount); + } +} diff --git a/src/Model/Values/Package/DeliveryData.php b/src/Model/Values/Package/DeliveryData.php new file mode 100644 index 0000000..d504eec --- /dev/null +++ b/src/Model/Values/Package/DeliveryData.php @@ -0,0 +1,239 @@ +offsetSet(Option::NOTE_DRIVER, $noteDriver); + } + + /** + * @param string $noteCustomer + * + * @return void + */ + public function setNoteCustomer(string $noteCustomer): void + { + $this->offsetSet(Option::NOTE_CUSTOMER, $noteCustomer); + } + + /** + * @param bool $comfortExclusiveService + * + * @return void + */ + public function setComfortExclusiveService(bool $comfortExclusiveService = true): void + { + $this->offsetSet(Option::COMFORT_EXCLUSIVE_SERVICE, (int) $comfortExclusiveService); + } + + /** + * @param bool $persDeliveryFloor + * + * @return void + */ + public function setPersDeliveryFloor(bool $persDeliveryFloor = true): void + { + $this->offsetSet(Option::PERS_DELIVERY_FLOOR, (int) $persDeliveryFloor); + } + + /** + * @param bool $persDeliveryBuilding + * + * @return void + */ + public function setPersDeliveryBuilding(bool $persDeliveryBuilding = true): void + { + $this->offsetSet(Option::PERS_DELIVERY_BUILDING, (int) $persDeliveryBuilding); + } + + /** + * @param bool $persDeliveryDepartment + * + * @return void + */ + public function setPersDeliveryDepartment(bool $persDeliveryDepartment = true): void + { + $this->offsetSet(Option::PERS_DELIVERY_DEPARTMENT, (int) $persDeliveryDepartment); + } + + /** + * @param string $pin + * + * @return void + */ + public function setPIN(string $pin): void + { + $this->offsetSet(Option::PIN, $pin); + } + + /** + * @param bool $satDelivery + * + * @return void + */ + public function setSatDelivery(bool $satDelivery = true): void + { + $this->offsetSet(Option::SAT_DELIVERY, (int) $satDelivery); + } + + /** + * @param bool $requireFullAge + * + * @return void + */ + public function setRequireFullAge(bool $requireFullAge = true): void + { + $this->offsetSet(Option::REQUIRE_FULL_AGE, (int) $requireFullAge); + } + + /** + * @param string $fullAgeData + * + * @return void + */ + public function setFullAgeData(string $fullAgeData): void + { + $this->offsetSet(Option::FULL_AGE_DATA, $fullAgeData); + } + + /** + * @param string $password + * + * @return void + */ + public function setPassword(string $password): void + { + $this->offsetSet(Option::PASSWORD, $password); + } + + /** + * @param bool $delInsurance + * + * @return void + */ + public function setDelInsurance(bool $delInsurance = true): void + { + $this->offsetSet(Option::DEL_INSURANCE, (int) $delInsurance); + } + + /** + * @param bool $delEvening + * + * @return void + */ + public function setDelEvening(bool $delEvening = true): void + { + $this->offsetSet(Option::DEL_EVENING, (int) $delEvening); + } + + /** + * @param bool $delExworks + * + * @return void + */ + public function setDelExworks(bool $delExworks = true): void + { + $this->offsetSet(Option::DEL_EXWORKS, (int) $delExworks); + } + + /** + * @param bool $comfort + * + * @return void + */ + public function setComfortService(bool $comfort = true): void + { + $this->offsetSet(Option::COMFORT_SERVICE, (int) $comfort); + } + + /** + * @param bool $comfort + * + * @return void + */ + public function setComfortServicePlus(bool $comfort = true): void + { + $this->offsetSet(Option::COMFORT_SERVICE_PLUS, (int) $comfort); + } + + /** + * @param \DateTime $deliveryDate + * + * @return void + */ + public function setDeliveryDate(DateTime $deliveryDate): void + { + $this->offsetSet(Option::DELIVERY_DATE, $deliveryDate->format('Y-m-d')); + } + + /** + * @param bool $swap + * + * @return void + */ + public function setSwap(bool $swap): void + { + $this->offsetSet(Option::SWAP, (int) $swap); + } + + /** + * @param string $swapOption + * + * @return void + */ + public function setSwapOption(string $swapOption): void + { + $this->offsetSet(Option::SWAP_OPTION, $swapOption); + } + + /** + * @param bool $openBeforePayment + * + * @return void + */ + public function setOpenBeforePayment(bool $openBeforePayment = true): void + { + $this->offsetSet(Option::OPEN_BEFORE_PAYMENT, (int) $openBeforePayment); + } + + /** + * @param bool $testBeforePayment + * + * @return void + */ + public function setTestBeforePayment(bool $testBeforePayment = true): void + { + $this->offsetSet(Option::TEST_BEFORE_PAYMENT, (int) $testBeforePayment); + } + + /** + * @param string $note + * + * @return void + */ + public function setNote(string $note): void + { + $this->offsetSet(Option::NOTE, $note); + } +} diff --git a/src/Model/Values/Package/ForeignCountryDeliveryData.php b/src/Model/Values/Package/ForeignCountryDeliveryData.php new file mode 100644 index 0000000..a9c1473 --- /dev/null +++ b/src/Model/Values/Package/ForeignCountryDeliveryData.php @@ -0,0 +1,58 @@ +offsetSet(Option::INVOICE_NUMBER, $invoiceNumber); + } + + /** + * @param string $pdf + * + * @return void + */ + public function setInvoicePDF(string $pdf): void + { + $this->offsetSet(Option::INVOICE_PDF, $pdf); + } + + /** + * @param string $terms + * + * @return void + */ + public function setTermsOfTrade(string $terms): void + { + $this->offsetSet(Option::TERMS_OF_TRADE, $terms); + } + + /** + * @param array $contentData + * + * @return void + */ + public function setContentData(array $contentData): void + { + $this->offsetSet(Option::CONTENT_DATA, $contentData); + } +} diff --git a/src/Model/Values/Package/NotificationData.php b/src/Model/Values/Package/NotificationData.php new file mode 100644 index 0000000..dfeb8e1 --- /dev/null +++ b/src/Model/Values/Package/NotificationData.php @@ -0,0 +1,78 @@ +offsetSet(Option::SMS_NOTIFICATION, (int) $notification); + } + + /** + * @param bool $phoneDeliveryNotification + * + * @return void + */ + public function setPhoneDeliveryNotification(bool $phoneDeliveryNotification = true): void + { + $this->offsetSet(Option::PHONE_DELIVERY_NOTIFICATION, (int) $phoneDeliveryNotification); + } + + /** + * @param bool $phoneOrderNotification + * + * @return void + */ + public function setPhoneOrderNotification(bool $phoneOrderNotification = true): void + { + $this->offsetSet(Option::PHONE_ORDER_NOTIFICATION, (int) $phoneOrderNotification); + } + + /** + * @param bool $emailNotification + * + * @return void + */ + public function setEmailNotification(bool $emailNotification = true): void + { + $this->offsetSet(Option::EMAIL_NOTIFICATION, (int) $emailNotification); + } + + /** + * @param bool $phoneNotification + * + * @return void + */ + public function setPhoneNotification(bool $phoneNotification = true): void + { + $this->offsetSet(Option::PHONE_NOTIFICATION, (int) $phoneNotification); + } + + /** + * @param bool $b2cNotification + * + * @return void + */ + public function setB2CNotification(bool $b2cNotification = true): void + { + $this->offsetSet(Option::B2C_NOTIFICATION, (int) $b2cNotification); + } +} diff --git a/src/Model/Values/Package/PackageData.php b/src/Model/Values/Package/PackageData.php new file mode 100644 index 0000000..00db212 --- /dev/null +++ b/src/Model/Values/Package/PackageData.php @@ -0,0 +1,88 @@ +offsetSet(Option::WIDTH, $width); + } + + /** + * @param float $length + * + * @return void + */ + public function setLength(float $length): void + { + $this->offsetSet(Option::LENGTH, $length); + } + + /** + * @param float $height + * + * @return void + */ + public function setHeigth(float $height): void + { + $this->offsetSet(Option::HEIGHT, $height); + } + + /** + * @param float $weight + * + * @return void + */ + public function setWeight(float $weight): void + { + $this->offsetSet(Option::WEIGHT, $weight); + } + + /** + * @param float $price + * + * @return void + */ + public function setPrice(float $price): void + { + $this->offsetSet(Option::PRICE, $price); + } + + /** + * @param float $volume + * + * @return void + */ + public function setVolume(float $volume): void + { + $this->offsetSet(Option::VOLUME, $volume); + } + + /** + * @param bool $overDimension + * + * @return void + */ + public function setOverDimension(bool $overDimension = true): void + { + $this->offsetSet(Option::OVER_DIMENSION, (int) $overDimension); + } +} diff --git a/src/Model/Values/Package/ParcelPackageData.php b/src/Model/Values/Package/ParcelPackageData.php new file mode 100644 index 0000000..c7b9c5a --- /dev/null +++ b/src/Model/Values/Package/ParcelPackageData.php @@ -0,0 +1,208 @@ +offsetSet(Option::MU_TYPE, $muType); + } + + /** + * @param int $piecesCount + * + * @return void + */ + public function setPiecesCount(int $piecesCount): void + { + $this->offsetSet(Option::PIECES_COUNT, $piecesCount); + } + + /** + * @param string $muType + * + * @return void + */ + public function setMuTypeOne(string $muType): void + { + $this->offsetSet(Option::MU_TYPE_ONE, $muType); + } + + /** + * @param int $piecesCount + * + * @return void + */ + public function setPiecesCountOne(int $piecesCount): void + { + $this->offsetSet(Option::PIECES_COUNT_ONE, $piecesCount); + } + + /** + * @param string $muType + * + * @return void + */ + public function setMuTypeTwo(string $muType): void + { + $this->offsetSet(Option::MU_TYPE_TWO, $muType); + } + + /** + * @param int $piecesCount + * + * @return void + */ + public function setPiecesCountTwo(int $piecesCount): void + { + $this->offsetSet(Option::PIECES_COUNT_TWO, $piecesCount); + } + + /** + * @param string $muType + * + * @return void + */ + public function setMuTypeThree(string $muType): void + { + $this->offsetSet(Option::MU_TYPE_THREE, $muType); + } + + /** + * @param int $piecesCount + * + * @return void + */ + public function setPiecesCountThree(int $piecesCount): void + { + $this->offsetSet(Option::PIECES_COUNT_THREE, $piecesCount); + } + + /** + * @param int $wrapBackCount + * + * @return void + */ + public function setWrapBackCount(int $wrapBackCount): void + { + $this->offsetSet(Option::WRAP_BACK_COUNT, $wrapBackCount); + } + + /** + * @param string $wrapBackNote + * + * @return void + */ + public function setWrapBackNote(string $wrapBackNote): void + { + $this->offsetSet(Option::WRAP_BACK_NOTE, $wrapBackNote); + } + + /** + * @param bool $appDisp + * + * @return void + */ + public function setAppDisp(bool $appDisp = true): void + { + $this->offsetSet(Option::APP_DISP, (int) $appDisp); + } + + /** + * @param string $content + * + * @return void + */ + public function setContent(string $content): void + { + $this->offsetSet(Option::CONTENT, $content); + } + + /** + * @param bool $getPiecesNumbers + * + * @return void + */ + public function setGetPiecesNumbers(bool $getPiecesNumbers = true): void + { + $this->offsetSet(Option::GET_PIECES_NUMBERS, (int) $getPiecesNumbers); + } + + /** + * @param string $contentOne + * + * @return void + */ + public function setContentOne(string $contentOne): void + { + $this->offsetSet(Option::CONTENT_ONE, $contentOne); + } + + /** + * @param string $contentTwo + * + * @return void + */ + public function setContentTwo(string $contentTwo): void + { + $this->offsetSet(Option::CONTENT_TWO, $contentTwo); + } + + /** + * @param string $contentThree + * + * @return void + */ + public function setContentThree(string $contentThree): void + { + $this->offsetSet(Option::CONTENT_THREE, $contentThree); + } + + /** + * @param bool $adrService + * + * @return void + */ + public function setAdrService(bool $adrService = true): void + { + $this->offsetSet(Option::ADR_SERVICE, (int) $adrService); + } + + /** + * @param array $adrContent + * + * @return void + */ + public function setAdrContent(array $adrContent): void + { + $this->offsetSet(Option::ADR_CONTENT, $adrContent); + } + + /** + * @param bool $vdlService + * + * @return void + */ + public function setVDLService(bool $vdlService): void + { + $this->offsetSet(Option::VDL_SERVICE, (int) $vdlService); + } +} diff --git a/src/Model/Values/PackageStatus.php b/src/Model/Values/PackageStatus.php new file mode 100644 index 0000000..0e135cd --- /dev/null +++ b/src/Model/Values/PackageStatus.php @@ -0,0 +1,78 @@ +id = $id; + $this->name = $name; + $this->date = $date; + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return string + */ + public function getName(): string + { + return $this->name; + } + + /** + * @return \DateTime|null + */ + public function getDate(): ?DateTime + { + return $this->date; + } + + /** + * @param array $data + * + * @return \Inspirum\Balikobot\Model\Values\PackageStatus + */ + public static function newInstanceFromData(array $data): self + { + try { + $date = $data['date'] ? new DateTime($data['date']) : null; + } catch (Throwable $exception) { + $date = null; + } + + return new self($data['status_id'], $data['name'], $date); + } +} diff --git a/src/Model/Values/PostCode.php b/src/Model/Values/PostCode.php new file mode 100644 index 0000000..904d14d --- /dev/null +++ b/src/Model/Values/PostCode.php @@ -0,0 +1,148 @@ +shipper = $shipper; + $this->service = $service; + $this->postcode = $postcode; + $this->postcodeEnd = $postcodeEnd; + $this->city = $city; + $this->country = $country; + $this->morningDelivery = $morningDelivery; + } + + /** + * @return string + */ + public function getShipper(): string + { + return $this->shipper; + } + + /** + * @return string|null + */ + public function getService(): ?string + { + return $this->service; + } + + /** + * @return string + */ + public function getPostcode(): string + { + return $this->postcode; + } + + /** + * @return string|null + */ + public function getPostcodeEnd(): ?string + { + return $this->postcodeEnd; + } + + /** + * @return string|null + */ + public function getCity(): ?string + { + return $this->city; + } + + /** + * @return string|null + */ + public function getCountry(): ?string + { + return $this->country; + } + + /** + * @return bool + */ + public function isMorningDelivery(): bool + { + return $this->morningDelivery; + } + + /** + * New instance from data + * + * @param string $shipper + * @param string|null $service + * @param array $data + * + * @return \Inspirum\Balikobot\Model\Values\PostCode + */ + public static function newInstanceFromData(string $shipper, ?string $service, array $data): self + { + return new self( + $shipper, + $service, + $data['postcode'], + $data['postcode_end'] ?? null, + $data['city'] ?? null, + $data['country'] ?? null, + $data['1B'] ?? false + ); + } +} diff --git a/src/Services/Balikobot.php b/src/Services/Balikobot.php new file mode 100644 index 0000000..41120c9 --- /dev/null +++ b/src/Services/Balikobot.php @@ -0,0 +1,416 @@ +client = new Client($requester); + } + + /** + * All supported shipper services. + * + * @return string[] + */ + public function getShippers(): array + { + return Shipper::all(); + } + + /** + * Add packages. + * + * @param \Inspirum\Balikobot\Model\Aggregates\PackageCollection $packages + * + * @return \Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection|\Inspirum\Balikobot\Model\Values\OrderedPackage[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function addPackages(PackageCollection $packages): OrderedPackageCollection + { + $response = $this->client->addPackages($packages->getShipper(), $packages->toArray()); + + // create return value object + $orderedPackages = new OrderedPackageCollection(); + + foreach ($response as $i => $package) { + $orderedPackages->add(OrderedPackage::newInstanceFromData( + $packages->getShipper(), + $packages->getEID(), + $package + )); + } + + return $orderedPackages; + } + + /** + * Exports Order into Balikobot system + * + * @param \Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection $packages + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function dropPackages(OrderedPackageCollection $packages): void + { + $this->client->dropPackages($packages->getShipper(), $packages->getPackageIds()); + } + + /** + * Exports Order into Balikobot system + * + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function dropPackage(OrderedPackage $package): void + { + $this->client->dropPackage($package->getShipper(), $package->getPackageId()); + } + + /** + * Order shipment. + * + * @param \Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection $packages + * @param \DateTime|null $date + * + * @return \Inspirum\Balikobot\Model\Values\OrderedShipment + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function orderShipment(OrderedPackageCollection $packages, DateTime $date = null): OrderedShipment + { + if ($date !== null) { + $date->setTime(0, 0, 0); + } + + $response = $this->client->orderShipment($packages->getShipper(), $packages->getPackageIds(), $date); + + $orderedShipment = OrderedShipment::newInstanceFromData( + $packages->getShipper(), + $packages->getPackageIds(), + $response, + $date + ); + + return $orderedShipment; + } + + /** + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @return \Inspirum\Balikobot\Model\Values\PackageStatus[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function trackPackage(OrderedPackage $package): array + { + $response = $this->client->trackPackage($package->getShipper(), $package->getCarrierId()); + + $statuses = []; + + foreach ($response as $status) { + $statuses[] = PackageStatus::newInstanceFromData($status); + } + + return $statuses; + } + + /** + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @return \Inspirum\Balikobot\Model\Values\PackageStatus + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function trackPackageLastStatus(OrderedPackage $package): PackageStatus + { + $response = $this->client->trackPackageLastStatus($package->getShipper(), $package->getCarrierId()); + + $status = PackageStatus::newInstanceFromData($response); + + return $status; + } + + /** + * @param string $shipper + * + * @return \Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getOverview(string $shipper): OrderedPackageCollection + { + $response = $this->client->getOverview($shipper); + + // create return value object + $orderedPackages = new OrderedPackageCollection(); + + foreach ($response as $i => $package) { + $orderedPackages->add(OrderedPackage::newInstanceFromData( + $shipper, + $package['eshop_id'], + $package + )); + } + + return $orderedPackages; + } + + /** + * @param \Inspirum\Balikobot\Model\Aggregates\OrderedPackageCollection $packages + * + * @return string + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getLabels(OrderedPackageCollection $packages): string + { + $response = $this->client->getLabels($packages->getShipper(), $packages->getPackageIds()); + + return $response; + } + + /** + * Gets complete information about a package + * + * @param \Inspirum\Balikobot\Model\Values\OrderedPackage $package + * + * @return \Inspirum\Balikobot\Model\Values\Package + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getPackageInfo(OrderedPackage $package): Package + { + $response = $this->client->getPackageInfo($package->getShipper(), $package->getPackageId()); + + $options = $response; + $options[Option::EID] = $package->getBatchId(); + + unset($options['package_id']); + unset($options['eshop_id']); + unset($options['carrier_id']); + unset($options['track_url']); + unset($options['label_url']); + unset($options['carrier_id_swap']); + unset($options['pieces']); + + $package = new Package($options); + + return $package; + } + + /** + * Gets complete information about a package + * + * @param string $shipper + * @param int $orderId + * + * @return \Inspirum\Balikobot\Model\Values\OrderedShipment + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getOrder(string $shipper, int $orderId): OrderedShipment + { + $response = $this->client->getOrder($shipper, $orderId); + + $orderedShipment = OrderedShipment::newInstanceFromData( + $shipper, + $response['package_ids'], + $response + ); + + return $orderedShipment; + } + + /** + * Returns available services for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getServices(string $shipper): array + { + $services = $this->client->getServices($shipper); + + return $services; + } + + /** + * Returns available manipulation units for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getManipulationUnits(string $shipper): array + { + $units = $this->client->getManipulationUnits($shipper); + + return $units; + } + + /** + * Get all available branches. + * + * @return \Generator|\Inspirum\Balikobot\Model\Values\Branch[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getBranches(): iterable + { + // get all shipper service codes + $shippers = $this->getShippers(); + + foreach ($shippers as $shipper) { + yield from $this->getBranchesForShipper($shipper); + } + } + + /** + * Get all available branches for given shipper. + * + * @param string $shipper + * + * @return \Generator|\Inspirum\Balikobot\Model\Values\Branch[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getBranchesForShipper(string $shipper): iterable + { + // get all services for shipper service + $services = array_keys($this->getServices($shipper)); + + // support shipper withou service type + if (empty($services)) { + $services = [null]; + } + + // get branches for all services + foreach ($services as $service) { + yield from $this->getBranchesForShipperService($shipper, $service); + } + } + + /** + * Get all available branches for given shipper and service type. + * + * @param string $shipper + * @param string|null $service + * + * @return \Generator|\Inspirum\Balikobot\Model\Values\Branch[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getBranchesForShipperService(string $shipper, ?string $service): iterable + { + $fullData = Shipper::hasFullBranchesSupport($shipper, $service); + $branches = $this->client->getBranches($shipper, $service, $fullData); + + foreach ($branches as $branch) { + yield Branch::newInstanceFromData($shipper, $service, $branch); + } + } + + /** + * Returns list of countries where service is available in + * + * @param string $shipper + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getCountries(string $shipper): array + { + $countries = $this->client->getCountries($shipper); + + return $countries; + } + + /** + * Returns available branches for the given shipper and its service + * + * @param string $shipper + * @param string $service + * @param string|null $country + * + * @return \Generator|\Inspirum\Balikobot\Model\Values\PostCode[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getPostCodes(string $shipper, string $service, string $country = null): iterable + { + $postcodes = $this->client->getPostCodes($shipper, $service, $country); + + foreach ($postcodes as $postcode) { + yield PostCode::newInstanceFromData($shipper, $service, $postcode); + } + } + + /** + * Check package(s) data. + * + * @param \Inspirum\Balikobot\Model\Aggregates\PackageCollection $packages + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function checkPackages(PackageCollection $packages): void + { + $this->client->checkPackages($packages->getShipper(), $packages->toArray()); + } + + /** + * Returns available manipulation units for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getAdrUnits(string $shipper): array + { + $units = $this->client->getAdrUnits($shipper); + + return $units; + } +} diff --git a/src/Services/Client.php b/src/Services/Client.php new file mode 100644 index 0000000..2b0dacd --- /dev/null +++ b/src/Services/Client.php @@ -0,0 +1,464 @@ +requester = $requester; + } + + /** + * Add package(s) to the Balikobot. + * + * @param string $shipper + * @param array $packages + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function addPackages(string $shipper, array $packages): array + { + $response = $this->requester->call('v1', $shipper, Request::ADD, $packages); + + if (isset($response[0]['package_id']) === false) { + throw new BadRequestException($response); + } + + unset($response['labels_url']); + unset($response['status']); + + return $response; + } + + /** + * Drops a package from the Balikobot. The package must be not ordered. + * + * @param string $shipper + * @param int $packageId + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function dropPackage(string $shipper, int $packageId): void + { + $this->dropPackages($shipper, [$packageId]); + } + + /** + * Drops a package from the Balikobot. The package must be not ordered. + * + * @param string $shipper + * @param array $packageIds + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function dropPackages(string $shipper, array $packageIds): void + { + $data = []; + + foreach ($packageIds as $packageId) { + $data[] = ['id' => $packageId]; + } + + $this->requester->call('v1', $shipper, Request::DROP, $data); + } + + /** + * Tracks a package + * + * @param string $shipper + * @param string $carrierId + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function trackPackage(string $shipper, string $carrierId): array + { + $data = [ + 0 => [ + 'id' => $carrierId + ], + ]; + + $response = $this->requester->call('v2', $shipper, Request::TRACK, $data); + + if (empty($response[0])) { + throw new BadRequestException($response); + } + + return $response[0]; + } + + /** + * Tracks a package, get the last info + * + * @param string $shipper + * @param string $carrierId + * + * @return array + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function trackPackageLastStatus(string $shipper, string $carrierId): array + { + $data = [ + 0 => [ + 'id' => $carrierId + ], + ]; + + $response = $this->requester->call('v1', $shipper, Request::TRACK_STATUS, $data, false); + + if (empty($response[0])) { + throw new BadRequestException($response); + } + + $status = [ + 'name' => $response[0]['status_text'], + 'status_id' => $response[0]['status_id'], + 'date' => null, + ]; + + return $status; + } + + /** + * Returns packages from the front (not ordered) for given shipper + * + * @param string $shipper + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getOverview(string $shipper): array + { + $response = $this->requester->call('v1', $shipper, Request::OVERVIEW, [], false); + + return $response; + } + + /** + * Gets labels + * + * @param string $shipper + * @param array $packageIds + * + * @return string + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getLabels(string $shipper, array $packageIds): string + { + $data = [ + 'package_ids' => $packageIds, + ]; + + $response = $this->requester->call('v1', $shipper, Request::LABELS, $data); + + return $response['labels_url']; + } + + /** + * Gets complete information about a package + * + * @param string $shipper + * @param int $packageId + * + * @return array + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getPackageInfo(string $shipper, int $packageId): array + { + $response = $this->requester->call('v1', $shipper, Request::PACKAGE . '/' . $packageId, [], false); + + return $response; + } + + /** + * Order shipment for packages. + * + * @param string $shipper + * @param array $packageIds + * @param \DateTime|null $date + * @param string|null $note + * + * @return array + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function orderShipment(string $shipper, array $packageIds, DateTime $date = null, string $note = null): array + { + $data = [ + 'package_ids' => $packageIds, + 'date' => $date ? $date->format('Y-m-d') : null, + 'note' => $note, + ]; + + $response = $this->requester->call('v1', $shipper, Request::ORDER, $data); + + unset($response['status']); + + return $response; + } + + /** + * Get order details. + * + * @param string $shipper + * @param int $orderId + * + * @return array + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getOrder(string $shipper, int $orderId): array + { + $response = $this->requester->call('v1', $shipper, Request::ORDER_VIEW . '/' . $orderId, [], false); + + unset($response['status']); + + return $response; + } + + /** + * Order pickup for packages. + * + * @param string $shipper + * @param \DateTime $dateFrom + * @param \DateTime $dateTo + * @param float $weight + * @param int $packageCount + * @param string|null $message + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function orderPickup( + string $shipper, + DateTime $dateFrom, + DateTime $dateTo, + float $weight, + int $packageCount, + string $message = null + ): void { + $data = [ + 'date' => $dateFrom->format('Y-m-d'), + 'time_from' => $dateFrom->format('H:s'), + 'time_to' => $dateTo->format('H:s'), + 'weight' => $weight, + 'package_count' => $packageCount, + 'message' => $message, + ]; + + $this->requester->call('v1', $shipper, Request::ORDER_PICKUP, $data); + } + + /** + * Returns available services for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getServices(string $shipper): array + { + $response = $this->requester->call('v1', $shipper, Request::SERVICES); + + if (isset($response['service_types']) === false) { + return []; + } + + return $response['service_types']; + } + + /** + * Returns available manipulation units for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getManipulationUnits(string $shipper): array + { + $response = $this->requester->call('v1', $shipper, Request::MANIPULATION_UNITS); + + if ($response['units'] === null) { + return []; + } + + $units = []; + + foreach ($response['units'] as $item) { + $units[$item['code']] = $item['name']; + } + + return $units; + } + + /** + * Returns available branches for the given shipper and its service + * Full branches instead branches request. + * + * @param string $shipper + * @param string $service + * @param bool $fullData + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getBranches(string $shipper, string $service = null, bool $fullData = false): array + { + $request = $fullData ? Request::FULL_BRANCHES : Request::BRANCHES; + + $response = $this->requester->call('v1', $shipper, $request . '/' . $service); + + if ($response['branches'] === null) { + return []; + } + + return $response['branches']; + } + + /** + * Returns list of countries where service is available in + * + * @param string $shipper + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getCountries(string $shipper): array + { + $response = $this->requester->call('v1', $shipper, Request::COUNTRIES); + + if ($response['service_types'] === null) { + return []; + } + + $services = []; + + foreach ($response['service_types'] as $item) { + $services[$item['service_type']] = $item['countries']; + } + + return $services; + } + + /** + * Returns available branches for the given shipper and its service + * + * @param string $shipper + * @param string $service + * @param string|null $country + * + * @return array[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getPostCodes(string $shipper, string $service, string $country = null): array + { + if ($country !== null) { + Country::validateCode($country); + + $urlPath = $service . '/' . $country; + } else { + $urlPath = $service; + } + + $response = $this->requester->call('v1', $shipper, Request::ZIP_CODES . '/' . $urlPath); + + if ($response['zip_codes'] === null) { + return []; + } + + $country = $response['country'] ?? $country; + $postCodes = []; + + foreach ($response['zip_codes'] as $postCode) { + $postCodes[] = [ + 'postcode' => $postCode['zip'] ?? ($postCode['zip_start'] ?? null), + 'postcode_end' => $postCode['zip_end'] ?? null, + 'city' => $postCode['city'] ?? null, + 'country' => $postCode['country'] ?? $country, + '1B' => (bool) ($postCode['1B'] ?? false), + ]; + } + + return $postCodes; + } + + /** + * Check package(s) data. + * + * @param string $shipper + * @param array $packages + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function checkPackages(string $shipper, array $packages): void + { + $this->requester->call('v1', $shipper, Request::CHECK, $packages); + } + + /** + * Returns available manipulation units for the given shipper + * + * @param string $shipper + * + * @return string[] + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function getAdrUnits(string $shipper): array + { + $response = $this->requester->call('v1', $shipper, Request::ADR_UNITS); + + if ($response['units'] === null) { + return []; + } + + $units = []; + + foreach ($response['units'] as $item) { + $units[$item['code']] = $item['name']; + } + + return $units; + } +} diff --git a/src/Services/Requester.php b/src/Services/Requester.php new file mode 100644 index 0000000..5c768e7 --- /dev/null +++ b/src/Services/Requester.php @@ -0,0 +1,207 @@ + 'https://api.balikobot.cz/', + 'v2' => 'https://api.balikobot.cz/v2/', + ]; + + /** + * API User. + * + * @var string + */ + private $apiUser; + + /** + * API key. + * + * @var string + */ + private $apiKey; + + /** + * Balikobot API client. + * + * @param string $apiUser + * @param string $apiKey + */ + public function __construct(string $apiUser, string $apiKey) + { + $this->apiUser = $apiUser; + $this->apiKey = $apiKey; + } + + /** + * Call API. + * + * @param string $version + * @param string $request + * @param string $shipper + * @param array $data + * @param bool $shouldHaveStatus + * + * @return array + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + public function call( + string $version, + string $shipper, + string $request, + array $data = [], + bool $shouldHaveStatus = true + ): array { + // resolve url + $path = trim($shipper . '/' . $request, '/'); + $host = $this->resolveHostName($version); + + // call API server and get response + $response = $this->request($host . $path, $data); + + // get status code and content + $statusCode = $response->getStatusCode(); + $content = $response->getBody()->getContents(); + + // parse response content to assoc array + $content = json_decode($content, true); + + // return empty array when json_decode fails + if ($content === null) { + $content = []; + } + + // validate response status code + $this->validateResponse($statusCode, $content, $shouldHaveStatus); + + // return response + return $content; + } + + /** + * Get API response. + * + * @param string $url + * @param array $data + * + * @return \Psr\Http\Message\ResponseInterface + */ + public function request(string $url, array $data = []): ResponseInterface + { + // init curl + $ch = curl_init(); + + // set headers + curl_setopt($ch, CURLOPT_URL, $url); + curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); + curl_setopt($ch, CURLOPT_HEADER, false); + + // set data + if (count($data) > 0) { + curl_setopt($ch, CURLOPT_POST, true); + curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($data)); + } + + // set auth + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Authorization: Basic ' . base64_encode($this->apiUser . ':' . $this->apiKey), + 'Content-Type: application/json', + ]); + + // execute curl + $response = (string) curl_exec($ch); + $statusCode = (int) curl_getinfo($ch, CURLINFO_HTTP_CODE); + + // close curl + curl_close($ch); + + return new Response($statusCode, [], $response); + } + + /** + * Get API url for given version. + * + * @param string $version + * + * @return string + */ + private function resolveHostName(string $version): string + { + return isset(self::API_URL[$version]) ? self::API_URL[$version] : self::API_URL['v1']; + } + + /** + * Validate response. + * + * @param int $statusCode + * @param array $response + * @param bool $shouldHaveStatus + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + private function validateResponse(int $statusCode, array $response, bool $shouldHaveStatus): void + { + $this->validateStatus($statusCode, $response); + + $this->validateResponseStatus($response, $shouldHaveStatus); + } + + /** + * Validate status code + * + * @param int $statusCode + * @param array $response + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + private function validateStatus(int $statusCode, array $response = []): void + { + // unauthorize + if ($statusCode === 401) { + throw new UnauthorizedException(); + } + + // request error + if ($statusCode !== 200) { + throw new BadRequestException($response, $statusCode); + } + } + + /** + * Validate response status. + * + * @param array $response + * @param bool $shouldHaveStatus + * + * @return void + * + * @throws \Inspirum\Balikobot\Contracts\ExceptionInterface + */ + private function validateResponseStatus(array $response, bool $shouldHaveStatus): void + { + // no status to validate + if (isset($response['status']) === false && $shouldHaveStatus === false) { + return; + } + + $statusCode = (int) ($response['status'] ?? 500); + + if ($statusCode !== 200) { + throw new BadRequestException($response, $statusCode); + } + } +} diff --git a/tests/AbstractTestCase.php b/tests/AbstractTestCase.php new file mode 100644 index 0000000..f51e50d --- /dev/null +++ b/tests/AbstractTestCase.php @@ -0,0 +1,55 @@ +shouldReceive('request')->andReturn(new Response($statusCode, [], (string) $data)); + + return $requester; + } +} diff --git a/tests/Integration/Balikobot/AbstractBalikobotTestCase.php b/tests/Integration/Balikobot/AbstractBalikobotTestCase.php new file mode 100644 index 0000000..2a1c5b9 --- /dev/null +++ b/tests/Integration/Balikobot/AbstractBalikobotTestCase.php @@ -0,0 +1,28 @@ +expectException(UnauthorizedException::class); + + $service = $this->newBalikobot('wrong', 'auth'); + + $service->getServices('cp'); + } + + public function testAuthorization() + { + $service = $this->newBalikobot('balikobot_test2cztest', '#lS1tBVo'); + + $packages = new PackageCollection(Shipper::CP); + + $package = new Package(); + $package->setServiceType(ServiceType::CP_NP); + $package->setRecName('Josef Novak'); + $package->setRecCity('Praha'); + $package->setRecStreet('Ulice'); + $package->setRecZip('17000'); + $package->setRecCountry(Country::CZECH_REPUBLIC); + $package->setRecPhone('777666555'); + $package->setPrice(2000); + $packages->add($package); + + $orderedPackages = $service->addPackages($packages); + + $this->assertNotEmpty($orderedPackages[0]->getPackageId()); + } +} diff --git a/tests/Integration/Balikobot/ShipperTest.php b/tests/Integration/Balikobot/ShipperTest.php new file mode 100644 index 0000000..454cf72 --- /dev/null +++ b/tests/Integration/Balikobot/ShipperTest.php @@ -0,0 +1,49 @@ +newBalikobot(); + + $shippers = $service->getShippers(); + + $this->assertEquals(Shipper::all(), $shippers); + } + + public function testPackageSupportAllShippersServices() + { + $service = $this->newBalikobot(); + + $shippers = Shipper::all(); + $services = []; + + // TODO: remove after API fix + unset($shippers[array_search(Shipper::UPS, $shippers)]); + + foreach ($shippers as $shipper) { + $services[$shipper] = array_keys($service->getServices($shipper)); + } + + $supportedServices = ServiceType::all(); + + // TODO: remove after API fix + unset($supportedServices[Shipper::UPS]); + + // make `[null]` array to empty array + $supportedServices = array_map(function ($data) { + if (empty(array_filter($data))) { + return []; + } + + return $data; + }, $supportedServices); + + $this->assertEquals($services, $supportedServices); + } +} diff --git a/tests/Unit/Balikobot/AbstractBalikobotTestCase.php b/tests/Unit/Balikobot/AbstractBalikobotTestCase.php new file mode 100644 index 0000000..fc33b89 --- /dev/null +++ b/tests/Unit/Balikobot/AbstractBalikobotTestCase.php @@ -0,0 +1,10 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + ]); + + $service = new Balikobot($requester); + + $packages = new PackageCollection('ppl', '0001'); + + $packages->add(new Package(['vs' => '0001', 'rec_name' => 'Name'])); + $packages->add(new Package(['vs' => '0002', 'price' => 2000])); + + $service->addPackages($packages); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/add', + [ + 0 => [ + 'eid' => '0001', + 'vs' => '0001', + 'rec_name' => 'Name' + ], + 1 => [ + 'eid' => '0001', + 'vs' => '0002', + 'price' => 2000 + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + 1 => [ + 'carrier_id' => 'NP1504102247M', + 'package_id' => 42720, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB.', + 'status' => '200', + ] + ]); + + $service = new Balikobot($requester); + + $packages = new PackageCollection('cp', '0001'); + + $orderedPackages = $service->addPackages($packages); + + $this->assertEquals(2, $orderedPackages->count()); + $this->assertEquals([42719, 42720], $orderedPackages->getPackageIds()); + $this->assertEquals('NP1504102247M', $orderedPackages[1]->getCarrierId()); + $this->assertEquals('0001', $orderedPackages[0]->getBatchId()); + } +} diff --git a/tests/Unit/Balikobot/CheckPackagesTest.php b/tests/Unit/Balikobot/CheckPackagesTest.php new file mode 100644 index 0000000..b426864 --- /dev/null +++ b/tests/Unit/Balikobot/CheckPackagesTest.php @@ -0,0 +1,47 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $service = new Balikobot($requester); + + $packages = new PackageCollection('ppl', '0001'); + + $packages->add(new Package(['vs' => '0001', 'rec_name' => 'Name'])); + $packages->add(new Package(['vs' => '0002', 'price' => 2000])); + + $service->checkPackages($packages); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/check', + [ + 0 => [ + 'eid' => '0001', + 'vs' => '0001', + 'rec_name' => 'Name' + ], + 1 => [ + 'eid' => '0001', + 'vs' => '0002', + 'price' => 2000 + ], + ], + ] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Balikobot/DropPackagesTest.php b/tests/Unit/Balikobot/DropPackagesTest.php new file mode 100644 index 0000000..d67eb15 --- /dev/null +++ b/tests/Unit/Balikobot/DropPackagesTest.php @@ -0,0 +1,70 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $service = new Balikobot($requester); + + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'ppl', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'ppl', '0001', '5678')); + + $service->dropPackages($packages); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/drop', + [ + 0 => [ + 'id' => 1, + ], + 1 => [ + 'id' => 2, + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testMakeRequestForSinglePackage() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $service = new Balikobot($requester); + + $package = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $service->dropPackage($package); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/drop', + [ + 0 => [ + 'id' => 1, + ], + ], + ] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Balikobot/GetAdrUnitsTest.php b/tests/Unit/Balikobot/GetAdrUnitsTest.php new file mode 100644 index 0000000..185eabf --- /dev/null +++ b/tests/Unit/Balikobot/GetAdrUnitsTest.php @@ -0,0 +1,60 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [], + ]); + + $service = new Balikobot($requester); + + $service->getAdrUnits('ppl'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/adrunits', + [] + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [ + [ + 'code' => 1, + 'name' => "KM", + 'attr' => 4 + ], + [ + 'code' => 876, + 'name' => "M", + ] + ], + ]); + + $service = new Balikobot($requester); + + $units = $service->getAdrUnits('cp'); + + $this->assertEquals( + [ + 1 => "KM", + 876 => "M", + ], + $units + ); + } +} diff --git a/tests/Unit/Balikobot/GetBranchesTest.php b/tests/Unit/Balikobot/GetBranchesTest.php new file mode 100644 index 0000000..f26277b --- /dev/null +++ b/tests/Unit/Balikobot/GetBranchesTest.php @@ -0,0 +1,185 @@ +assertTrue($fullbranches); + + $fullbranches = Shipper::hasFullBranchesSupport('zasilkovna', null); + + $this->assertTrue($fullbranches); + + $fullbranches = Shipper::hasFullBranchesSupport('pbh', '6'); + + $this->assertTrue($fullbranches); + + $fullbranches = Shipper::hasFullBranchesSupport('pbh', '15'); + + $this->assertTrue($fullbranches); + + $fullbranches = Shipper::hasFullBranchesSupport('cp', 'RR'); + + $this->assertFalse($fullbranches); + + $fullbranches = Shipper::hasFullBranchesSupport('ulozenka', null); + + $this->assertFalse($fullbranches); + } + + public function testGetBranchesForShipperCallAllServices() + { + /* @var \Inspirum\Balikobot\Services\Balikobot|\Mockery\MockInterface $service */ + $service = Mockery::mock( + Balikobot::class . '[getServices,getBranchesForShipperService]', + [new Requester('test', 'test')] + ); + + $service->shouldReceive('getServices')->with('cp')->andReturn(['NP' => 'NP', 'RR' => 'RR']); + $service->shouldReceive('getBranchesForShipperService')->with('cp', 'NP')->andReturnUsing(function () { + yield from $this->branchesGenerator(2); + }); + $service->shouldReceive('getBranchesForShipperService')->with('cp', 'RR')->andReturnUsing(function () { + yield from $this->branchesGenerator(3); + }); + + $count = 0; + foreach ($service->getBranchesForShipper('cp') as $branch) { + $this->assertNotEmpty($branch->getZip()); + $count++; + } + + $this->assertEquals(5, $count); + } + + public function testGetBranchesForShipperCallForEmptyServices() + { + /* @var \Inspirum\Balikobot\Services\Balikobot|\Mockery\MockInterface $service */ + $service = Mockery::mock( + Balikobot::class . '[getServices,getBranchesForShipperService]', + [new Requester('test', 'test')] + ); + + $service->shouldReceive('getServices')->with('zasilkovna')->andReturn([]); + $service->shouldReceive('getBranchesForShipperService')->with('zasilkovna', null)->andReturnUsing(function () { + yield from $this->branchesGenerator(2); + }); + + $count = 0; + foreach ($service->getBranchesForShipper('zasilkovna') as $branch) { + $this->assertNotEmpty($branch->getZip()); + $count++; + } + + $this->assertEquals(2, $count); + } + + public function testGetBranchesCallAllShippers() + { + /* @var \Inspirum\Balikobot\Services\Balikobot|\Mockery\MockInterface $service */ + $service = Mockery::mock( + Balikobot::class . '[getShippers,getBranchesForShipper]', + [new Requester('test', 'test')] + ); + + $service->shouldReceive('getShippers')->andReturn(['cp', 'ppl']); + $service->shouldReceive('getBranchesForShipper')->with('cp')->andReturnUsing(function () { + yield from $this->branchesGenerator(0); + }); + $service->shouldReceive('getBranchesForShipper')->with('ppl')->andReturnUsing(function () { + yield from $this->branchesGenerator(2); + }); + + $count = 0; + foreach ($service->getBranches() as $branch) { + $this->assertNotEmpty($branch->getZip()); + $count++; + } + + $this->assertEquals(2, $count); + } + + private function branchesGenerator(int $limit): iterable + { + for ($i = 0; $i < $limit; $i++) { + yield Branch::newInstanceFromData('cp', 'NP', [ + 'zip' => '11000', + ]); + } + } + + public function testFullBranchesMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [], + ]); + + $services = new Balikobot($requester); + + $branches = $services->getBranchesForShipperService('cp', 'NP'); + + $branches->valid(); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/fullbranches/NP', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [ + [ + 'id' => 1, + 'zip' => "11000", + ], + [ + 'id' => 876, + 'zip' => "12000", + ] + ], + ]); + + $service = new Balikobot($requester); + + $branches = $service->getBranchesForShipperService('cp', 'NP'); + + $this->assertInstanceOf(Generator::class, $branches); + + /* @var \Inspirum\Balikobot\Model\Values\Branch $branch */ + $branch = $branches->current(); + + $this->assertInstanceOf(Branch::class, $branch); + $this->assertEquals('1', $branch->getId()); + + $branches->next(); + $branch = $branches->current(); + + $this->assertInstanceOf(Branch::class, $branch); + $this->assertEquals('876', $branch->getId()); + + $branches->next(); + $branch = $branches->current(); + + $this->assertEquals(null, $branch); + } +} diff --git a/tests/Unit/Balikobot/GetCountriesTest.php b/tests/Unit/Balikobot/GetCountriesTest.php new file mode 100644 index 0000000..caab7a2 --- /dev/null +++ b/tests/Unit/Balikobot/GetCountriesTest.php @@ -0,0 +1,73 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [], + ]); + + $service = new Balikobot($requester); + + $service->getCountries('cp'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/countries4service', + [] + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [ + [ + 'service_type' => 1, + 'countries' => [ + 'CZ', + 'UK', + 'DE' + ], + ], + [ + 'service_type' => 4, + 'countries' => [ + 'CZ', + 'SK', + ], + ], + ], + ]); + + $service = new Balikobot($requester); + + $units = $service->getCountries('cp'); + + $this->assertEquals( + [ + 1 => [ + 'CZ', + 'UK', + 'DE' + ], + 4 => [ + 'CZ', + 'SK', + ] + ], + $units + ); + } +} diff --git a/tests/Unit/Balikobot/GetLabelsTest.php b/tests/Unit/Balikobot/GetLabelsTest.php new file mode 100644 index 0000000..8974d1c --- /dev/null +++ b/tests/Unit/Balikobot/GetLabelsTest.php @@ -0,0 +1,57 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => "http://pdf.balikobot.cz/dpd/eNorMdY1NFwwXDAELgE2" + ]); + + $service = new Balikobot($requester); + + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'ppl', '0001', '1234')); + $packages->add(new OrderedPackage(7, 'ppl', '0001', '5678')); + + $service->getLabels($packages); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/labels', + [ + 'package_ids' => [1, 7], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + ]); + + $service = new Balikobot($requester); + + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'ppl', '0001', '1234')); + + $labelsUrl = $service->getLabels($packages); + + $this->assertEquals('https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', $labelsUrl); + } +} diff --git a/tests/Unit/Balikobot/GetManipulationUnitsTest.php b/tests/Unit/Balikobot/GetManipulationUnitsTest.php new file mode 100644 index 0000000..20cc352 --- /dev/null +++ b/tests/Unit/Balikobot/GetManipulationUnitsTest.php @@ -0,0 +1,60 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [], + ]); + + $service = new Balikobot($requester); + + $service->getManipulationUnits('ppl'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/manipulationunits', + [] + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [ + [ + 'code' => 1, + 'name' => "KM", + 'attr' => 4 + ], + [ + 'code' => 876, + 'name' => "M", + ] + ], + ]); + + $service = new Balikobot($requester); + + $units = $service->getManipulationUnits('cp'); + + $this->assertEquals( + [ + 1 => "KM", + 876 => "M", + ], + $units + ); + } +} diff --git a/tests/Unit/Balikobot/GetOrderTest.php b/tests/Unit/Balikobot/GetOrderTest.php new file mode 100644 index 0000000..1b12271 --- /dev/null +++ b/tests/Unit/Balikobot/GetOrderTest.php @@ -0,0 +1,58 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 4, 65], + ]); + + $service = new Balikobot($requester); + + $service->getOrder('cp', 1); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/orderview/1', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 4, 65], + ]); + + $service = new Balikobot($requester); + + $orderedShipment = $service->getOrder('ppl', 29); + + $this->assertEquals(29, $orderedShipment->getOrderId()); + $this->assertEquals('http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', $orderedShipment->getFileUrl()); + $this->assertEquals('http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', $orderedShipment->getHandoverUrl()); + $this->assertEquals('http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', $orderedShipment->getLabelsUrl()); + $this->assertEquals([1, 4, 65], $orderedShipment->getPackageIds()); + $this->assertEquals(null, $orderedShipment->getDate()); + $this->assertEquals('ppl', $orderedShipment->getShipper()); + } +} diff --git a/tests/Unit/Balikobot/GetOverviewTest.php b/tests/Unit/Balikobot/GetOverviewTest.php new file mode 100644 index 0000000..6dde355 --- /dev/null +++ b/tests/Unit/Balikobot/GetOverviewTest.php @@ -0,0 +1,51 @@ +newRequesterWithMockedRequestMethod(200, []); + + $service = new Balikobot($requester); + + $service->getOverview('ppl'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/ppl/overview', []] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'eshop_id' => '0001', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + ], + 1 => [ + 'carrier_id' => 'NP1504102247M', + 'eshop_id' => '0001', + 'package_id' => 42720, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB.', + ] + ]); + + $service = new Balikobot($requester); + + $orderedPackages = $service->getOverview('ppl'); + + $this->assertEquals(2, $orderedPackages->count()); + $this->assertEquals([42719, 42720], $orderedPackages->getPackageIds()); + $this->assertEquals('NP1504102247M', $orderedPackages[1]->getCarrierId()); + $this->assertEquals('0001', $orderedPackages[0]->getBatchId()); + } +} diff --git a/tests/Unit/Balikobot/GetPackageInfoTest.php b/tests/Unit/Balikobot/GetPackageInfoTest.php new file mode 100644 index 0000000..305440b --- /dev/null +++ b/tests/Unit/Balikobot/GetPackageInfoTest.php @@ -0,0 +1,66 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $service = new Balikobot($requester); + + $orderedPackage = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $service->getPackageInfo($orderedPackage); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/package/1', + [] + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'package_id' => 1, + 'eshop_id' => 19, + 'carrier_id' => '1234', + 'track_url' => '/track', + 'label_url' => '/labels', + 'carrier_id_swap' => '11111', + 'pieces' => [1, 3], + 'real_order_id' => '180001', + 'order_number' => 2, + 'eid' => '0002' + ]); + + $service = new Balikobot($requester); + + $orderedPackage = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $package = $service->getPackageInfo($orderedPackage); + + $this->assertArrayNotHasKey('package_id', $package->toArray()); + $this->assertArrayNotHasKey('eshop_id', $package->toArray()); + $this->assertArrayNotHasKey('carrier_id', $package->toArray()); + $this->assertArrayNotHasKey('track_url', $package->toArray()); + $this->assertArrayNotHasKey('label_url', $package->toArray()); + $this->assertArrayNotHasKey('carrier_id_swap', $package->toArray()); + $this->assertArrayNotHasKey('pieces', $package->toArray()); + $this->assertEquals('0001', $package->getEID()); + $this->assertEquals('180001', $package->offsetGet('real_order_id')); + $this->assertEquals(2, $package->offsetGet('order_number')); + $this->assertEquals('0001', $package->offsetGet('eid')); + } +} diff --git a/tests/Unit/Balikobot/GetPostcodesTest.php b/tests/Unit/Balikobot/GetPostcodesTest.php new file mode 100644 index 0000000..05b8626 --- /dev/null +++ b/tests/Unit/Balikobot/GetPostcodesTest.php @@ -0,0 +1,78 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'zip_codes' => [], + ]); + + $service = new Balikobot($requester); + + $postCodes = $service->getPostCodes('ppl', '7'); + + $postCodes->valid(); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/zipcodes/7', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_type' => 'NP', + 'type' => 'zip', + 'zip_codes' => [ + [ + 'zip' => '35002', + '1B' => false, + 'country' => 'CZ', + ], + [ + 'zip' => '19000', + '1B' => true, + 'country' => 'CZ', + ], + ], + ]); + + $service = new Balikobot($requester); + + $postCodes = $service->getPostCodes('cp', 'NP'); + + $this->assertInstanceOf(Generator::class, $postCodes); + + /* @var \Inspirum\Balikobot\Model\Values\PostCode $postCode */ + $postCode = $postCodes->current(); + + $this->assertInstanceOf(PostCode::class, $postCode); + $this->assertEquals('35002', $postCode->getPostcode()); + + $postCodes->next(); + $postCode = $postCodes->current(); + + $this->assertInstanceOf(PostCode::class, $postCode); + $this->assertEquals('19000', $postCode->getPostcode()); + + $postCodes->next(); + $postCode = $postCodes->current(); + + $this->assertEquals(null, $postCode); + } +} diff --git a/tests/Unit/Balikobot/GetServicesTest.php b/tests/Unit/Balikobot/GetServicesTest.php new file mode 100644 index 0000000..2e78f83 --- /dev/null +++ b/tests/Unit/Balikobot/GetServicesTest.php @@ -0,0 +1,46 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $service = new Balikobot($requester); + + $service->getServices('ppl'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/services', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [ + 'NP', + 'RR', + ], + ]); + + $service = new Balikobot($requester); + + $services = $service->getServices('ppl'); + + $this->assertEquals(['NP', 'RR'], $services); + } +} diff --git a/tests/Unit/Balikobot/OrderShipmentTest.php b/tests/Unit/Balikobot/OrderShipmentTest.php new file mode 100644 index 0000000..c95b2ab --- /dev/null +++ b/tests/Unit/Balikobot/OrderShipmentTest.php @@ -0,0 +1,75 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 2], + ]); + + $service = new Balikobot($requester); + + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'ppl', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'ppl', '0001', '5678')); + + $service->orderShipment($packages, new DateTime('2018-10-10 10:00:00')); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/order', + [ + 'note' => null, + 'date' => '2018-10-10', + 'package_ids' => [1, 2], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 2], + ]); + + $service = new Balikobot($requester); + + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'ppl', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'ppl', '0001', '5678')); + + $orderedShipment = $service->orderShipment($packages, new DateTime('2018-10-10 10:00:00')); + + $this->assertEquals('ppl', $orderedShipment->getShipper()); + $this->assertEquals([1, 2], $orderedShipment->getPackageIds()); + $this->assertEquals(new DateTime('2018-10-10 00:00:00'), $orderedShipment->getDate()); + $this->assertEquals('http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', $orderedShipment->getFileUrl()); + $this->assertEquals('http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', $orderedShipment->getLabelsUrl()); + $this->assertEquals('http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', $orderedShipment->getHandoverUrl()); + $this->assertEquals(29, $orderedShipment->getOrderId()); + } +} diff --git a/tests/Unit/Balikobot/TrackLastPackageTest.php b/tests/Unit/Balikobot/TrackLastPackageTest.php new file mode 100644 index 0000000..d4f8895 --- /dev/null +++ b/tests/Unit/Balikobot/TrackLastPackageTest.php @@ -0,0 +1,61 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'status_id' => 1, + 'status_text' => 'Zásilka byla doručena příjemci.', + ], + ]); + + $service = new Balikobot($requester); + + $package = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $service->trackPackageLastStatus($package); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/ppl/trackstatus', + [ + 0 => [ + 'id' => '1234', + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'status_id' => 1, + 'status_text' => 'Zásilka byla doručena příjemci.', + ], + ]); + + $service = new Balikobot($requester); + + $package = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $status = $service->trackPackageLastStatus($package); + + $this->assertEquals(1, $status->getId()); + $this->assertEquals(null, $status->getDate()); + $this->assertEquals('Zásilka byla doručena příjemci.', $status->getName()); + } +} diff --git a/tests/Unit/Balikobot/TrackPackageTest.php b/tests/Unit/Balikobot/TrackPackageTest.php new file mode 100644 index 0000000..e645175 --- /dev/null +++ b/tests/Unit/Balikobot/TrackPackageTest.php @@ -0,0 +1,80 @@ +newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + [ + 'date' => '2018-11-07 14:15:01', + 'name' => 'Přijetí', + 'status_id' => 2, + ], + ], + ]); + + $service = new Balikobot($requester); + + $package = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $service->trackPackage($package); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/v2/ppl/track', + [ + 0 => [ + 'id' => '1234', + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testResponseData() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + [ + 'date' => '2018-11-07 14:15:01', + 'name' => 'Přijetí', + 'status_id' => 2, + ], + [ + 'date' => '2018-11-08 18:00:00', + 'name' => 'Doručení', + 'status_id' => 1, + ], + [ + 'date' => '2018-11-09 11:19:51', + 'name' => 'Dodání', + 'status_id' => -1, + ], + ], + ]); + + $service = new Balikobot($requester); + + $package = new OrderedPackage(1, 'ppl', '0001', '1234'); + + $statuses = $service->trackPackage($package); + + $this->assertEquals(3, count($statuses)); + $this->assertEquals(2, $statuses[0]->getId()); + $this->assertEquals(new DateTime('2018-11-08 18:00:00'), $statuses[1]->getDate()); + $this->assertEquals('Dodání', $statuses[2]->getName()); + $this->assertEquals(1, $statuses[1]->getId()); + } +} diff --git a/tests/Unit/BranchTest.php b/tests/Unit/BranchTest.php new file mode 100644 index 0000000..06dc295 --- /dev/null +++ b/tests/Unit/BranchTest.php @@ -0,0 +1,186 @@ + '1234', + 'type' => "type", + 'name' => "name", + 'city' => "city", + 'street' => 'street', + 'zip' => 'zip', + 'country' => 'country', + 'city_part' => 'city_part', + 'district' => 'district', + 'region' => 'region', + 'currency' => 'currency', + 'photo_small' => 'photo_small', + 'photo_big' => 'photo_big', + 'url' => 'url', + 'latitude' => 123.45, + 'longitude' => 67.890, + 'directions_global' => 'directions_global', + 'directions_car' => 'directions_car', + 'directions_public' => 'directions_public', + 'wheelchair_accessible' => false, + 'claim_assistant' => true, + 'dressing_room' => true, + 'opening_monday' => 'opening_monday', + 'opening_tuesday' => 'opening_tuesday', + 'opening_wednesday' => 'opening_wednesday', + 'opening_thursday' => 'opening_thursday', + 'opening_friday' => 'opening_friday', + 'opening_saturday' => 'opening_saturday', + 'opening_sunday' => 'opening_sunday', + ]); + + $this->assertEquals('cp', $branch->getShipper()); + $this->assertEquals('NP', $branch->getServiceType()); + $this->assertEquals('1234', $branch->getId()); + $this->assertEquals('type', $branch->getType()); + $this->assertEquals('name', $branch->getName()); + $this->assertEquals('city', $branch->getCity()); + $this->assertEquals('street', $branch->getStreet()); + $this->assertEquals('zip', $branch->getZip()); + $this->assertEquals('country', $branch->getCountry()); + $this->assertEquals('city_part', $branch->getCityPart()); + $this->assertEquals('district', $branch->getDistrict()); + $this->assertEquals('region', $branch->getRegion()); + $this->assertEquals('currency', $branch->getCurrency()); + $this->assertEquals('photo_small', $branch->getPhotoSmall()); + $this->assertEquals('photo_big', $branch->getPhotoBig()); + $this->assertEquals('url', $branch->getUrl()); + $this->assertEquals(123.45, $branch->getLatitude()); + $this->assertEquals(67.890, $branch->getLongitude()); + $this->assertEquals('directions_global', $branch->getDirectionsGlobal()); + $this->assertEquals('directions_car', $branch->getDirectionsCar()); + $this->assertEquals('directions_public', $branch->getDirectionsPublic()); + $this->assertEquals(false, $branch->getWheelchairAccessible()); + $this->assertEquals(true, $branch->getClaimAssistant()); + $this->assertEquals(true, $branch->getDressingRoom()); + $this->assertEquals('opening_monday', $branch->getOpeningMonday()); + $this->assertEquals('opening_tuesday', $branch->getOpeningTuesday()); + $this->assertEquals('opening_wednesday', $branch->getOpeningWednesday()); + $this->assertEquals('opening_thursday', $branch->getOpeningThursday()); + $this->assertEquals('opening_friday', $branch->getOpeningFriday()); + $this->assertEquals('opening_saturday', $branch->getOpeningSaturday()); + $this->assertEquals('opening_sunday', $branch->getOpeningSunday()); + } + + public function testStaticConstructorWithMissingData() + { + $branch = Branch::newInstanceFromData('cp', 'NP', [ + 'zip' => 'zip', + ]); + + $this->assertEquals('cp', $branch->getShipper()); + $this->assertEquals('NP', $branch->getServiceType()); + $this->assertEquals(null, $branch->getId()); + $this->assertEquals('branch', $branch->getType()); + $this->assertEquals('zip', $branch->getName()); + $this->assertEquals(null, $branch->getCity()); + $this->assertEquals(null, $branch->getStreet()); + $this->assertEquals('zip', $branch->getZip()); + $this->assertEquals(null, $branch->getCountry()); + $this->assertEquals(null, $branch->getCityPart()); + $this->assertEquals(null, $branch->getDistrict()); + $this->assertEquals(null, $branch->getRegion()); + $this->assertEquals(null, $branch->getCurrency()); + $this->assertEquals(null, $branch->getPhotoSmall()); + $this->assertEquals(null, $branch->getPhotoBig()); + $this->assertEquals(null, $branch->getUrl()); + $this->assertEquals(null, $branch->getLatitude()); + $this->assertEquals(null, $branch->getLongitude()); + $this->assertEquals(null, $branch->getDirectionsGlobal()); + $this->assertEquals(null, $branch->getDirectionsCar()); + $this->assertEquals(null, $branch->getDirectionsPublic()); + $this->assertEquals(null, $branch->getWheelchairAccessible()); + $this->assertEquals(null, $branch->getClaimAssistant()); + $this->assertEquals(null, $branch->getDressingRoom()); + $this->assertEquals(null, $branch->getOpeningMonday()); + $this->assertEquals(null, $branch->getOpeningTuesday()); + $this->assertEquals(null, $branch->getOpeningWednesday()); + $this->assertEquals(null, $branch->getOpeningThursday()); + $this->assertEquals(null, $branch->getOpeningFriday()); + $this->assertEquals(null, $branch->getOpeningSaturday()); + $this->assertEquals(null, $branch->getOpeningSunday()); + } + + public function testStaticConstructorFallbackName() + { + $branch = Branch::newInstanceFromData('cp', 'NP', [ + 'zip' => 'zip', + 'address' => 'address', + ]); + + $this->assertEquals('zip', $branch->getName()); + $this->assertEquals('branch', $branch->getType()); + $this->assertEquals('address', $branch->getStreet()); + } + + public function testBranchIdResolver() + { + $branch = Branch::newInstanceFromData('cp', 'NP', [ + 'id' => 11, + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('11000', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('sp', 'NP', [ + 'id' => 11, + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('11000', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('ulozenka', '7', [ + 'id' => 11, + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('11000', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('ppl', 'NP', [ + 'id' => 'KM1234', + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('1234', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('ppl', 'NP', [ + 'id' => 'K1M234', + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('K1M234', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('intime', 'NP', [ + 'id' => 11, + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('Branch Name', $branch->getBranchId()); + + $branch = Branch::newInstanceFromData('zasilkovna', null, [ + 'id' => 167, + 'name' => 'Branch Name', + 'zip' => '110 00', + ]); + + $this->assertEquals('167', $branch->getBranchId()); + } +} diff --git a/tests/Unit/Client/AbstractClientTestCase.php b/tests/Unit/Client/AbstractClientTestCase.php new file mode 100644 index 0000000..b685df8 --- /dev/null +++ b/tests/Unit/Client/AbstractClientTestCase.php @@ -0,0 +1,10 @@ +expectException(UnauthorizedException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(401, []); + + $client = new Client($requester); + + $client->addPackages('cp', []); + } + + public function testThrowsExceptionMatchStatusCode() + { + $requester = $this->newRequesterWithMockedRequestMethod(409, []); + + $client = new Client($requester); + + try { + $client->addPackages('cp', []); + } catch (ExceptionInterface $exception) { + $this->assertEquals(409, $exception->getStatusCode()); + } + } + + public function testThrowsExceptionMatchStatusCodeFromResponse() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, ['status' => 419]); + + $client = new Client($requester); + + try { + $client->addPackages('cp', []); + } catch (ExceptionInterface $exception) { + $this->assertEquals(419, $exception->getStatusCode()); + } + } + + public function testThrowsExceptionMatchResponse() + { + $requester = $this->newRequesterWithMockedRequestMethod(409, [ + 'test' => 1, + 'errors' => [ + 'id' => 404, + ], + ]); + + $client = new Client($requester); + + try { + $client->addPackages('cp', []); + } catch (ExceptionInterface $exception) { + $this->assertEquals(['test' => 1, 'errors' => ['id' => 404]], $exception->getResponse()); + $this->assertEquals('{"test":1,"errors":{"id":404}}', $exception->getResponseAsString()); + } + } + + public function testThrowsExceptionMatchSimpleErrors() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + 0 => [ + 'status' => 413, + 'id' => 404, + 'eid' => 'Missing', + 'rec_name' => 406, + ], + 1 => [ + 'aa' => 406, + ], + ]); + + $client = new Client($requester); + + try { + $client->addPackages('cp', []); + } catch (ExceptionInterface $exception) { + $this->assertEquals( + [ + 0 => [ + 'status' => 'Špatný formát dat.', + 'id' => 'Nespecifikovaná chyba.', + 'rec_name' => 'Nedorazilo jméno příjemce.', + ], + 1 => [ + 'aa' => 'Nedorazila žádná data ke zpracování.', + ] + ], + $exception->getErrors() + ); + } + } + + public function testThrowsExceptionMatchErrors() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + 0 => [ + 'errors' => [ + [ + 'type' => '413', + 'attribute' => 'rec_zip', + 'message' => 'Nepovolené PSČ příjemce.', + ], + [ + 'type' => '406', + 'attribute' => 'eid', + 'message' => 'Nedorazilo eshop ID.', + ], + ], + ], + 1 => [ + 'errors' => [ + [ + 'type' => '406', + 'attribute' => 'service_type', + 'message' => 'Nedorazilo ID vybrané služby přepravce.' + ], + ] + ] + ]); + + $client = new Client($requester); + + try { + $client->addPackages('cp', []); + } catch (ExceptionInterface $exception) { + $this->assertEquals( + [ + 0 => [ + 'rec_zip' => 'Nepovolené PSČ příjemce.', + 'eid' => 'Nedorazilo eshop ID.', + ], + 1 => [ + 'service_type' => 'Nedorazilo ID vybrané služby přepravce.', + ], + ], + $exception->getErrors() + ); + } + } +} diff --git a/tests/Unit/Client/Requests/AddRequestTest.php b/tests/Unit/Client/Requests/AddRequestTest.php new file mode 100644 index 0000000..6613592 --- /dev/null +++ b/tests/Unit/Client/Requests/AddRequestTest.php @@ -0,0 +1,135 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->addPackages('cp', []); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->addPackages('cp', []); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + ]); + + $client = new Client($requester); + + $client->addPackages('cp', []); + } + + public function testThrowsExceptionWhenNoReturnPackages() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'eid' => 200 + ] + ]); + + $client = new Client($requester); + + $client->addPackages('cp', []); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + ]); + + $client = new Client($requester); + + $client->addPackages('cp', ['data' => [1, 2, 3], 'test' => false]); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/add', ['data' => [1, 2, 3], 'test' => false]] + ); + + $this->assertTrue(true); + } + + public function testOnlyPackagesDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + 1 => [ + 'carrier_id' => 'NP1504102247M', + 'package_id' => 42720, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB.', + 'status' => '200', + ] + ]); + + $client = new Client($requester); + + $packages = $client->addPackages('cp', []); + + $this->assertEquals( + [ + 0 => [ + 'carrier_id' => 'NP1504102246M', + 'package_id' => 42719, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'status' => '200', + ], + 1 => [ + 'carrier_id' => 'NP1504102247M', + 'package_id' => 42720, + 'label_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoB.', + 'status' => '200', + ] + ], + $packages + ); + } +} diff --git a/tests/Unit/Client/Requests/AdrUnitsRequestTest.php b/tests/Unit/Client/Requests/AdrUnitsRequestTest.php new file mode 100644 index 0000000..a9714c3 --- /dev/null +++ b/tests/Unit/Client/Requests/AdrUnitsRequestTest.php @@ -0,0 +1,110 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getAdrUnits('cp'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getAdrUnits('cp'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getAdrUnits('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [], + ]); + + $client = new Client($requester); + + $client->getAdrUnits('cp'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/adrunits', []] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfUnitsMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => null, + ]); + + $client = new Client($requester); + + $units = $client->getAdrUnits('cp'); + + $this->assertEquals([], $units); + } + + public function testOnlyUnitsDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [ + [ + 'code' => 1, + 'name' => "KM", + 'attr' => 4 + ], + [ + 'code' => 876, + 'name' => "M", + ] + ], + ]); + + $client = new Client($requester); + + $units = $client->getAdrUnits('cp'); + + $this->assertEquals( + [ + 1 => "KM", + 876 => "M", + ], + $units + ); + } +} diff --git a/tests/Unit/Client/Requests/BranchesRequestTest.php b/tests/Unit/Client/Requests/BranchesRequestTest.php new file mode 100644 index 0000000..95331d4 --- /dev/null +++ b/tests/Unit/Client/Requests/BranchesRequestTest.php @@ -0,0 +1,153 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getBranches('cp'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getBranches('cp'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getBranches('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [], + ]); + + $client = new Client($requester); + + $client->getBranches('cp'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/branches', []] + ); + + $this->assertTrue(true); + } + + public function testMakeRequestWithService() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [], + ]); + + $client = new Client($requester); + + $client->getBranches('cp', 'NP'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/branches/NP', []] + ); + + $this->assertTrue(true); + } + + public function testMakeRequestFullbranches() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [], + ]); + + $client = new Client($requester); + + $client->getBranches('cp', 'NP', true); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/fullbranches/NP', []] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfUnitsMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => null, + ]); + + $client = new Client($requester); + + $units = $client->getBranches('cp'); + + $this->assertEquals([], $units); + } + + public function testOnlyBranchesDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'branches' => [ + [ + 'code' => 1, + 'name' => "AAA", + ], + [ + 'code' => 876, + 'name' => "BBB", + ] + ], + ]); + + $client = new Client($requester); + + $units = $client->getBranches('cp'); + + $this->assertEquals( + [ + [ + 'code' => 1, + 'name' => "AAA", + ], + [ + 'code' => 876, + 'name' => "BBB", + ] + ], + $units + ); + } +} diff --git a/tests/Unit/Client/Requests/CheckRequestTest.php b/tests/Unit/Client/Requests/CheckRequestTest.php new file mode 100644 index 0000000..4a38c17 --- /dev/null +++ b/tests/Unit/Client/Requests/CheckRequestTest.php @@ -0,0 +1,65 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->checkPackages('cp', []); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->checkPackages('cp', []); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->checkPackages('cp', []); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->checkPackages('cp', ['data' => [1, 2, 3], 'test' => false]); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/check', ['data' => [1, 2, 3], 'test' => false]] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Client/Requests/CountriesRequestTest.php b/tests/Unit/Client/Requests/CountriesRequestTest.php new file mode 100644 index 0000000..e831a47 --- /dev/null +++ b/tests/Unit/Client/Requests/CountriesRequestTest.php @@ -0,0 +1,123 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getCountries('cp'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getCountries('cp'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getCountries('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [], + ]); + + $client = new Client($requester); + + $client->getCountries('cp'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/countries4service', []] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfUnitsMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => null, + ]); + + $client = new Client($requester); + + $countries = $client->getCountries('cp'); + + $this->assertEquals([], $countries); + } + + public function testOnlyCountriesDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [ + [ + 'service_type' => 1, + 'countries' => [ + 'CZ', + 'UK', + 'DE' + ], + ], + [ + 'service_type' => 4, + 'countries' => [ + 'CZ', + 'SK', + ], + ], + ], + ]); + + $client = new Client($requester); + + $units = $client->getCountries('cp'); + + $this->assertEquals( + [ + 1 => [ + 'CZ', + 'UK', + 'DE' + ], + 4 => [ + 'CZ', + 'SK', + ] + ], + $units + ); + } +} diff --git a/tests/Unit/Client/Requests/DropRequestTest.php b/tests/Unit/Client/Requests/DropRequestTest.php new file mode 100644 index 0000000..d8f078e --- /dev/null +++ b/tests/Unit/Client/Requests/DropRequestTest.php @@ -0,0 +1,79 @@ +shouldReceive('dropPackages')->with('cp', [1])->once()->andReturns(); + + $client->dropPackage('cp', 1); + + $this->assertTrue(true); + } + + public function testThrowsExceptionOnError() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->dropPackages('cp', []); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->dropPackages('cp', []); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->dropPackages('cp', []); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->dropPackages('cp', [1, 4, 876]); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/drop', [['id' => 1], ['id' => 4], ['id' => 876]]] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Client/Requests/LabelsRequestTest.php b/tests/Unit/Client/Requests/LabelsRequestTest.php new file mode 100644 index 0000000..e6761b3 --- /dev/null +++ b/tests/Unit/Client/Requests/LabelsRequestTest.php @@ -0,0 +1,80 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getLabels('cp', []); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getLabels('cp', []); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getLabels('cp', []); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => "http://pdf.balikobot.cz/dpd/eNorMdY1NFwwXDAELgE2" + ]); + + $client = new Client($requester); + + $client->getLabels('cp', [1, 7, 876]); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/labels', ['package_ids' => [1, 7, 876]]] + ); + + $this->assertTrue(true); + } + + public function testOnlyLabelUrlIsReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + ]); + + $client = new Client($requester); + + $labelsUrl = $client->getLabels('cp', []); + + $this->assertEquals('https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', $labelsUrl); + } +} diff --git a/tests/Unit/Client/Requests/ManipulationUnitsRequestTest.php b/tests/Unit/Client/Requests/ManipulationUnitsRequestTest.php new file mode 100644 index 0000000..633773f --- /dev/null +++ b/tests/Unit/Client/Requests/ManipulationUnitsRequestTest.php @@ -0,0 +1,104 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getManipulationUnits('cp'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getManipulationUnits('cp'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getManipulationUnits('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [], + ]); + + $client = new Client($requester); + + $client->getManipulationUnits('cp'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/manipulationunits', []] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfUnitsMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => null, + ]); + + $client = new Client($requester); + + $units = $client->getManipulationUnits('cp'); + + $this->assertEquals([], $units); + } + + public function testOnlyUnitsDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'units' => [ + [ + 'code' => 1, + 'name' => "KM", + 'attr' => 4 + ], + [ + 'code' => 876, + 'name' => "M", + ] + ], + ]); + + $client = new Client($requester); + + $units = $client->getManipulationUnits('cp'); + + $this->assertEquals([1 => "KM", 876 => "M"], $units); + } +} diff --git a/tests/Unit/Client/Requests/OrderPickupRequestTest.php b/tests/Unit/Client/Requests/OrderPickupRequestTest.php new file mode 100644 index 0000000..68f10f6 --- /dev/null +++ b/tests/Unit/Client/Requests/OrderPickupRequestTest.php @@ -0,0 +1,83 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->orderPickup('cp', new DateTime(), new DateTime('+4 HOURS'), 1, 2); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->orderPickup('cp', new DateTime(), new DateTime('+4 HOURS'), 1, 2); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->orderPickup('cp', new DateTime(), new DateTime('+4 HOURS'), 1, 2); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->orderPickup( + 'cp', + new DateTime('2018-10-10 14:00:00'), + new DateTime('2018-12-10 20:00:00'), + 1, + 2, + 'TEST' + ); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/orderpickup', + [ + 'date' => '2018-10-10', + 'time_from' => '14:00', + 'time_to' => '20:00', + 'weight' => 1, + 'package_count' => 2, + 'message' => 'TEST', + ] + ] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Client/Requests/OrderRequestTest.php b/tests/Unit/Client/Requests/OrderRequestTest.php new file mode 100644 index 0000000..7a40bbb --- /dev/null +++ b/tests/Unit/Client/Requests/OrderRequestTest.php @@ -0,0 +1,102 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->orderShipment('cp', [1]); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->orderShipment('cp', [1]); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->orderShipment('cp', [1]); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->orderShipment('cp', [1, 4], new DateTime('2018-10-10 14:00:00'), 'TEST'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/order', + [ + 'package_ids' => [1, 4], + 'date' => '2018-10-10', + 'note' => 'TEST', + ] + ] + ); + + $this->assertTrue(true); + } + + public function testOnlyOrderDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1], + ]); + + $client = new Client($requester); + + $order = $client->orderShipment('cp', [1]); + + $this->assertEquals( + [ + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1], + ], + $order + ); + } +} diff --git a/tests/Unit/Client/Requests/OrderViewRequestTest.php b/tests/Unit/Client/Requests/OrderViewRequestTest.php new file mode 100644 index 0000000..e29a866 --- /dev/null +++ b/tests/Unit/Client/Requests/OrderViewRequestTest.php @@ -0,0 +1,95 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getOrder('cp', 1); + } + + public function testRequestDoesNotHaveStatus() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'order_id' => 29, + ]); + + $client = new Client($requester); + + $order = $client->getOrder('cp', 1); + + $this->assertNotEmpty($order); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getOrder('cp', 1); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getOrder('cp', 1); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/orderview/1', []] + ); + + $this->assertTrue(true); + } + + public function testOnlyOrderDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 4, 65], + ]); + + $client = new Client($requester); + + $order = $client->getOrder('cp', 1); + + $this->assertEquals( + [ + 'labels_url' => 'https://pdf.balikobot.cz/cp/eNorMTIwt9A1NbYwMwdcMBAZAoA.', + 'order_id' => 29, + 'file_url' => 'http://csv.balikobot.cz/cp/eNoz0jUFXDABKFwwlQ..', + 'handover_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0BfwwAe5cMMo.', + 'labels_url' => 'http://pdf.balikobot.cz/cp/eNoz0jW0XDBcMAHtXDDJ', + 'package_ids' => [1, 4, 65], + ], + $order + ); + } +} diff --git a/tests/Unit/Client/Requests/OverviewRequestTest.php b/tests/Unit/Client/Requests/OverviewRequestTest.php new file mode 100644 index 0000000..2e0119f --- /dev/null +++ b/tests/Unit/Client/Requests/OverviewRequestTest.php @@ -0,0 +1,65 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getOverview('cp'); + } + + public function testRequestDoesNotHaveStatus() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'order_id' => 29, + ]); + + $client = new Client($requester); + + $order = $client->getOverview('cp'); + + $this->assertNotEmpty($order); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getOverview('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getOverview('cp'); + + $requester->shouldHaveReceived( + 'request', + ['https://api.balikobot.cz/cp/overview', []] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Client/Requests/PackageRequestTest.php b/tests/Unit/Client/Requests/PackageRequestTest.php new file mode 100644 index 0000000..1a3777b --- /dev/null +++ b/tests/Unit/Client/Requests/PackageRequestTest.php @@ -0,0 +1,70 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getPackageInfo('cp', 1); + } + + public function testRequestDoesNotHaveStatus() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'data' => 1, + ]); + + $client = new Client($requester); + + $status = $client->getPackageInfo('cp', 1); + + $this->assertNotEmpty($status); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getPackageInfo('cp', 1); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getPackageInfo('cp', 1); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/package/1', + [] + ] + ); + + $this->assertTrue(true); + } +} diff --git a/tests/Unit/Client/Requests/PostcodeRequestTest.php b/tests/Unit/Client/Requests/PostcodeRequestTest.php new file mode 100644 index 0000000..52b3fad --- /dev/null +++ b/tests/Unit/Client/Requests/PostcodeRequestTest.php @@ -0,0 +1,271 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getPostCodes('cp', 'NP'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getPostCodes('cp', 'NP'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getPostCodes('cp', 'NP'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'zip_codes' => [], + ]); + + $client = new Client($requester); + + $client->getPostCodes('cp', 'NP'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/zipcodes/NP', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testMakeRequestWithCountry() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'zip_codes' => [], + ]); + + $client = new Client($requester); + + $client->getPostCodes('cp', 'NP', 'CZ'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/zipcodes/NP/CZ', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfPostCodesMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'zip_codes' => null, + ]); + + $client = new Client($requester); + + $postcodes = $client->getPostCodes('cp', 'NP'); + + $this->assertEquals([], $postcodes); + } + + public function testDataAreReturnedFromResponseType1() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_type' => 'NP', + 'type' => 'zip', + 'zip_codes' => [ + [ + 'zip' => '35002', + '1B' => false, + 'country' => 'CZ', + ], + [ + 'zip' => '19000', + '1B' => true, + 'country' => 'CZ', + ], + ], + ]); + + $client = new Client($requester); + + $postcodes = $client->getPostCodes('cp', 'NP'); + + $this->assertEquals( + [ + [ + 'postcode' => '35002', + 'postcode_end' => null, + 'city' => null, + 'country' => 'CZ', + '1B' => false + ], + [ + 'postcode' => '19000', + 'postcode_end' => null, + 'city' => null, + 'country' => 'CZ', + '1B' => true + ], + ], + $postcodes + ); + } + + public function testDataAreReturnedFromResponseType2() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_type' => '1', + 'type' => 'zip_range', + 'zip_codes' => [ + [ + 'zip_start' => '10000', + 'zip_end' => '10199', + 'country' => 'CZ', + ], + [ + 'zip_start' => '35000', + 'zip_end' => '35299', + 'country' => 'CZ', + ], + ], + ]); + + $client = new Client($requester); + + $postcodes = $client->getPostCodes('cp', 'NP'); + + $this->assertEquals( + [ + [ + 'postcode' => '10000', + 'postcode_end' => '10199', + 'city' => null, + 'country' => 'CZ', + '1B' => false + ], + [ + 'postcode' => '35000', + 'postcode_end' => '35299', + 'city' => null, + 'country' => 'CZ', + '1B' => false + ], + ], + $postcodes + ); + } + + public function testDataAreReturnedFromResponseType4() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_type' => '1', + 'type' => 'zip_range', + 'country' => 'AD', + 'zip_codes' => [ + [ + 'city' => 'AIXIRIVALL', + 'zip_start' => '25999', + 'zip_end' => '25999', + ], + ], + ]); + + $client = new Client($requester); + + $postcodes = $client->getPostCodes('cp', 'NP'); + + $this->assertEquals( + [ + [ + 'postcode' => '25999', + 'postcode_end' => '25999', + 'city' => 'AIXIRIVALL', + 'country' => 'AD', + '1B' => false + ], + ], + $postcodes + ); + } + + public function testDataAreReturnedFromResponseType5() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_type' => '1', + 'type' => 'city', + 'country' => 'AE', + 'zip_codes' => [ + [ + 'city' => 'ABU DHABI', + ], + [ + 'city' => 'AJMAN CITY', + ], + ], + ]); + + $client = new Client($requester); + + $postcodes = $client->getPostCodes('cp', 'NP'); + + $this->assertEquals( + [ + [ + 'postcode' => null, + 'postcode_end' => null, + 'city' => 'ABU DHABI', + 'country' => 'AE', + '1B' => false + ], + [ + 'postcode' => null, + 'postcode_end' => null, + 'city' => 'AJMAN CITY', + 'country' => 'AE', + '1B' => false + ], + ], + $postcodes + ); + } +} diff --git a/tests/Unit/Client/Requests/ServicesRequestTest.php b/tests/Unit/Client/Requests/ServicesRequestTest.php new file mode 100644 index 0000000..8169f17 --- /dev/null +++ b/tests/Unit/Client/Requests/ServicesRequestTest.php @@ -0,0 +1,98 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getServices('cp'); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->getServices('cp'); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->getServices('cp'); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->getServices('cp'); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/services', + [], + ] + ); + + $this->assertTrue(true); + } + + public function testEmptyArrayIsReturnedIfServiceTypesMissing() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $services = $client->getServices('cp'); + + $this->assertEquals([], $services); + } + + public function testOnlyUnitsDataAreReturned() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 'service_types' => [ + 'NP', + 'RR', + ], + ]); + + $client = new Client($requester); + + $services = $client->getServices('cp'); + + $this->assertEquals(['NP', 'RR'], $services); + } +} diff --git a/tests/Unit/Client/Requests/TrackLastStatusRequestTest.php b/tests/Unit/Client/Requests/TrackLastStatusRequestTest.php new file mode 100644 index 0000000..271bf1d --- /dev/null +++ b/tests/Unit/Client/Requests/TrackLastStatusRequestTest.php @@ -0,0 +1,118 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->trackPackageLastStatus('cp', 1); + } + + public function testRequestDoesNotHaveStatus() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 0 => [ + 'status_id' => 1, + 'status_text' => 'Zásilka byla doručena příjemci.', + ], + ]); + + $client = new Client($requester); + + $status = $client->trackPackageLastStatus('cp', 1); + + $this->assertNotEmpty($status); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->trackPackageLastStatus('cp', 1); + } + + public function testThrowsExceptionWhenNoReturnStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->trackPackageLastStatus('cp', 1); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'status_id' => 1, + 'status_text' => 'Zásilka byla doručena příjemci.', + ], + ]); + + $client = new Client($requester); + + $client->trackPackageLastStatus('cp', 1); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/cp/trackstatus', + [ + 0 => [ + 'id' => 1, + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testDataAreReturnedInV2Format() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'status_id' => 1, + 'status_text' => 'Zásilka byla doručena příjemci.', + ], + ]); + + $client = new Client($requester); + + $status = $client->trackPackageLastStatus('cp', 1); + + $this->assertEquals( + [ + 'name' => 'Zásilka byla doručena příjemci.', + 'status_id' => 1, + 'date' => null, + ], + $status + ); + } +} diff --git a/tests/Unit/Client/Requests/TrackRequestTest.php b/tests/Unit/Client/Requests/TrackRequestTest.php new file mode 100644 index 0000000..719a43c --- /dev/null +++ b/tests/Unit/Client/Requests/TrackRequestTest.php @@ -0,0 +1,119 @@ +expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(400, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->trackPackage('cp', 1); + } + + public function testRequestShouldHaveStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, []); + + $client = new Client($requester); + + $client->trackPackage('cp', 1); + } + + public function testThrowsExceptionOnBadStatusCode() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 400, + ]); + + $client = new Client($requester); + + $client->trackPackage('cp', 1); + } + + public function testThrowsExceptionWhenNoReturnStatus() + { + $this->expectException(BadRequestException::class); + + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + ]); + + $client = new Client($requester); + + $client->trackPackage('cp', 1); + } + + public function testMakeRequest() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + 'date' => '2018-11-07 14:15:01', + 'name' => 'Doručení', + 'status_id' => 2, + ], + ]); + + $client = new Client($requester); + + $client->trackPackage('cp', 1); + + $requester->shouldHaveReceived( + 'request', + [ + 'https://api.balikobot.cz/v2/cp/track', + [ + 0 => [ + 'id' => 1, + ], + ], + ] + ); + + $this->assertTrue(true); + } + + public function testDataAreReturnedInV2Format() + { + $requester = $this->newRequesterWithMockedRequestMethod(200, [ + 'status' => 200, + 0 => [ + [ + 'date' => '2018-11-07 14:15:01', + 'name' => 'Doručení', + 'status_id' => 2, + ], + ], + ]); + + $client = new Client($requester); + + $status = $client->trackPackage('cp', 1); + + $this->assertEquals( + [ + [ + 'date' => '2018-11-07 14:15:01', + 'name' => 'Doručení', + 'status_id' => 2, + ], + ], + $status + ); + } +} diff --git a/tests/Unit/OrderedPackageCollectionTest.php b/tests/Unit/OrderedPackageCollectionTest.php new file mode 100644 index 0000000..604845b --- /dev/null +++ b/tests/Unit/OrderedPackageCollectionTest.php @@ -0,0 +1,94 @@ +add(new OrderedPackage(1, 'cp', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'cp', '0001', '5678')); + + $this->assertEquals('cp', $packages->getShipper()); + $this->assertEquals([1, 2], $packages->getPackageIds()); + $this->assertEquals(['1234', '5678'], $packages->getCarrierIds()); + $this->assertEquals(2, $packages->count()); + } + + public function testThrowsErrorOnMissingShipper() + { + $this->expectException(RuntimeException::class); + + $packages = new OrderedPackageCollection(); + + $packages->getShipper(); + } + + public function testCollectionShipperFromFirstPackage() + { + $packages = new OrderedPackageCollection(); + + $packages->add(new OrderedPackage(1, 'cp', '0001', '1234')); + + $this->assertEquals('cp', $packages->getShipper()); + } + + public function testDiffShipperThrowsError() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Package is from different shipper ("ppl" instead of "cp")'); + + $packages = new OrderedPackageCollection('cp'); + + $packages->add(new OrderedPackage(1, 'cp', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'ppl', '0001', '5678')); + } + + public function testDiffShipperThrowsErrorWithOffsetSetMethod() + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage('Package is from different shipper ("ppl" instead of "cp")'); + + $packages = new OrderedPackageCollection('cp'); + + $packages->offsetSet(1, new OrderedPackage(1, 'cp', '0001', '1234')); + $packages->offsetSet(2, new OrderedPackage(2, 'ppl', '0001', '5678')); + } + + public function testSupportArrayAccess() + { + $packages = new OrderedPackageCollection('cp'); + + $packages->offsetSet(1, new OrderedPackage(1, 'cp', '0001', '1234')); + $packages->offsetSet(4, new OrderedPackage(2, 'cp', '0001', '5678')); + + $this->assertEquals(2, $packages->offsetGet(4)->getPackageId()); + $this->assertEquals(2, $packages->count()); + $this->assertTrue($packages->offsetExists(1)); + + $packages->offsetUnset(1); + + $this->assertFalse($packages->offsetExists(1)); + } + + public function testSupportIteratorAggregate() + { + $packages = new OrderedPackageCollection('cp'); + + $packages->add(new OrderedPackage(6, 'cp', '0001', '1234')); + $packages->add(new OrderedPackage(2, 'cp', '0001', '5678')); + + $iterator = $packages->getIterator(); + + $this->assertEquals(2, $iterator->count()); + $this->assertEquals(6, $iterator->current()->getPackageId()); + } +} diff --git a/tests/Unit/OrderedPackageTest.php b/tests/Unit/OrderedPackageTest.php new file mode 100644 index 0000000..bf1e363 --- /dev/null +++ b/tests/Unit/OrderedPackageTest.php @@ -0,0 +1,48 @@ + 1234, + 'carrier_id' => "02IID", + 'track_url' => "/track", + 'label_url' => "/labels", + 'carrier_id_swap' => 23, + 'pieces' => [1, 2], + ]); + + $this->assertEquals('cp', $orderedPackage->getShipper()); + $this->assertEquals('0001', $orderedPackage->getBatchId()); + $this->assertEquals(1234, $orderedPackage->getPackageId()); + $this->assertEquals("02IID", $orderedPackage->getCarrierId()); + $this->assertEquals("/track", $orderedPackage->getTrackUrl()); + $this->assertEquals("/labels", $orderedPackage->getLabelUrl()); + $this->assertEquals(23, $orderedPackage->getCarrierIdSwap()); + $this->assertEquals([1, 2], $orderedPackage->getPieces()); + } + + public function testStaticConstructorWithMissingData() + { + $orderedPackage = OrderedPackage::newInstanceFromData('cp', '0001', [ + 'package_id' => 1234, + 'carrier_id' => "02IID", + 'label_url' => "/labels", + ]); + + $this->assertEquals('cp', $orderedPackage->getShipper()); + $this->assertEquals('0001', $orderedPackage->getBatchId()); + $this->assertEquals(1234, $orderedPackage->getPackageId()); + $this->assertEquals("02IID", $orderedPackage->getCarrierId()); + $this->assertEquals(null, $orderedPackage->getTrackUrl()); + $this->assertEquals("/labels", $orderedPackage->getLabelUrl()); + $this->assertEquals(null, $orderedPackage->getCarrierIdSwap()); + $this->assertEquals([], $orderedPackage->getPieces()); + } +} diff --git a/tests/Unit/OrderedShipmentTest.php b/tests/Unit/OrderedShipmentTest.php new file mode 100644 index 0000000..6876f20 --- /dev/null +++ b/tests/Unit/OrderedShipmentTest.php @@ -0,0 +1,54 @@ + 1234, + 'handover_url' => "/handover", + 'labels_url' => "/labels", + 'file_url' => "/file", + ], + new DateTime('2018-10-10 14:00:00') + ); + + $this->assertEquals('cp', $orderedShipment->getShipper()); + $this->assertEquals(1234, $orderedShipment->getOrderId()); + $this->assertEquals("/handover", $orderedShipment->getHandoverUrl()); + $this->assertEquals("/labels", $orderedShipment->getLabelsUrl()); + $this->assertEquals("/file", $orderedShipment->getFileUrl()); + $this->assertEquals([1, 67], $orderedShipment->getPackageIds()); + $this->assertEquals(new \DateTime('2018-10-10 14:00:00'), $orderedShipment->getDate()); + } + + public function testStaticConstructorWithMissingData() + { + $orderedShipment = OrderedShipment::newInstanceFromData( + 'cp', + [1, 67], + [ + 'order_id' => 1234, + 'handover_url' => "/handover", + 'labels_url' => "/labels", + ] + ); + + $this->assertEquals('cp', $orderedShipment->getShipper()); + $this->assertEquals(1234, $orderedShipment->getOrderId()); + $this->assertEquals("/handover", $orderedShipment->getHandoverUrl()); + $this->assertEquals("/labels", $orderedShipment->getLabelsUrl()); + $this->assertEquals(null, $orderedShipment->getFileUrl()); + $this->assertEquals([1, 67], $orderedShipment->getPackageIds()); + $this->assertEquals(null, $orderedShipment->getDate()); + } +} diff --git a/tests/Unit/PackageCollectionTest.php b/tests/Unit/PackageCollectionTest.php new file mode 100644 index 0000000..3ac58f2 --- /dev/null +++ b/tests/Unit/PackageCollectionTest.php @@ -0,0 +1,71 @@ +assertNotEmpty($packages->getEid()); + } + + public function testCreateUniqueEid() + { + $packages1 = new PackageCollection('cp'); + $packages2 = new PackageCollection('cp'); + $packages3 = new PackageCollection('cp'); + + $this->assertTrue($packages1->getEid() !== $packages2->getEid()); + $this->assertTrue($packages1->getEid() !== $packages3->getEid()); + $this->assertTrue($packages2->getEid() !== $packages3->getEid()); + } + + public function testAddedPackagesHasCollectionEid() + { + $packages = new PackageCollection('cp', '0001'); + + $packages->add(new Package(['test' => 1])); + $packages->add(new Package(['test' => 2])); + + /* @var \Inspirum\Balikobot\Model\Values\Package[] $packages */ + foreach ($packages as $package) { + $this->assertEquals('0001', $package->getEID()); + } + + $this->assertEquals('cp', $packages->getShipper()); + $this->assertEquals(2, $packages->count()); + } + + public function testAddedPackagesAreClones() + { + $packages = new PackageCollection('cp', '0001'); + + $package = new Package(['test' => 1]); + + $packages->add($package); + + $package->offsetSet('test', 2); + + $packages->add($package); + + $this->assertEquals( + [ + 0 => [ + 'eid' => '0001', + 'test' => 1, + ], + 1 => [ + 'eid' => '0001', + 'test' => 2, + ], + ], + $packages->toArray() + ); + } +} diff --git a/tests/Unit/PackageStatusTest.php b/tests/Unit/PackageStatusTest.php new file mode 100644 index 0000000..6ae9327 --- /dev/null +++ b/tests/Unit/PackageStatusTest.php @@ -0,0 +1,39 @@ + '2018-11-07 14:15:01', + 'name' => 'Doručení', + 'status_id' => 2, + ] + ); + + $this->assertEquals(new DateTime('2018-11-07 14:15:01'), $status->getDate()); + $this->assertEquals(2, $status->getId()); + $this->assertEquals('Doručení', $status->getName()); + } + + public function testStaticConstructorWithMissingData() + { + $status = PackageStatus::newInstanceFromData( + [ + 'name' => 'Doručení', + 'status_id' => 2, + ] + ); + + $this->assertEquals(null, $status->getDate()); + $this->assertEquals(2, $status->getId()); + $this->assertEquals('Doručení', $status->getName()); + } +} diff --git a/tests/Unit/PackageTest.php b/tests/Unit/PackageTest.php new file mode 100644 index 0000000..967870c --- /dev/null +++ b/tests/Unit/PackageTest.php @@ -0,0 +1,218 @@ + 1, + 'eid' => '7890', + 'test' => false, + ] + ); + + $this->assertEquals( + [ + 'a' => 1, + 'eid' => '7890', + 'test' => false, + ], + $package->toArray() + ); + } + + public function testSupportArrayAccess() + { + $package = new Package(); + + $package->offsetSet('a', 2); + $package->offsetSet('b', false); + + $this->assertEquals(2, $package->offsetGet('a')); + $this->assertEquals(false, $package->offsetGet('b')); + $this->assertTrue($package->offsetExists('b')); + + $package->offsetUnset('b'); + + $this->assertFalse($package->offsetExists('b')); + } + + public function testPackageSetters() + { + $package = new Package(); + + $package->setEID('eid'); + $package->setOrderNumber(1); + $package->setRealOrderId('RealOrderID'); + $package->setServiceType('NP'); + $package->setServices([1, 2, 3]); + $package->setBranchId('ID678'); + $package->setPrice(2000); + $package->setDelInsurance(true); + $package->setDelEvening(false); + $package->setDelExworks(true); + $package->setCodPrice(1789); + $package->setCodCurrency('CZK'); + $package->setVS('67890'); + $package->setRecName('Name'); + $package->setRecFirm('Firm'); + $package->setRecStreet('Street'); + $package->setRecCity('City'); + $package->setRecZip('18900'); + $package->setRecRegion('Region'); + $package->setRecCountry('Czech'); + $package->setRecEmail('email@email.com'); + $package->setRecPhone('777666555'); + $package->setWeight(4.3); + $package->setRequireFullAge(true); + $package->setPassword('123456'); + $package->setCreditCard(true); + $package->setSmsNotification(false); + $package->setWidth(1.3); + $package->setLength(14.1); + $package->setHeigth(19); + $package->setNote('NOTE'); + $package->setSwap(true); + $package->setSwapOption('Option'); + $package->setVDLService(true); + $package->setVolume(4); + $package->setMuType('MU_1'); + $package->setPiecesCount(1); + $package->setMuTypeOne('MU_1'); + $package->setPiecesCountOne(1); + $package->setMuTypeTwo('MU_2'); + $package->setPiecesCountTwo(2); + $package->setMuTypeThree('MU_3'); + $package->setPiecesCountThree(3); + $package->setComfortService(true); + $package->setComfortServicePlus(false); + $package->setOverDimension(true); + $package->setWrapBackCount(6); + $package->setWrapBackNote('WNote'); + $package->setAppDisp(true); + $package->setDeliveryDate(new \DateTime('2018-10-10 10:00:01')); + $package->setReturnTrack(true); + $package->setBankAccountNumber('56789/0900'); + $package->setContent('content'); + $package->setTermsOfTrade('terms an terms'); + $package->setInvoicePDF('4567890'); + $package->setFullAgeData('FullAgeData'); + $package->setSatDelivery(true); + $package->setGetPiecesNumbers(false); + $package->setReturnFullErrors(true); + $package->setContentOne('Content1'); + $package->setContentTwo('Content2'); + $package->setContentThree('Content3'); + $package->setPhoneDeliveryNotification(true); + $package->setPhoneOrderNotification(false); + $package->setEmailNotification(true); + $package->setPhoneNotification(false); + $package->setB2CNotification(true); + $package->setNoteDriver('NoteDriver'); + $package->setNoteCustomer('NoteCustomer'); + $package->setComfortExclusiveService(false); + $package->setPersDeliveryFloor(true); + $package->setPersDeliveryBuilding(false); + $package->setPersDeliveryDepartment(false); + $package->setPIN('1235'); + $package->setContentData(['a' => 1, 'test' => 4]); + $package->setInvoiceNumber('23456789'); + $package->setOpenBeforePayment(true); + $package->setTestBeforePayment(false); + $package->setAdrService(true); + $package->setAdrContent(['b' => '6']); + + $this->assertEquals( + [ + Option::EID => 'eid', + Option::ORDER_NUMBER => 1, + Option::REAL_ORDER_ID => 'RealOrderID', + Option::SERVICE_TYPE => 'NP', + Option::SERVICES => '1+2+3', + Option::BRANCH_ID => 'ID678', + Option::PRICE => 2000.0, + Option::DEL_INSURANCE => 1, + Option::DEL_EVENING => 0, + Option::DEL_EXWORKS => 1, + Option::COD_PRICE => 1789.0, + Option::COD_CURRENCY => 'CZK', + Option::VS => '67890', + Option::REC_NAME => 'Name', + Option::REC_FIRM => 'Firm', + Option::REC_STREET => 'Street', + Option::REC_CITY => 'City', + Option::REC_ZIP => '18900', + Option::REC_REGION => 'Region', + Option::REC_COUNTRY => 'Czech', + Option::REC_EMAIL => 'email@email.com', + Option::REC_PHONE => '777666555', + Option::WEIGHT => 4.3, + Option::REQUIRE_FULL_AGE => 1, + Option::PASSWORD => '123456', + Option::CREDIT_CARD => 1, + Option::SMS_NOTIFICATION => 0, + Option::WIDTH => 1.3, + Option::LENGTH => 14.1, + Option::HEIGHT => 19.0, + Option::NOTE => 'NOTE', + Option::SWAP => 1, + Option::SWAP_OPTION => 'Option', + Option::VDL_SERVICE => 1, + Option::VOLUME => 4.0, + Option::MU_TYPE => 'MU_1', + Option::PIECES_COUNT => 1, + Option::MU_TYPE_ONE => 'MU_1', + Option::PIECES_COUNT_ONE => 1, + Option::MU_TYPE_TWO => 'MU_2', + Option::PIECES_COUNT_TWO => 2, + Option::MU_TYPE_THREE => 'MU_3', + Option::PIECES_COUNT_THREE => 3, + Option::COMFORT_SERVICE => 1, + Option::COMFORT_SERVICE_PLUS => 0, + Option::OVER_DIMENSION => 1, + Option::WRAP_BACK_COUNT => 6, + Option::WRAP_BACK_NOTE => 'WNote', + Option::APP_DISP => 1, + Option::DELIVERY_DATE => '2018-10-10', + Option::RETURN_TRACK => 1, + Option::BANK_ACCOUNT_NUMBER => '56789/0900', + Option::CONTENT => 'content', + Option::TERMS_OF_TRADE => 'terms an terms', + Option::INVOICE_PDF => '4567890', + Option::FULL_AGE_DATA => 'FullAgeData', + Option::SAT_DELIVERY => 1, + Option::GET_PIECES_NUMBERS => 0, + Option::RETURN_FULL_ERRORS => 1, + Option::CONTENT_ONE => 'Content1', + Option::CONTENT_TWO => 'Content2', + Option::CONTENT_THREE => 'Content3', + Option::PHONE_DELIVERY_NOTIFICATION => 1, + Option::PHONE_ORDER_NOTIFICATION => 0, + Option::EMAIL_NOTIFICATION => 1, + Option::PHONE_NOTIFICATION => 0, + Option::B2C_NOTIFICATION => 1, + Option::NOTE_DRIVER => 'NoteDriver', + Option::NOTE_CUSTOMER => 'NoteCustomer', + Option::COMFORT_EXCLUSIVE_SERVICE => 0, + Option::PERS_DELIVERY_FLOOR => 1, + Option::PERS_DELIVERY_BUILDING => 0, + Option::PERS_DELIVERY_DEPARTMENT => 0, + Option::PIN => '1235', + Option::CONTENT_DATA => ['a' => 1, 'test' => 4], + Option::INVOICE_NUMBER => '23456789', + Option::OPEN_BEFORE_PAYMENT => 1, + Option::TEST_BEFORE_PAYMENT => 0, + Option::ADR_SERVICE => 1, + Option::ADR_CONTENT => ['b' => '6'], + ], + $package->toArray() + ); + } +} diff --git a/tests/Unit/PostcodeTest.php b/tests/Unit/PostcodeTest.php new file mode 100644 index 0000000..4a9b801 --- /dev/null +++ b/tests/Unit/PostcodeTest.php @@ -0,0 +1,51 @@ + '17000', + 'postcode_end' => '18000', + 'city' => 'Prague', + 'country' => 'CZ', + '1B' => true, + ] + ); + + $this->assertEquals('cp', $postcode->getShipper()); + $this->assertEquals('NP', $postcode->getService()); + $this->assertEquals('17000', $postcode->getPostcode()); + $this->assertEquals('18000', $postcode->getPostcodeEnd()); + $this->assertEquals('CZ', $postcode->getCountry()); + $this->assertEquals('Prague', $postcode->getCity()); + $this->assertTrue($postcode->isMorningDelivery()); + } + + public function testStaticConstructorWithMissingData() + { + $postcode = PostCode::newInstanceFromData( + 'cp', + null, + [ + 'postcode' => '17000', + ] + ); + + $this->assertEquals('cp', $postcode->getShipper()); + $this->assertEquals(null, $postcode->getService()); + $this->assertEquals('17000', $postcode->getPostcode()); + $this->assertEquals(null, $postcode->getPostcodeEnd()); + $this->assertEquals(null, $postcode->getCountry()); + $this->assertEquals(null, $postcode->getCity()); + $this->assertFalse($postcode->isMorningDelivery()); + } +}