├── .github
└── workflows
│ └── test.yaml
├── .gitignore
├── LICENSE
├── README.md
├── composer.json
├── phpcs.xml.dist
├── phpunit.xml.dist
├── psalm-baseline.xml
├── psalm.xml.dist
├── src
├── Address.php
├── AuthenticationRequestHeaderProvider.php
├── CurrencyAwareTrait.php
├── Customer.php
├── Gateway.php
├── GatewayInterface.php
├── Item.php
├── ItemBag.php
├── ItemInterface.php
├── Message
│ ├── AbstractOrderRequest.php
│ ├── AbstractRequest.php
│ ├── AbstractResponse.php
│ ├── AcknowledgeRequest.php
│ ├── AcknowledgeResponse.php
│ ├── AuthorizeRequest.php
│ ├── AuthorizeResponse.php
│ ├── CaptureRequest.php
│ ├── CaptureResponse.php
│ ├── ExtendAuthorizationRequest.php
│ ├── ExtendAuthorizationResponse.php
│ ├── FetchTransactionRequest.php
│ ├── FetchTransactionResponse.php
│ ├── ItemDataTrait.php
│ ├── MerchantUrlsDataTrait.php
│ ├── RefundRequest.php
│ ├── RefundResponse.php
│ ├── UpdateCustomerAddressRequest.php
│ ├── UpdateCustomerAddressResponse.php
│ ├── UpdateMerchantReferencesRequest.php
│ ├── UpdateMerchantReferencesResponse.php
│ ├── UpdateTransactionRequest.php
│ ├── UpdateTransactionResponse.php
│ ├── VoidRequest.php
│ └── VoidResponse.php
└── WidgetOptions.php
└── tests
├── AuthenticationRequestHeaderProviderTest.php
├── ExpectedAuthorizationHeaderTrait.php
├── GatewayTest.php
├── ItemBagTest.php
├── ItemTest.php
└── Message
├── AbstractRequestTest.php
├── AbstractResponseTest.php
├── AcknowledgeRequestTest.php
├── AcknowledgeResponseTest.php
├── AddressTest.php
├── AuthorizeRequestTest.php
├── AuthorizeResponseTest.php
├── CaptureRequestTest.php
├── CaptureResponseTest.php
├── CustomerTest.php
├── ExtendAuthorizationRequestTest.php
├── ExtendAuthorizationResponseTest.php
├── FetchTransactionRequestTest.php
├── FetchTransactionResponseTest.php
├── ItemDataTestTrait.php
├── MerchantUrlsDataTestTrait.php
├── RefundRequestTest.php
├── RefundResponseTest.php
├── RequestTestCase.php
├── UpdateCustomerAddressRequestTest.php
├── UpdateCustomerAddressResponseTest.php
├── UpdateMerchantReferencesRequestTest.php
├── UpdateTransactionRequestTest.php
├── VoidRequestTest.php
├── VoidResponseTest.php
└── WidgetOptionsTest.php
/.github/workflows/test.yaml:
--------------------------------------------------------------------------------
1 | name: Test
2 |
3 | on:
4 | push:
5 | branches-ignore:
6 | - 'master'
7 | tags-ignore:
8 | - '**'
9 |
10 | jobs:
11 | setup:
12 | runs-on: ubuntu-latest
13 | steps:
14 | - uses: actions/checkout@v2
15 | - uses: shivammathur/setup-php@v2
16 | with:
17 | php-version: 7.4
18 | coverage: none
19 | - uses: actions/cache@v2
20 | with:
21 | path: vendor
22 | key: php-7.4-vendor-${{ hashFiles('**/composer.json') }}
23 | restore-keys: php-7.4-vendor-
24 | - run: composer install --no-interaction --no-ansi
25 | - id: set-php-versions
26 | run: echo "::set-output name=php-versions::$(vendor/bin/devtools list:php-versions)"
27 | - id: set-tools
28 | run: echo "::set-output name=tools::$(vendor/bin/devtools list:enabled-tools)"
29 | outputs:
30 | php-versions: ${{ steps.set-php-versions.outputs.php-versions }}
31 | tools: ${{ steps.set-tools.outputs.tools }}
32 |
33 | test:
34 | needs: setup
35 | runs-on: ubuntu-latest
36 | strategy:
37 | matrix:
38 | php-version: ${{ fromJson(needs.setup.outputs.php-versions) }}
39 | tool: ${{ fromJson(needs.setup.outputs.tools) }}
40 | fail-fast: false
41 | steps:
42 | - uses: actions/checkout@v2
43 | - uses: shivammathur/setup-php@v2
44 | with:
45 | php-version: ${{ matrix.php-version }}
46 | ini-values: date.timezone=Europe/Amsterdam, assert.exception=1, zend.assertions=1
47 | - uses: actions/cache@v2
48 | with:
49 | path: vendor
50 | key: php-${{ matrix.php-version }}-vendor-${{ hashFiles('**/composer.json') }}
51 | restore-keys: php-${{ matrix.php-version }}-vendor-
52 | - run: composer install --no-interaction --no-ansi
53 |
54 | - run: vendor/bin/devtools ${{ matrix.tool }}
55 |
--------------------------------------------------------------------------------
/.gitignore:
--------------------------------------------------------------------------------
1 | .DS_Store
2 | .idea
3 | .phpunit.result.cache
4 | vendor
5 | composer.lock
6 | phpunit.xml
7 | /.phpcs-cache
8 |
--------------------------------------------------------------------------------
/LICENSE:
--------------------------------------------------------------------------------
1 | MIT License
2 |
3 | Copyright (c) 2019 MyOnlineStore B.V.
4 |
5 | Permission is hereby granted, free of charge, to any person obtaining a copy
6 | of this software and associated documentation files (the "Software"), to deal
7 | in the Software without restriction, including without limitation the rights
8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9 | copies of the Software, and to permit persons to whom the Software is
10 | furnished to do so, subject to the following conditions:
11 |
12 | The above copyright notice and this permission notice shall be included in all
13 | copies or substantial portions of the Software.
14 |
15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21 | SOFTWARE.
22 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # NO LONGER MAINTAINED
2 | This repository is no longer being maintained.
3 |
4 | # Omnipay: Klarna Checkout
5 | [](LICENSE)
6 | [](https://github.com/MyOnlineStore/omnipay-klarna-checkout)
7 | [](https://github.com/MyOnlineStore/omnipay-klarna-checkout)
8 | [](https://github.com/MyOnlineStore/omnipay-klarna-checkout)
9 |
10 | ## Introduction
11 |
12 | [Omnipay](https://github.com/thephpleague/omnipay) is a framework agnostic, multi-gateway payment
13 | processing library for PHP 5.6+. This package implements Klarna Checkout support for Omnipay.
14 |
15 | ## Installation
16 |
17 | To install, simply add it to your `composer.json` file:
18 | ```shell
19 | $ composer require myonlinestore/omnipay-klarna-checkout
20 | ```
21 |
22 | ## Initialization
23 |
24 | First, create the Omnipay gateway:
25 | ```php
26 | $gateway = Omnipay\Omnipay::create('\MyOnlineStore\Omnipay\KlarnaCheckout\Gateway');
27 | // or
28 | $gateway = new MyOnlineStore\Omnipay\KlarnaCheckout\Gateway(/* $httpClient, $httpRequest */);
29 | ```
30 | Then, initialize it with the correct credentials:
31 | ```php
32 | $gateway->initialize([
33 | 'username' => $username,
34 | 'secret' => $secret,
35 | 'api_region' => $region, // Optional, may be Gateway::API_VERSION_EUROPE (default) or Gateway::API_VERSION_NORTH_AMERICA
36 | 'testMode' => false // Optional, default: true
37 | ]);
38 | // or
39 | $gateway->setUsername($username);
40 | $gateway->setSecret($secret);
41 | $gateway->setApiRegion($region);
42 | ```
43 |
44 | ## Usage
45 |
46 | For general usage instructions, please see the main [Omnipay](https://github.com/thephpleague/omnipay)
47 | repository.
48 |
49 | ### General flow
50 |
51 | 1. [Create a Klarna order](#authorize)
52 | 2. [Update transaction](#update-transaction) (if required)
53 | 3. [Render the Iframe](#render-iframe)
54 | 4. Respond to redirects to `checkoutUrl` or `confirmation_url`
55 | 5. Respond to [checkout callbacks](https://developers.klarna.com/api/#checkout-api-callbacks-callbacks)
56 | 6. Respond to the request to `push_url` (indicates order was completed by client)
57 | with a [ackowledgement](#acknowledge)
58 | 7. [Extend authorization](#extend-authorization) (if required)
59 | 8. [Update the merchant address](#update-merchant-address) (if required)
60 | 9. Perform one or more [capture(s)](#capture), [refund(s)](#refund) or [void](#void) operations
61 |
62 | ### Authorize
63 |
64 | To create a new order, use the `authorize` method:
65 | ```php
66 | $data = [
67 | 'amount' => 100,
68 | 'tax_amount' => 20,
69 | 'currency' => 'SEK',
70 | 'locale' => 'SE',
71 | 'purchase_country' => 'SE',
72 |
73 | 'notify_url' => '', // https://developers.klarna.com/api/#checkout-api__ordermerchant_urls__validation
74 | 'return_url' => '', // https://developers.klarna.com/api/#checkout-api__ordermerchant_urls__checkout
75 | 'terms_url' => '', // https://developers.klarna.com/api/#checkout-api__ordermerchant_urls__terms
76 | 'validation_url' => '', // https://developers.klarna.com/api/#checkout-api__ordermerchant_urls__validation
77 |
78 | 'items' => [
79 | [
80 | 'type' => 'physical',
81 | 'name' => 'Shirt',
82 | 'quantity' => 1,
83 | 'tax_rate' => 25,
84 | 'price' => 100,
85 | 'unit_price' => 100,
86 | 'total_tax_amount' => 20,
87 | ],
88 | ],
89 | ];
90 |
91 | $response = $gateway->authorize($data)->send()->getData();
92 | ```
93 | This will return the order details as well as the checkout HTML snippet to render on your site.
94 |
95 | [API documentation](https://github.com/MyOnlineStore/omnipay-klarna-checkout/blob/master/src/Message/AuthorizeRequest.php)
96 |
97 | ## Render Iframe
98 |
99 | Klarna Checkout requires an iframe to be rendered when authorizing payments:
100 |
101 | ```php
102 | $response = $gateway->fetchTransaction(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])
103 | ->send();
104 |
105 | echo $response->getData()['checkout']['html_snippet'];
106 | ```
107 |
108 | After submitting the form within the iframe,
109 | Klarna will redirect the client to the provided `confirmation_url` (success)
110 | or `checkout_url` (failure)`.
111 |
112 | ### Update transaction
113 |
114 | While an order has not been authorized (completed) by the client, it may be updated:
115 |
116 | ```php
117 | $response = $gateway->updateTransaction([
118 | 'transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab',
119 | 'amount' => 200,
120 | 'tax_amount' => 40,
121 | 'currency' => 'SEK',
122 | 'locale' => 'SE',
123 | 'purchase_country' => 'SE',
124 | 'items' => [/*...*/],
125 | ])->send();
126 | ```
127 |
128 | The response will contain the updated order data.
129 |
130 | [API documentation](https://developers.klarna.com/api/#checkout-api-update-an-order)
131 |
132 | ### Extend authorization
133 |
134 | Klarna order authorization is valid until a specific date, and may be extended (up to a maximum of 180 days).
135 | The updated expiration date may then be retrieved with a [fetch](#fetch) request
136 |
137 | ```php
138 | if ($gateway->extendAuthorization(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])->send()->isSuccessful()) {
139 | $expiration = new \DateTimeImmutable(
140 | $gateway->fetchTransaction(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])
141 | ->send()
142 | ->getData()['management']['expires_at']
143 | );
144 | }
145 | ```
146 |
147 | [API documentation](https://developers.klarna.com/api/#order-management-api-extend-authorization-time)
148 |
149 | ### Capture
150 |
151 | ```php
152 | $success = $gateway->capture([
153 | 'transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab',
154 | 'amount' => '995',
155 | ])->send()
156 | ->isSuccessful();
157 | ```
158 |
159 | [API documentation](https://developers.klarna.com/api/#order-management-api-create-capture)
160 |
161 | ### Fetch
162 |
163 | A Klarna order is initially available through the checkout API. After it has been authorized, it will be available
164 | through the Order management API (and will, after some time, no longer be available in the checkout API).
165 | This fetch request will first check whether the order exitst in the checkout API.
166 | If that is not the case, or the status indicates the order is finished,
167 | it will also fetch the order from the order management API
168 |
169 | ```php
170 | $response = $gateway->fetchTransaction(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])
171 | ->send();
172 |
173 | $success = $response->isSuccessful();
174 | $checkoutData = $response->getData()['checkout'] ?? [];
175 | $managementData = $response->getData()['management'] ?? [];
176 | ```
177 | API documentation |
178 | [Checkout](https://developers.klarna.com/api/#checkout-api-retrieve-an-order) |
179 | [Order management](https://developers.klarna.com/api/#order-management-api-get-order)
180 |
181 | ### Acknowlegde
182 |
183 | Acknowledge a completed order
184 |
185 | ```php
186 | $success = $gateway->acknowledge(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])
187 | ->send()
188 | ->isSuccessful();
189 | ```
190 |
191 | [API documentation](https://developers.klarna.com/api/#order-management-api-acknowledge-order)
192 |
193 | ### Refund
194 |
195 | ```php
196 | $success = $gateway->refund([
197 | 'transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab',
198 | 'amount' => '995',
199 | ])->send()
200 | ->isSuccessful();
201 | ```
202 |
203 | [API documentation](https://developers.klarna.com/api/#order-management-api-create-a-refund)
204 |
205 | ### Void
206 |
207 | You may release the remaining authorized amount. Specifying a specific amount is not possible.
208 |
209 | ```php
210 | $success = $gateway->void(['transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab'])
211 | ->send()
212 | ->isSuccessful();
213 | ```
214 |
215 | [API documentation](https://developers.klarna.com/api/#order-management-api-release-remaining-authorization)
216 |
217 | ### Update customer address
218 |
219 | This may be used when updating customer address details *after* the order has been authorized.
220 | Success op this operation is subject to a risk assessment by Klarna. Both addresses are required parameters.
221 |
222 | ```php
223 | $success = $gateway->refund([
224 | 'transactionReference' => 'a5bec272-d68d-4df9-9fdd-8e35e51f92ab',
225 | 'shipping_address' => [
226 | 'given_name'=> 'Klara',
227 | 'family_name'=> 'Joyce',
228 | 'title'=> 'Mrs',
229 | 'street_address'=> 'Apartment 10',
230 | 'street_address2'=> '1 Safeway',
231 | 'postal_code'=> '12345',
232 | 'city'=> 'Knoxville',
233 | 'region'=> 'TN',
234 | 'country'=> 'us',
235 | 'email'=> 'klara.joyce@klarna.com',
236 | 'phone'=> '1-555-555-5555'
237 | ],
238 | 'billing_address' => [
239 | 'given_name'=> 'Klara',
240 | 'family_name'=> 'Joyce',
241 | 'title'=> 'Mrs',
242 | 'street_address'=> 'Apartment 10',
243 | 'street_address2'=> '1 Safeway',
244 | 'postal_code'=> '12345',
245 | 'city'=> 'Knoxville',
246 | 'region'=> 'TN',
247 | 'country'=> 'us',
248 | 'email'=> 'klara.joyce@klarna.com',
249 | 'phone'=> '1-555-555-5555'
250 | ],
251 | ])->send()
252 | ->isSuccessful();
253 | ```
254 |
255 | [API documentation](https://developers.klarna.com/api/#order-management-api-update-customer-addresses)
256 |
257 | ### Update merchant reference(s)
258 |
259 | If an order has been authorized by the client, its merchant references may be updated:
260 |
261 | ```php
262 | $response = $gateway->updateMerchantReferences([
263 | 'merchant_reference1' => 'foo',
264 | 'merchant_reference2' => 'bar',
265 | ])->send();
266 | ```
267 |
268 | [API documentation](https://developers.klarna.com/api/#order-management-api-update-merchant-references)
269 |
270 |
271 | ## Units
272 |
273 | Klarna expresses amounts in minor units as described [here](https://developers.klarna.com/api/#data-types).
274 |
--------------------------------------------------------------------------------
/composer.json:
--------------------------------------------------------------------------------
1 | {
2 | "name": "myonlinestore/omnipay-klarna-checkout",
3 | "type": "library",
4 | "description": "Klarna Checkout gateway for Omnipay payment processing library",
5 | "keywords": ["Klarna Checkout", "Omnipay"],
6 | "homepage": "https://github.com/MyOnlineStore/omnipay-klarna-checkout",
7 | "license": "MIT",
8 | "autoload": {
9 | "psr-4" : {
10 | "MyOnlineStore\\Omnipay\\KlarnaCheckout\\" : "src/",
11 | "MyOnlineStore\\Tests\\Omnipay\\KlarnaCheckout\\" : "tests/"
12 | }
13 | },
14 | "require": {
15 | "php": "^7.4 | ^8.0",
16 | "omnipay/common": "^3.1",
17 | "ext-json": "*"
18 | },
19 | "require-dev": {
20 | "myonlinestore/coding-standard": "^3.1",
21 | "myonlinestore/php-devtools": "^0.2",
22 | "omnipay/tests": "^4.1",
23 | "vimeo/psalm": "^4.18"
24 | },
25 | "config": {
26 | "sort-packages": true,
27 | "allow-plugins": {
28 | "dealerdirect/phpcodesniffer-composer-installer": true,
29 | "composer/package-versions-deprecated": true
30 | }
31 | }
32 | }
33 |
--------------------------------------------------------------------------------
/phpcs.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
5 |
6 |
7 |
8 |
9 |
10 |
11 |
12 | src
13 | tests
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
--------------------------------------------------------------------------------
/phpunit.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
7 |
8 |
9 | src
10 |
11 |
12 |
13 |
14 |
15 | ./tests/
16 |
17 |
18 |
19 |
--------------------------------------------------------------------------------
/psalm-baseline.xml:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | $request->getSecret()
6 | $request->getUsername()
7 |
8 |
9 |
10 |
11 | $this
12 |
13 |
14 | authorize
15 | capture
16 | refund
17 | setBaseUrl
18 | void
19 |
20 |
21 | self
22 |
23 |
24 |
25 |
26 | setMerchantData
27 | setTaxRate
28 | setTotalAmount
29 | setTotalDiscountAmount
30 | setTotalTaxAmount
31 | setType
32 |
33 |
34 |
35 |
36 | ItemInterface[]
37 |
38 |
39 | add
40 |
41 |
42 | $item
43 |
44 |
45 |
46 |
47 | getAmount
48 |
49 |
50 |
51 |
52 | Money|null
53 |
54 |
55 | setLocale
56 | setTaxAmount
57 |
58 |
59 | $items
60 |
61 |
62 |
63 |
64 | AcknowledgeRequest
65 |
66 |
67 |
68 |
69 | $response->getBody()
70 |
71 |
72 | AuthorizeRequest
73 |
74 |
75 |
76 |
77 | getRedirectData
78 | getRedirectUrl
79 |
80 |
81 | $data
82 | $renderUrl
83 |
84 |
85 | $this->renderUrl
86 | null
87 |
88 |
89 |
90 |
91 | CaptureRequest
92 |
93 |
94 |
95 |
96 | ExtendAuthorizationRequest
97 |
98 |
99 |
100 |
101 | $responseData
102 |
103 |
104 | FetchTransactionRequest
105 |
106 |
107 |
108 |
109 | RefundRequest
110 |
111 |
112 |
113 |
114 | getArrayCopy
115 | getArrayCopy
116 |
117 |
118 | UpdateCustomerAddressRequest
119 |
120 |
121 |
122 |
123 | (int) $statusCode
124 |
125 |
126 |
127 |
128 | UpdateMerchantReferencesRequest
129 |
130 |
131 |
132 |
133 | UpdateTransactionRequest
134 |
135 |
136 |
137 |
138 | VoidRequest
139 |
140 |
141 |
142 |
143 | public function initialize(array $parameters = [])
144 |
145 |
146 |
147 |
--------------------------------------------------------------------------------
/psalm.xml.dist:
--------------------------------------------------------------------------------
1 |
2 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
--------------------------------------------------------------------------------
/src/Address.php:
--------------------------------------------------------------------------------
1 | null,
17 | 'reference' => null,
18 | 'attention' => null,
19 | 'family_name' => null,
20 | 'given_name' => null,
21 | 'email' => null,
22 | 'title' => null,
23 | 'street_address' => null,
24 | 'street_address2' => null,
25 | 'street_name' => null,
26 | 'house_extension' => null,
27 | 'street_number' => null,
28 | 'postal_code' => null,
29 | 'city' => null,
30 | 'region' => null,
31 | 'phone' => null,
32 | 'country' => null,
33 | ];
34 |
35 | return new self(\array_merge($defaults, \array_intersect_key($data, $defaults)));
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/src/AuthenticationRequestHeaderProvider.php:
--------------------------------------------------------------------------------
1 | \sprintf(
14 | 'Basic %s',
15 | \base64_encode(
16 | \sprintf(
17 | '%s:%s',
18 | $request->getUsername(),
19 | $request->getSecret()
20 | )
21 | )
22 | ),
23 | ];
24 | }
25 | }
26 |
--------------------------------------------------------------------------------
/src/CurrencyAwareTrait.php:
--------------------------------------------------------------------------------
1 | getCurrency());
29 | } catch (\InvalidArgumentException $exception) {
30 | $currency = new Currency('USD');
31 | }
32 |
33 | $moneyParser = new DecimalMoneyParser(new ISOCurrencies());
34 |
35 | return $moneyParser->parse((string) $amount, $currency);
36 | }
37 |
38 | /**
39 | * @param Money $money
40 | *
41 | * @return int
42 | *
43 | * @throws ParserException
44 | */
45 | protected function toCurrencyMinorUnits(Money $money): int
46 | {
47 | $moneyParser = new DecimalMoneyParser(new ISOCurrencies());
48 |
49 | return (int) $moneyParser->parse($money->getAmount(), $money->getCurrency())->getAmount();
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Customer.php:
--------------------------------------------------------------------------------
1 | null,
17 | 'type' => 'person',
18 | ];
19 |
20 | return new self(\array_merge($defaults, \array_intersect_key($data, $defaults)));
21 | }
22 | }
23 |
--------------------------------------------------------------------------------
/src/Gateway.php:
--------------------------------------------------------------------------------
1 | createRequest(AcknowledgeRequest::class, $options);
35 | }
36 |
37 | /**
38 | * @inheritdoc
39 | */
40 | public function authorize(array $options = [])
41 | {
42 | return $this->createRequest(AuthorizeRequest::class, $options);
43 | }
44 |
45 | /**
46 | * @inheritdoc
47 | */
48 | public function capture(array $options = [])
49 | {
50 | return $this->createRequest(CaptureRequest::class, $options);
51 | }
52 |
53 | /**
54 | * @inheritdoc
55 | */
56 | public function extendAuthorization(array $options = []): RequestInterface
57 | {
58 | return $this->createRequest(ExtendAuthorizationRequest::class, $options);
59 | }
60 |
61 | /**
62 | * @inheritdoc
63 | */
64 | public function fetchTransaction(array $options = []): RequestInterface
65 | {
66 | return $this->createRequest(FetchTransactionRequest::class, $options);
67 | }
68 |
69 | /**
70 | * @return string REGION_* constant value
71 | */
72 | public function getApiRegion(): string
73 | {
74 | return $this->getParameter('api_region');
75 | }
76 |
77 | /**
78 | * @inheritDoc
79 | */
80 | public function getDefaultParameters(): array
81 | {
82 | return [
83 | 'api_region' => self::API_VERSION_EUROPE,
84 | 'secret' => '',
85 | 'testMode' => true,
86 | 'username' => '',
87 | ];
88 | }
89 |
90 | public function getName(): string
91 | {
92 | return 'KlarnaCheckout';
93 | }
94 |
95 | public function getSecret(): string
96 | {
97 | return $this->getParameter('secret');
98 | }
99 |
100 | public function getUsername(): string
101 | {
102 | return $this->getParameter('username');
103 | }
104 |
105 | /**
106 | * @inheritDoc
107 | */
108 | public function initialize(array $parameters = [])
109 | {
110 | parent::initialize($parameters);
111 |
112 | $this->setBaseUrl();
113 |
114 | return $this;
115 | }
116 |
117 | /**
118 | * @inheritdoc
119 | */
120 | public function refund(array $options = [])
121 | {
122 | return $this->createRequest(RefundRequest::class, $options);
123 | }
124 |
125 | /**
126 | * @param string $region
127 | *
128 | * @return $this
129 | */
130 | public function setApiRegion(string $region): self
131 | {
132 | $this->setParameter('api_region', $region);
133 |
134 | return $this;
135 | }
136 |
137 | /**
138 | * @param string $secret
139 | *
140 | * @return $this
141 | */
142 | public function setSecret(string $secret): self
143 | {
144 | $this->setParameter('secret', $secret);
145 |
146 | return $this;
147 | }
148 |
149 | /**
150 | * @param string $username
151 | *
152 | * @return $this
153 | */
154 | public function setUsername(string $username): self
155 | {
156 | $this->setParameter('username', $username);
157 |
158 | return $this;
159 | }
160 |
161 | public function setTestMode($value): self
162 | {
163 | parent::setTestMode($value);
164 |
165 | $this->setBaseUrl();
166 |
167 | return $this;
168 | }
169 |
170 | /**
171 | * @inheritDoc
172 | */
173 | public function updateCustomerAddress(array $options = []): RequestInterface
174 | {
175 | return $this->createRequest(UpdateCustomerAddressRequest::class, $options);
176 | }
177 |
178 | public function updateMerchantReferences(array $options = []): RequestInterface
179 | {
180 | return $this->createRequest(UpdateMerchantReferencesRequest::class, $options);
181 | }
182 |
183 | /**
184 | * @inheritdoc
185 | */
186 | public function updateTransaction(array $options = []): RequestInterface
187 | {
188 | return $this->createRequest(UpdateTransactionRequest::class, $options);
189 | }
190 |
191 | /**
192 | * @inheritdoc
193 | */
194 | public function void(array $options = [])
195 | {
196 | return $this->createRequest(VoidRequest::class, $options);
197 | }
198 |
199 | private function setBaseUrl()
200 | {
201 | if (self::API_VERSION_EUROPE === $this->getApiRegion()) {
202 | $this->parameters->set('base_url', $this->getTestMode() ? self::EU_TEST_BASE_URL : self::EU_BASE_URL);
203 |
204 | return;
205 | }
206 |
207 | $this->parameters->set('base_url', $this->getTestMode() ? self::NA_TEST_BASE_URL : self::NA_BASE_URL);
208 | }
209 | }
210 |
--------------------------------------------------------------------------------
/src/GatewayInterface.php:
--------------------------------------------------------------------------------
1 | getParameter('merchant_data');
14 | }
15 |
16 | /**
17 | * @inheritDoc
18 | */
19 | public function getTaxRate()
20 | {
21 | return $this->getParameter('tax_rate');
22 | }
23 |
24 | /**
25 | * @inheritDoc
26 | */
27 | public function getTotalAmount()
28 | {
29 | return $this->getParameter('total_amount');
30 | }
31 |
32 | /**
33 | * @inheritDoc
34 | */
35 | public function getTotalDiscountAmount()
36 | {
37 | return $this->getParameter('total_discount_amount');
38 | }
39 |
40 | /**
41 | * @inheritDoc
42 | */
43 | public function getTotalTaxAmount()
44 | {
45 | return $this->getParameter('total_tax_amount');
46 | }
47 |
48 | /**
49 | * @inheritDoc
50 | */
51 | public function getType()
52 | {
53 | return $this->getParameter('type');
54 | }
55 |
56 | /**
57 | * @param string $data
58 | */
59 | public function setMerchantData($data)
60 | {
61 | $this->setParameter('merchant_data', $data);
62 | }
63 |
64 | /**
65 | * @param int $taxRate
66 | */
67 | public function setTaxRate($taxRate)
68 | {
69 | $this->setParameter('tax_rate', $taxRate);
70 | }
71 |
72 | /**
73 | * @param int $amount
74 | */
75 | public function setTotalAmount($amount)
76 | {
77 | $this->setParameter('total_amount', $amount);
78 | }
79 |
80 | /**
81 | * @param int $amount
82 | */
83 | public function setTotalDiscountAmount($amount)
84 | {
85 | $this->setParameter('total_discount_amount', $amount);
86 | }
87 |
88 | /**
89 | * @param int $amount
90 | */
91 | public function setTotalTaxAmount($amount)
92 | {
93 | $this->setParameter('total_tax_amount', $amount);
94 | }
95 |
96 | /**
97 | * @param string $type
98 | */
99 | public function setType($type)
100 | {
101 | $this->setParameter('type', $type);
102 | }
103 | }
104 |
--------------------------------------------------------------------------------
/src/ItemBag.php:
--------------------------------------------------------------------------------
1 | items[] = $item;
19 | } else {
20 | $this->items[] = new Item($item);
21 | }
22 | }
23 | }
24 |
--------------------------------------------------------------------------------
/src/ItemInterface.php:
--------------------------------------------------------------------------------
1 | getParameter('billing_address');
21 | }
22 |
23 | /**
24 | * @return Customer|null
25 | */
26 | public function getCustomer()
27 | {
28 | return $this->getParameter('customer');
29 | }
30 |
31 | /**
32 | * @return bool|null
33 | */
34 | public function getGuiAutofocus()
35 | {
36 | return $this->getParameter('gui_autofocus');
37 | }
38 |
39 | /**
40 | * @return bool|null
41 | */
42 | public function getGuiMinimalConfirmation()
43 | {
44 | return $this->getParameter('gui_minimal_confirmation');
45 | }
46 |
47 | /**
48 | * @return string|null
49 | */
50 | public function getPurchaseCountry()
51 | {
52 | return $this->getParameter('purchase_country');
53 | }
54 |
55 | /**
56 | * @return Address|null
57 | */
58 | public function getShippingAddress()
59 | {
60 | return $this->getParameter('shipping_address');
61 | }
62 |
63 | /**
64 | * @return string[]|null ISO 3166 alpha-2 codes of shipping countries, or null if none are specified
65 | */
66 | public function getShippingCountries()
67 | {
68 | return $this->getParameter('shipping_countries');
69 | }
70 |
71 | /**
72 | * @return WidgetOptions|null
73 | */
74 | public function getWidgetOptions()
75 | {
76 | return $this->getParameter('widget_options');
77 | }
78 |
79 | /**
80 | * @param array $billingAddress
81 | *
82 | * @return $this
83 | */
84 | public function setBillingAddress($billingAddress): self
85 | {
86 | $this->setParameter('billing_address', Address::fromArray($billingAddress));
87 |
88 | return $this;
89 | }
90 |
91 | /**
92 | * @param array $customer
93 | *
94 | * @return $this
95 | */
96 | public function setCustomer(array $customer): self
97 | {
98 | $this->setParameter('customer', Customer::fromArray($customer));
99 |
100 | return $this;
101 | }
102 |
103 | /**
104 | * @param bool $value
105 | *
106 | * @return $this
107 | */
108 | public function setGuiAutofocus(bool $value): self
109 | {
110 | $this->setParameter('gui_autofocus', $value);
111 |
112 | return $this;
113 | }
114 |
115 | /**
116 | * @param bool $value
117 | *
118 | * @return $this
119 | */
120 | public function setGuiMinimalConfirmation(bool $value): self
121 | {
122 | $this->setParameter('gui_minimal_confirmation', $value);
123 |
124 | return $this;
125 | }
126 |
127 | /**
128 | * @param string $value
129 | *
130 | * @return $this
131 | */
132 | public function setPurchaseCountry(string $value): self
133 | {
134 | $this->setParameter('purchase_country', $value);
135 |
136 | return $this;
137 | }
138 |
139 | /**
140 | * @param array $shippingAddress
141 | *
142 | * @return $this
143 | */
144 | public function setShippingAddress(array $shippingAddress): self
145 | {
146 | $this->setParameter('shipping_address', Address::fromArray($shippingAddress));
147 |
148 | return $this;
149 | }
150 |
151 | /**
152 | * @param string[] $countries ISO 3166 alpha-2 codes of shipping countries
153 | *
154 | * @return $this
155 | */
156 | public function setShippingCountries(array $countries): self
157 | {
158 | $this->setParameter('shipping_countries', $countries);
159 |
160 | return $this;
161 | }
162 |
163 | /**
164 | * @param array $widgetOptions
165 | *
166 | * @return $this
167 | */
168 | public function setWidgetOptions(array $widgetOptions): self
169 | {
170 | $this->setParameter('widget_options', WidgetOptions::fromArray($widgetOptions));
171 |
172 | return $this;
173 | }
174 |
175 | /**
176 | * @return array
177 | */
178 | protected function getOrderData(): array
179 | {
180 | $data = [
181 | 'order_amount' => $this->getAmountInteger(),
182 | 'order_tax_amount' => null === $this->getTaxAmount() ? 0 : (int) $this->getTaxAmount()->getAmount(),
183 | 'order_lines' => $this->getItemData($this->getItems() ?? new ItemBag()),
184 | 'purchase_currency' => $this->getCurrency(),
185 | 'purchase_country' => $this->getPurchaseCountry(),
186 | ];
187 |
188 | if (null !== $locale = $this->getLocale()) {
189 | $data['locale'] = \str_replace('_', '-', $locale);
190 | }
191 |
192 | if (null !== $shippingCountries = $this->getShippingCountries()) {
193 | $data['shipping_countries'] = $shippingCountries;
194 | }
195 |
196 | if (null !== $shippingAddress = $this->getShippingAddress()) {
197 | $data['shipping_address'] = $shippingAddress->getArrayCopy();
198 | }
199 |
200 | if (null !== $billingAddress = $this->getBillingAddress()) {
201 | $data['billing_address'] = $billingAddress->getArrayCopy();
202 | }
203 |
204 | if (null !== $merchantReference1 = $this->getMerchantReference1()) {
205 | $data['merchant_reference1'] = $merchantReference1;
206 | }
207 |
208 | if (null !== $merchantReference2 = $this->getMerchantReference2()) {
209 | $data['merchant_reference2'] = $merchantReference2;
210 | }
211 |
212 | if (null !== $widgetOptions = $this->getWidgetOptions()) {
213 | $data['options'] = $widgetOptions->getArrayCopy();
214 | }
215 |
216 | if (null !== $customer = $this->getCustomer()) {
217 | $data['customer'] = $customer->getArrayCopy();
218 | }
219 |
220 | $guiOptions = [];
221 |
222 | if (false === $this->getGuiAutofocus()) {
223 | $guiOptions[] = 'disable_autofocus';
224 | }
225 |
226 | if ($this->getGuiMinimalConfirmation()) {
227 | $guiOptions[] = 'minimal_confirmation';
228 | }
229 |
230 | if (!empty($guiOptions)) {
231 | $data['gui'] = ['options' => $guiOptions];
232 | }
233 |
234 | return $data;
235 | }
236 | }
237 |
--------------------------------------------------------------------------------
/src/Message/AbstractRequest.php:
--------------------------------------------------------------------------------
1 | getParameter('amount')) {
28 | return null;
29 | }
30 |
31 | return $this->convertToMoney($amount);
32 | }
33 |
34 | /**
35 | * @return string|null REGION_* constant value
36 | */
37 | public function getApiRegion()
38 | {
39 | return $this->getParameter('api_region');
40 | }
41 |
42 | /**
43 | * @return string|null
44 | */
45 | public function getBaseUrl()
46 | {
47 | return $this->getParameter('base_url');
48 | }
49 |
50 | /**
51 | * RFC 1766 customer's locale.
52 | *
53 | * @return string|null
54 | */
55 | public function getLocale()
56 | {
57 | return $this->getParameter('locale');
58 | }
59 |
60 | /**
61 | * @return string|null
62 | */
63 | public function getMerchantReference1()
64 | {
65 | return $this->getParameter('merchant_reference1');
66 | }
67 |
68 | /**
69 | * @return string|null
70 | */
71 | public function getMerchantReference2()
72 | {
73 | return $this->getParameter('merchant_reference2');
74 | }
75 |
76 | /**
77 | * @return string|null
78 | */
79 | public function getSecret()
80 | {
81 | return $this->getParameter('secret');
82 | }
83 |
84 | /**
85 | * The total tax amount of the order
86 | *
87 | * @return Money|null
88 | */
89 | public function getTaxAmount()
90 | {
91 | if (null === $amount = $this->getParameter('tax_amount')) {
92 | return null;
93 | }
94 |
95 | return $this->convertToMoney($amount);
96 | }
97 |
98 | /**
99 | * @return string|null
100 | */
101 | public function getUsername()
102 | {
103 | return $this->getParameter('username');
104 | }
105 |
106 | /**
107 | * @param string $region
108 | *
109 | * @return $this
110 | */
111 | public function setApiRegion(string $region): self
112 | {
113 | $this->setParameter('api_region', $region);
114 |
115 | return $this;
116 | }
117 |
118 | /**
119 | * @param string $baseUrl
120 | *
121 | * @return $this
122 | */
123 | public function setBaseUrl(string $baseUrl): self
124 | {
125 | $this->setParameter('base_url', $baseUrl);
126 |
127 | return $this;
128 | }
129 |
130 | /**
131 | * @inheritdoc
132 | */
133 | public function setItems($items)
134 | {
135 | if ($items && !$items instanceof ItemBag) {
136 | $items = new ItemBag($items);
137 | }
138 |
139 | return $this->setParameter('items', $items);
140 | }
141 |
142 | public function setLocale(string $locale)
143 | {
144 | $this->setParameter('locale', $locale);
145 | }
146 |
147 | /**
148 | * @param string $merchantReference
149 | *
150 | * @return $this
151 | */
152 | public function setMerchantReference1(string $merchantReference): self
153 | {
154 | $this->setParameter('merchant_reference1', $merchantReference);
155 |
156 | return $this;
157 | }
158 |
159 | /**
160 | * @param string $merchantReference
161 | *
162 | * @return $this
163 | */
164 | public function setMerchantReference2(string $merchantReference): self
165 | {
166 | $this->setParameter('merchant_reference2', $merchantReference);
167 |
168 | return $this;
169 | }
170 |
171 | /**
172 | * @param string $secret
173 | *
174 | * @return $this
175 | */
176 | public function setSecret(string $secret): self
177 | {
178 | $this->setParameter('secret', $secret);
179 |
180 | return $this;
181 | }
182 |
183 | /**
184 | * @param mixed $value
185 | */
186 | public function setTaxAmount($value)
187 | {
188 | $this->setParameter('tax_amount', $value);
189 | }
190 |
191 | /**
192 | * @param string $username
193 | *
194 | * @return $this
195 | */
196 | public function setUsername(string $username): self
197 | {
198 | $this->setParameter('username', $username);
199 |
200 | return $this;
201 | }
202 |
203 | /**
204 | * @param ResponseInterface $response
205 | *
206 | * @return array
207 | */
208 | protected function getResponseBody(ResponseInterface $response): array
209 | {
210 | try {
211 | return \json_decode($response->getBody()->getContents(), true);
212 | } catch (\TypeError $exception) {
213 | return [];
214 | }
215 | }
216 |
217 | /**
218 | * @param string $method
219 | * @param string $url
220 | * @param mixed $data
221 | *
222 | * @return ResponseInterface
223 | *
224 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
225 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
226 | */
227 | protected function sendRequest(string $method, string $url, $data): ResponseInterface
228 | {
229 | $headers = (new AuthenticationRequestHeaderProvider())->getHeaders($this);
230 |
231 | if ('GET' === $method) {
232 | return $this->httpClient->request(
233 | $method,
234 | $this->getBaseUrl() . $url,
235 | $headers
236 | );
237 | }
238 |
239 | return $this->httpClient->request(
240 | $method,
241 | $this->getBaseUrl() . $url,
242 | \array_merge(
243 | ['Content-Type' => 'application/json'],
244 | $headers
245 | ),
246 | \json_encode($data)
247 | );
248 | }
249 | }
250 |
--------------------------------------------------------------------------------
/src/Message/AbstractResponse.php:
--------------------------------------------------------------------------------
1 | data['error_code'] ?? null;
14 | }
15 |
16 | /**
17 | * @inheritdoc
18 | */
19 | public function getMessage()
20 | {
21 | return $this->data['error_message'] ?? null;
22 | }
23 |
24 | /**
25 | * @inheritDoc
26 | */
27 | public function getTransactionReference()
28 | {
29 | return $this->data['order_id'] ?? null;
30 | }
31 |
32 | public function isSuccessful(): bool
33 | {
34 | return !isset($this->data['error_code']);
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/src/Message/AcknowledgeRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
20 |
21 | return null;
22 | }
23 |
24 | /**
25 | * @inheritDoc
26 | *
27 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
28 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
29 | */
30 | public function sendData($data)
31 | {
32 | $response = $this->sendRequest(
33 | 'POST',
34 | \sprintf(
35 | '/ordermanagement/v1/orders/%s/acknowledge',
36 | $this->getTransactionReference()
37 | ),
38 | $data
39 | );
40 |
41 | return new AcknowledgeResponse(
42 | $this,
43 | $this->getResponseBody($response),
44 | $response->getStatusCode()
45 | );
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Message/AcknowledgeResponse.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
23 | }
24 |
25 | public function getStatusCode(): int
26 | {
27 | return $this->statusCode;
28 | }
29 |
30 | public function isSuccessful(): bool
31 | {
32 | return parent::isSuccessful() && 204 === $this->getStatusCode();
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Message/AuthorizeRequest.php:
--------------------------------------------------------------------------------
1 | validate(
26 | 'amount',
27 | 'currency',
28 | 'items',
29 | 'locale',
30 | 'purchase_country',
31 | 'tax_amount'
32 | );
33 |
34 | $data = $this->getOrderData();
35 | $data['merchant_urls'] = $this->getMerchantUrls();
36 |
37 | return $data;
38 | }
39 |
40 | /**
41 | * @return string|null
42 | */
43 | public function getRenderUrl()
44 | {
45 | return $this->getParameter('render_url');
46 | }
47 |
48 | /**
49 | * @inheritDoc
50 | *
51 | * @throws InvalidResponseException
52 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
53 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
54 | */
55 | public function sendData($data)
56 | {
57 | $response = $this->getTransactionReference() ?
58 | $this->sendRequest('GET', '/checkout/v3/orders/' . $this->getTransactionReference(), $data) :
59 | $this->sendRequest('POST', '/checkout/v3/orders', $data);
60 |
61 | if ($response->getStatusCode() >= 400) {
62 | throw new InvalidResponseException(
63 | \sprintf('Reason: %s (%s)', $response->getReasonPhrase(), $response->getBody())
64 | );
65 | }
66 |
67 | return new AuthorizeResponse($this, $this->getResponseBody($response), $this->getRenderUrl());
68 | }
69 |
70 | /**
71 | * @param string $url
72 | *
73 | * @return $this
74 | */
75 | public function setRenderUrl(string $url): self
76 | {
77 | $this->setParameter('render_url', $url);
78 |
79 | return $this;
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/src/Message/AuthorizeResponse.php:
--------------------------------------------------------------------------------
1 | renderUrl = $renderUrl;
21 | }
22 |
23 | /**
24 | * @inheritDoc
25 | */
26 | public function getRedirectData()
27 | {
28 | return null;
29 | }
30 |
31 | /**
32 | * @inheritDoc
33 | */
34 | public function getRedirectUrl()
35 | {
36 | return $this->renderUrl;
37 | }
38 |
39 | public function isRedirect(): bool
40 | {
41 | return null !== $this->renderUrl;
42 | }
43 |
44 | public function isSuccessful(): bool
45 | {
46 | // Authorize is only successful once it has been acknowledged
47 | return false;
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/src/Message/CaptureRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference', 'amount');
22 |
23 | $data = ['captured_amount' => $this->getAmountInteger()];
24 |
25 | if (null !== $items = $this->getItems()) {
26 | $data['order_lines'] = $this->getItemData($items);
27 | }
28 |
29 | return $data;
30 | }
31 |
32 | /**
33 | * @inheritdoc
34 | *
35 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
36 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
37 | */
38 | public function sendData($data)
39 | {
40 | $response = $this->sendRequest(
41 | 'POST',
42 | \sprintf(
43 | '/ordermanagement/v1/orders/%s/captures',
44 | $this->getTransactionReference()
45 | ),
46 | $data
47 | );
48 |
49 | return new CaptureResponse(
50 | $this,
51 | $this->getResponseBody($response),
52 | $this->getTransactionReference(),
53 | $response->getStatusCode()
54 | );
55 | }
56 | }
57 |
--------------------------------------------------------------------------------
/src/Message/CaptureResponse.php:
--------------------------------------------------------------------------------
1 | transactionReference = $transactionReference;
27 | $this->statusCode = $statusCode;
28 | }
29 |
30 | public function getStatusCode(): int
31 | {
32 | return $this->statusCode;
33 | }
34 |
35 | /**
36 | * @inheritDoc
37 | */
38 | public function getTransactionReference()
39 | {
40 | return $this->transactionReference;
41 | }
42 |
43 | public function isSuccessful(): bool
44 | {
45 | return parent::isSuccessful() && 201 === $this->statusCode;
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/src/Message/ExtendAuthorizationRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
20 |
21 | return null;
22 | }
23 |
24 | /**
25 | * @param mixed $data
26 | *
27 | * @return ExtendAuthorizationResponse
28 | *
29 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
30 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
31 | */
32 | public function sendData($data): ExtendAuthorizationResponse
33 | {
34 | $responseBody = $this->getResponseBody(
35 | $this->sendRequest(
36 | 'POST',
37 | \sprintf('/ordermanagement/v1/orders/%s/extend-authorization-time', $this->getTransactionReference()),
38 | $data
39 | )
40 | );
41 |
42 | return new ExtendAuthorizationResponse(
43 | $this,
44 | \array_merge(
45 | $responseBody,
46 | ['order_id' => $this->getTransactionReference()]
47 | )
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Message/ExtendAuthorizationResponse.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
20 |
21 | return null;
22 | }
23 |
24 | /**
25 | * @inheritDoc
26 | *
27 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
28 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
29 | */
30 | public function sendData($data)
31 | {
32 | $response = $this->sendRequest(
33 | 'GET',
34 | '/checkout/v3/orders/' . $this->getTransactionReference(),
35 | $data
36 | );
37 |
38 | $responseData['checkout'] = $this->getResponseBody($response);
39 |
40 | if (
41 | (isset($responseData['checkout']['status']) && 'checkout_complete' === $responseData['checkout']['status'])
42 | || 404 === $response->getStatusCode()
43 | ) {
44 | $responseData['management'] = $this->getResponseBody(
45 | $this->sendRequest(
46 | 'GET',
47 | '/ordermanagement/v1/orders/' . $this->getTransactionReference(),
48 | $data
49 | )
50 | );
51 | }
52 |
53 | return new FetchTransactionResponse($this, $responseData);
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Message/FetchTransactionResponse.php:
--------------------------------------------------------------------------------
1 | data['checkout']['order_id'] ?? $this->data['management']['order_id'];
14 | }
15 |
16 | public function isSuccessful(): bool
17 | {
18 | return parent::isSuccessful() &&
19 | (!empty($this->data['checkout']['status']) || !empty($this->data['management']['status']));
20 | }
21 | }
22 |
--------------------------------------------------------------------------------
/src/Message/ItemDataTrait.php:
--------------------------------------------------------------------------------
1 | getTaxRate();
22 | $price = null === $item->getPrice() ? $this->convertToMoney(0) : $this->convertToMoney($item->getPrice());
23 | $totalTaxAmount = null === $item->getTotalTaxAmount()
24 | ? $this->convertToMoney(0)
25 | : $this->convertToMoney($item->getTotalTaxAmount());
26 | $totalDiscountAmount = null === $item->getTotalDiscountAmount()
27 | ? $this->convertToMoney(0)
28 | : $this->convertToMoney($item->getTotalDiscountAmount());
29 | $totalAmount = null === $item->getTotalAmount()
30 | ? $price->multiply($item->getQuantity())->subtract($totalDiscountAmount)
31 | : $this->convertToMoney($item->getTotalAmount());
32 |
33 | $orderLines[] = [
34 | 'type' => $item->getType(),
35 | 'name' => $item->getName(),
36 | 'quantity' => $item->getQuantity(),
37 | 'tax_rate' => null === $taxRate ? 0 : (int) ($item->getTaxRate() * 100),
38 | 'total_amount' => (int) $totalAmount->getAmount(),
39 | 'total_tax_amount' => (int) $totalTaxAmount->getAmount(),
40 | 'total_discount_amount' => (int) $totalDiscountAmount->getAmount(),
41 | 'unit_price' => (int) $price->getAmount(),
42 | 'merchant_data' => $item->getMerchantData(),
43 | ];
44 | }
45 |
46 | return $orderLines;
47 | }
48 |
49 | abstract protected function convertToMoney($amount): Money;
50 | }
51 |
--------------------------------------------------------------------------------
/src/Message/MerchantUrlsDataTrait.php:
--------------------------------------------------------------------------------
1 | getParameter('addressUpdateUrl');
17 | }
18 |
19 | /**
20 | * @return string|null
21 | */
22 | public function getCancellationTermsUrl()
23 | {
24 | return $this->getParameter('cancellationTermsUrl');
25 | }
26 |
27 | /**
28 | * @return array
29 | *
30 | * @throws InvalidRequestException
31 | */
32 | public function getMerchantUrls(): array
33 | {
34 | $this->validate('notifyUrl', 'returnUrl', 'termsUrl', 'validationUrl');
35 |
36 | $returnUrl = $this->getReturnUrl();
37 |
38 | $merchantUrls = [
39 | 'checkout' => $returnUrl,
40 | 'confirmation' => $this->getConfirmationUrl() ?? $returnUrl,
41 | 'push' => $this->getNotifyUrl(),
42 | 'terms' => $this->getTermsUrl(),
43 | 'validation' => $this->getValidationUrl(),
44 | ];
45 |
46 | if (null !== ($cancellationTermsUrl = $this->getCancellationTermsUrl())) {
47 | $merchantUrls['cancellation_terms'] = $cancellationTermsUrl;
48 | }
49 |
50 | if (null !== ($addressUpdateUrl = $this->getAddressUpdateUrl())) {
51 | $merchantUrls['address_update'] = $addressUpdateUrl;
52 | }
53 |
54 | return $merchantUrls;
55 | }
56 |
57 | /**
58 | * @return string|null
59 | */
60 | abstract public function getNotifyUrl();
61 |
62 | /**
63 | * @return string|null
64 | */
65 | abstract public function getReturnUrl();
66 |
67 | /**
68 | * @return string|null
69 | */
70 | public function getTermsUrl()
71 | {
72 | return $this->getParameter('termsUrl');
73 | }
74 |
75 | /**
76 | * @return string|null
77 | */
78 | public function getValidationUrl()
79 | {
80 | return $this->getParameter('validationUrl');
81 | }
82 |
83 | /**
84 | * @return string|null
85 | */
86 | public function getConfirmationUrl()
87 | {
88 | return $this->getParameter('confirmationUrl');
89 | }
90 |
91 | /**
92 | * @param string $url
93 | *
94 | * @return $this
95 | */
96 | public function setAddressUpdateUrl(string $url): self
97 | {
98 | $this->setParameter('addressUpdateUrl', $url);
99 |
100 | return $this;
101 | }
102 |
103 | /**
104 | * @param string $url
105 | *
106 | * @return $this
107 | */
108 | public function setCancellationTermsUrl(string $url): self
109 | {
110 | $this->setParameter('cancellationTermsUrl', $url);
111 |
112 | return $this;
113 | }
114 |
115 | /**
116 | * @param string $url
117 | *
118 | * @return $this
119 | */
120 | public function setTermsUrl(string $url): self
121 | {
122 | $this->setParameter('termsUrl', $url);
123 |
124 | return $this;
125 | }
126 |
127 | /**
128 | * @param string $url
129 | *
130 | * @return $this
131 | */
132 | public function setValidationUrl(string $url): self
133 | {
134 | $this->setParameter('validationUrl', $url);
135 |
136 | return $this;
137 | }
138 |
139 | /**
140 | * @param string $url
141 | *
142 | * @return $this
143 | */
144 | public function setConfirmationUrl(string $url): self
145 | {
146 | $this->setParameter('confirmationUrl', $url);
147 |
148 | return $this;
149 | }
150 |
151 | /**
152 | * @param string $args,... a variable length list of required parameters
153 | *
154 | * @throws InvalidRequestException
155 | */
156 | abstract public function validate(...$args);
157 |
158 | /**
159 | * @param string $key
160 | *
161 | * @return mixed
162 | */
163 | abstract protected function getParameter($key);
164 |
165 | /**
166 | * Set a single parameter
167 | *
168 | * @param string $key The parameter key
169 | * @param mixed $value The value to set
170 | *
171 | * @return AbstractRequest Provides a fluent interface
172 | *
173 | * @throws RuntimeException if a request parameter is modified after the request has been sent.
174 | */
175 | abstract protected function setParameter($key, $value);
176 | }
177 |
--------------------------------------------------------------------------------
/src/Message/RefundRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference', 'amount');
24 |
25 | $data = ['refunded_amount' => $this->getAmountInteger()];
26 | $items = $this->getItems();
27 |
28 | if (null !== $items) {
29 | $data['order_lines'] = $this->getItemData($items);
30 | }
31 |
32 | return $data;
33 | }
34 |
35 | /**
36 | * @inheritdoc
37 | *
38 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
39 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
40 | */
41 | public function sendData($data)
42 | {
43 | $response = $this->sendRequest(
44 | 'POST',
45 | \sprintf('/ordermanagement/v1/orders/%s/refunds', $this->getTransactionReference()),
46 | $data
47 | );
48 |
49 | return new RefundResponse(
50 | $this,
51 | $this->getResponseBody($response),
52 | $response->getStatusCode()
53 | );
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/src/Message/RefundResponse.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
23 | }
24 |
25 | public function getStatusCode(): int
26 | {
27 | return $this->statusCode;
28 | }
29 |
30 | public function isSuccessful(): bool
31 | {
32 | return parent::isSuccessful() && 201 === $this->statusCode;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/Message/UpdateCustomerAddressRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference', 'billing_address', 'shipping_address');
20 |
21 | return [
22 | 'shipping_address' => $this->getShippingAddress()->getArrayCopy(),
23 | 'billing_address' => $this->getBillingAddress()->getArrayCopy(),
24 | ];
25 | }
26 |
27 | /**
28 | * @inheritDoc
29 | *
30 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
31 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
32 | */
33 | public function sendData($data)
34 | {
35 | $response = $this->sendRequest(
36 | 'PATCH',
37 | \sprintf('/ordermanagement/v1/orders/%s/customer-details', $this->getTransactionReference()),
38 | $data
39 | );
40 |
41 | return new UpdateCustomerAddressResponse(
42 | $this,
43 | \array_merge(
44 | $this->getResponseBody($response),
45 | ['order_id' => $this->getTransactionReference()]
46 | ),
47 | $response->getStatusCode()
48 | );
49 | }
50 | }
51 |
--------------------------------------------------------------------------------
/src/Message/UpdateCustomerAddressResponse.php:
--------------------------------------------------------------------------------
1 | statusCode = (int) $statusCode;
23 | }
24 |
25 | public function isSuccessful(): bool
26 | {
27 | return parent::isSuccessful() && 204 === $this->statusCode;
28 | }
29 | }
30 |
--------------------------------------------------------------------------------
/src/Message/UpdateMerchantReferencesRequest.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
11 |
12 | return [
13 | 'merchant_reference1' => $this->getMerchantReference1(),
14 | 'merchant_reference2' => $this->getMerchantReference2(),
15 | ];
16 | }
17 |
18 | public function sendData($data)
19 | {
20 | return new UpdateMerchantReferencesResponse(
21 | $this,
22 | $this->getResponseBody(
23 | $this->sendRequest(
24 | 'PATCH',
25 | \sprintf('/ordermanagement/v1/orders/%s/merchant-references', $this->getTransactionReference()),
26 | $data
27 | )
28 | )
29 | );
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/src/Message/UpdateMerchantReferencesResponse.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
24 | $data = $this->getOrderData();
25 |
26 | try {
27 | $data['merchant_urls'] = $this->getMerchantUrls();
28 | } catch (InvalidRequestException $exception) {
29 | // Insufficient data for merchant urls
30 | }
31 |
32 | return $data;
33 | }
34 |
35 | /**
36 | * @inheritdoc
37 | *
38 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
39 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
40 | */
41 | public function sendData($data)
42 | {
43 | return new UpdateTransactionResponse(
44 | $this,
45 | $this->getResponseBody(
46 | $this->sendRequest(
47 | 'POST',
48 | \sprintf('/checkout/v3/orders/%s', $this->getTransactionReference()),
49 | $data
50 | )
51 | )
52 | );
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/src/Message/UpdateTransactionResponse.php:
--------------------------------------------------------------------------------
1 | validate('transactionReference');
20 |
21 | return [];
22 | }
23 |
24 | /**
25 | * @inheritdoc
26 | *
27 | * @throws RequestException when the HTTP client is passed a request that is invalid and cannot be sent.
28 | * @throws NetworkException if there is an error with the network or the remote server cannot be reached.
29 | */
30 | public function sendData($data)
31 | {
32 | $baseUrl = \sprintf('/ordermanagement/v1/orders/%s', $this->getTransactionReference());
33 | $orderManagementResponse = $this->sendRequest('GET', $baseUrl, []);
34 |
35 | $order = $this->getResponseBody($orderManagementResponse);
36 |
37 | $voidUrl = \sprintf('%s/release-remaining-authorization', $baseUrl);
38 |
39 | if (empty($order['captures'])) {
40 | $voidUrl = \sprintf('%s/cancel', $baseUrl);
41 | }
42 |
43 | $response = $this->sendRequest('POST', $voidUrl, $data);
44 |
45 | return new VoidResponse(
46 | $this,
47 | $this->getResponseBody($response),
48 | $response->getStatusCode()
49 | );
50 | }
51 | }
52 |
--------------------------------------------------------------------------------
/src/Message/VoidResponse.php:
--------------------------------------------------------------------------------
1 | statusCode = $statusCode;
23 | }
24 |
25 | public function getStatusCode(): int
26 | {
27 | return $this->statusCode;
28 | }
29 |
30 | public function isSuccessful(): bool
31 | {
32 | return parent::isSuccessful() && 204 === $this->statusCode;
33 | }
34 | }
35 |
--------------------------------------------------------------------------------
/src/WidgetOptions.php:
--------------------------------------------------------------------------------
1 | 'eCommerce',
17 | 'allow_separate_shipping_address' => false,
18 | 'color_button' => null,
19 | 'color_button_text' => null,
20 | 'color_checkbox' => null,
21 | 'color_checkbox_checkmark' => null,
22 | 'color_header' => null,
23 | 'color_link' => null,
24 | 'date_of_birth_mandatory' => false,
25 | 'shipping_details' => null,
26 | 'title_mandatory' => false,
27 | 'additional_checkbox' => null,
28 | 'radius_border' => null,
29 | 'show_subtotal_detail' => false,
30 | 'require_validate_callback_success' => false,
31 | 'allow_global_billing_countries' => false,
32 | ];
33 |
34 | return new self(\array_merge($defaults, \array_intersect_key($data, $defaults)));
35 | }
36 | }
37 |
--------------------------------------------------------------------------------
/tests/AuthenticationRequestHeaderProviderTest.php:
--------------------------------------------------------------------------------
1 | createMock(AbstractRequest::class);
15 |
16 | $userName = 'foobar';
17 | $request->expects(self::once())->method('getUsername')->willReturn($userName);
18 | $secret = 'barbaz';
19 | $request->expects(self::once())->method('getSecret')->willReturn($secret);
20 |
21 | self::assertEquals(
22 | [
23 | 'Authorization' => \sprintf(
24 | 'Basic %s',
25 | \base64_encode(
26 | \sprintf(
27 | '%s:%s',
28 | $userName,
29 | $secret
30 | )
31 | )
32 | ),
33 | ],
34 | (new AuthenticationRequestHeaderProvider())->getHeaders($request)
35 | );
36 | }
37 | }
38 |
--------------------------------------------------------------------------------
/tests/ExpectedAuthorizationHeaderTrait.php:
--------------------------------------------------------------------------------
1 | \sprintf(
17 | 'Basic %s',
18 | \base64_encode(
19 | \sprintf(
20 | '%s:%s',
21 | RequestTestCase::USERNAME,
22 | RequestTestCase::SECRET
23 | )
24 | )
25 | ),
26 | ];
27 | }
28 | }
29 |
--------------------------------------------------------------------------------
/tests/GatewayTest.php:
--------------------------------------------------------------------------------
1 | gateway = new Gateway($this->getHttpClient(), $this->getHttpRequest());
27 | }
28 |
29 | /**
30 | * @return array
31 | */
32 | public function baseUrlDataProvider(): array
33 | {
34 | return [
35 | [true, Gateway::API_VERSION_EUROPE, Gateway::EU_TEST_BASE_URL],
36 | [false, Gateway::API_VERSION_EUROPE, Gateway::EU_BASE_URL],
37 | [true, Gateway::API_VERSION_NORTH_AMERICA, Gateway::NA_TEST_BASE_URL],
38 | [false, Gateway::API_VERSION_NORTH_AMERICA, Gateway::NA_BASE_URL],
39 | ];
40 | }
41 |
42 | public function testAcknowledge()
43 | {
44 | $this->assertInstanceOf(AcknowledgeRequest::class, $this->gateway->acknowledge());
45 | }
46 |
47 | public function testAuthorize()
48 | {
49 | $this->assertInstanceOf(AuthorizeRequest::class, $this->gateway->authorize());
50 | }
51 |
52 | public function testCapture()
53 | {
54 | $this->assertInstanceOf(CaptureRequest::class, $this->gateway->capture());
55 | }
56 |
57 | public function testExtendAuthorizationWillReturnInstanceOfExtendAuthorization()
58 | {
59 | $request = $this->gateway->extendAuthorization(['transactionReference' => 'foobar']);
60 |
61 | $this->assertInstanceOf(ExtendAuthorizationRequest::class, $request);
62 | self::assertSame('foobar', $request->getTransactionReference());
63 | }
64 |
65 | public function testFetchTransaction()
66 | {
67 | $this->assertInstanceOf(FetchTransactionRequest::class, $this->gateway->fetchTransaction());
68 | }
69 |
70 | /**
71 | * @dataProvider baseUrlDataProvider
72 | *
73 | * @param bool $testMode
74 | * @param string $region
75 | * @param string $expectedUrl
76 | */
77 | public function testInitialisationWillSetCorrectBaseUrl($testMode, $region, $expectedUrl)
78 | {
79 | $this->gateway->initialize(['testMode' => $testMode, 'api_region' => $region]);
80 | self::assertEquals($expectedUrl, $this->gateway->getParameter('base_url'));
81 | }
82 |
83 | /**
84 | * @dataProvider baseUrlDataProvider
85 | *
86 | * @param bool $testMode
87 | * @param string $region
88 | * @param string $expectedUrl
89 | */
90 | public function testSetTestModeWillSetCorrectBaseUrl($testMode, $region, $expectedUrl)
91 | {
92 | $this->gateway->initialize(['api_region' => $region]);
93 | $this->gateway->setTestMode($testMode);
94 | self::assertEquals($expectedUrl, $this->gateway->getParameter('base_url'));
95 | }
96 |
97 | public function testRefund()
98 | {
99 | $this->assertInstanceOf(RefundRequest::class, $this->gateway->refund());
100 | }
101 |
102 | public function testUpdateCustomerAddress()
103 | {
104 | $this->assertInstanceOf(UpdateCustomerAddressRequest::class, $this->gateway->updateCustomerAddress());
105 | }
106 |
107 | public function testUpdateMerchantReferences()
108 | {
109 | $this->assertInstanceOf(UpdateMerchantReferencesRequest::class, $this->gateway->updateMerchantReferences());
110 | }
111 |
112 | public function testUpdateTransaction()
113 | {
114 | $this->assertInstanceOf(UpdateTransactionRequest::class, $this->gateway->updateTransaction());
115 | }
116 |
117 | public function testVoid()
118 | {
119 | $this->assertInstanceOf(VoidRequest::class, $this->gateway->void());
120 | }
121 | }
122 |
--------------------------------------------------------------------------------
/tests/ItemBagTest.php:
--------------------------------------------------------------------------------
1 | createMock(ItemInterface::class);
15 |
16 | $itemBag = new ItemBag();
17 | $itemBag->add($item);
18 |
19 | self::assertSame([$item], $itemBag->all());
20 | }
21 |
22 | public function testAddNonItem()
23 | {
24 | $itemArray = ['tax_rate' => 1000];
25 |
26 | $itemBag = new ItemBag();
27 | $itemBag->add($itemArray);
28 |
29 | self::assertEquals($itemArray, $itemBag->all()[0]->getParameters());
30 | }
31 | }
32 |
--------------------------------------------------------------------------------
/tests/ItemTest.php:
--------------------------------------------------------------------------------
1 | setTaxRate($taxRate);
22 | $item->setTotalTaxAmount($totalTaxAmount);
23 | $item->setTotalAmount($totalAmount);
24 | $item->setTotalDiscountAmount($totalDiscountAmount);
25 | $item->setType($type);
26 | $item->setMerchantData($merchantData);
27 |
28 | self::assertEquals($taxRate, $item->getTaxRate());
29 | self::assertEquals($totalTaxAmount, $item->getTotalTaxAmount());
30 | self::assertEquals($totalAmount, $item->getTotalAmount());
31 | self::assertEquals($totalDiscountAmount, $item->getTotalDiscountAmount());
32 | self::assertEquals($type, $item->getType());
33 | self::assertEquals($merchantData, $item->getMerchantData());
34 | }
35 | }
36 |
--------------------------------------------------------------------------------
/tests/Message/AbstractRequestTest.php:
--------------------------------------------------------------------------------
1 | getHttpClient();
22 | $httpRequest = $this->getHttpRequest();
23 |
24 | $this->request = new class ($httpClient, $httpRequest) extends AbstractRequest
25 | {
26 | /**
27 | * @inheritdoc
28 | */
29 | public function sendData($data)
30 | {
31 | return [];
32 | }
33 |
34 | /**
35 | * @inheritdoc
36 | */
37 | public function getData()
38 | {
39 | return [];
40 | }
41 | };
42 | }
43 |
44 | public function testGetAmountWithDecimalStringShouldReturnCorrectValue()
45 | {
46 | $amount = '5.25';
47 | $currencyIso = 'EUR';
48 |
49 | $this->request->setCurrency($currencyIso);
50 | $this->request->setAmount($amount);
51 |
52 | self::assertSame('525', $this->request->getAmount()->getAmount());
53 | }
54 |
55 | public function testGetResponseBodyWillReturnArray()
56 | {
57 | $httpClient = $this->getHttpClient();
58 | $httpRequest = $this->getHttpRequest();
59 |
60 | $request = new class ($httpClient, $httpRequest) extends AbstractRequest
61 | {
62 | public function sendData($data)
63 | {
64 | return [];
65 | }
66 |
67 | public function getData()
68 | {
69 | return [];
70 | }
71 |
72 | // phpcs:disable Generic.CodeAnalysis.UselessOverridingMethod
73 | public function getResponseBody(ResponseInterface $response): array
74 | {
75 | return parent::getResponseBody($response); // TODO: Change the autogenerated stub
76 | }
77 | };
78 |
79 | $response = $this->createMock(ResponseInterface::class);
80 | $stream = $this->createMock(StreamInterface::class);
81 |
82 | $response->expects(self::once())
83 | ->method('getBody')
84 | ->willReturn($stream);
85 |
86 | $decodedResponse = ['foo' => 'bar'];
87 | $stream->expects(self::once())
88 | ->method('getContents')
89 | ->willReturn(\json_encode($decodedResponse));
90 |
91 | self::assertSame($decodedResponse, $request->getResponseBody($response));
92 | }
93 |
94 | public function testGetResponseBodyWillReturnArrayIfResponseIsEmtpy()
95 | {
96 | $httpClient = $this->getHttpClient();
97 | $httpRequest = $this->getHttpRequest();
98 |
99 | $request = new class ($httpClient, $httpRequest) extends AbstractRequest
100 | {
101 | public function sendData($data)
102 | {
103 | return [];
104 | }
105 |
106 | public function getData()
107 | {
108 | return [];
109 | }
110 |
111 | public function getResponseBody(ResponseInterface $response): array
112 | {
113 | return parent::getResponseBody($response); // TODO: Change the autogenerated stub
114 | }
115 | };
116 |
117 | $response = $this->createMock(ResponseInterface::class);
118 | $stream = $this->createMock(StreamInterface::class);
119 |
120 | $response->expects(self::once())
121 | ->method('getBody')
122 | ->willReturn($stream);
123 |
124 | $stream->expects(self::once())
125 | ->method('getContents')
126 | ->willReturn(null);
127 |
128 | self::assertSame([], $request->getResponseBody($response));
129 | }
130 |
131 | public function testGetTaxAmountWithDecimalStringShouldReturnCorrectValue()
132 | {
133 | $taxAmount = '5.25';
134 | $currencyIso = 'EUR';
135 |
136 | $this->request->setCurrency($currencyIso);
137 | $this->request->setTaxAmount($taxAmount);
138 |
139 | self::assertSame('525', $this->request->getTaxAmount()->getAmount());
140 | }
141 |
142 | public function testGetters()
143 | {
144 | $locale = 'nl_NL';
145 | $taxAmount = 500;
146 | $currencyIso = 'EUR';
147 |
148 | $this->request->setCurrency($currencyIso);
149 | $this->request->setLocale($locale);
150 | $this->request->setTaxAmount(new Money($taxAmount, new Currency($currencyIso)));
151 |
152 | self::assertSame($locale, $this->request->getLocale());
153 | self::assertSame((string) $taxAmount, $this->request->getTaxAmount()->getAmount());
154 | }
155 |
156 | public function testSetItemsWithArray()
157 | {
158 | $itemsArray = [['tax_rate' => 10]];
159 |
160 | $this->request->setItems($itemsArray);
161 |
162 | self::assertEquals(new ItemBag($itemsArray), $this->request->getParameters()['items']);
163 | }
164 |
165 | public function testSetItemsWithItemBag()
166 | {
167 | $itemBag = $this->createMock(ItemBag::class);
168 |
169 | $this->request->setItems($itemBag);
170 |
171 | self::assertSame($itemBag, $this->request->getParameters()['items']);
172 | }
173 | }
174 |
--------------------------------------------------------------------------------
/tests/Message/AbstractResponseTest.php:
--------------------------------------------------------------------------------
1 | getMockForAbstractClass(
14 | AbstractResponse::class,
15 | [$this->getMockRequest(), ['order_id' => 'foo']]
16 | );
17 |
18 | self::assertEquals('foo', $response->getTransactionReference());
19 | }
20 |
21 | public function testGetTransactionReferenceReturnsNullIfNoOrderIdExists()
22 | {
23 | $response = $this->getMockForAbstractClass(
24 | AbstractResponse::class,
25 | [$this->getMockRequest(), []]
26 | );
27 |
28 | self::assertNull($response->getTransactionReference());
29 | }
30 |
31 | public function testIsSuccessfulWillReturnFalseIfResponseContainsErrors()
32 | {
33 | $response = $this->getMockForAbstractClass(
34 | AbstractResponse::class,
35 | [$this->getMockRequest(), ['error_code' => 'foo']]
36 | );
37 |
38 | self::assertFalse($response->isSuccessful());
39 | }
40 |
41 | public function testIsSuccessfulWillReturnTrueIfResponseContainsNoErrors()
42 | {
43 | $response = $this->getMockForAbstractClass(AbstractResponse::class, [$this->getMockRequest(), []]);
44 |
45 | self::assertTrue($response->isSuccessful());
46 | }
47 |
48 | public function testGetMessageWillReturnErrorMessage()
49 | {
50 | $response = $this->getMockForAbstractClass(
51 | AbstractResponse::class,
52 | [$this->getMockRequest(), ['error_message' => 'oh noes!']]
53 | );
54 |
55 | self::assertSame('oh noes!', $response->getMessage());
56 | }
57 |
58 | public function testGetMessageWillReturnNullIfResponseContainsNoErrorMessage()
59 | {
60 | $response = $this->getMockForAbstractClass(AbstractResponse::class, [$this->getMockRequest(), []]);
61 |
62 | self::assertNull($response->getMessage());
63 | }
64 |
65 | public function testGetCodeWillReturnErrorCode()
66 | {
67 | $response = $this->getMockForAbstractClass(
68 | AbstractResponse::class,
69 | [$this->getMockRequest(), ['error_code' => 'oh_noes']]
70 | );
71 |
72 | self::assertSame('oh_noes', $response->getCode());
73 | }
74 |
75 | public function testGetCodeWillReturnNullIfResponseContainsNoErrorCode()
76 | {
77 | $response = $this->getMockForAbstractClass(AbstractResponse::class, [$this->getMockRequest(), []]);
78 |
79 | self::assertNull($response->getCode());
80 | }
81 | }
82 |
--------------------------------------------------------------------------------
/tests/Message/AcknowledgeRequestTest.php:
--------------------------------------------------------------------------------
1 | acknowledgeRequest = new AcknowledgeRequest($this->httpClient, $this->getHttpRequest());
19 | }
20 |
21 | public function testGetData()
22 | {
23 | $this->acknowledgeRequest->initialize(['transactionReference' => 'foo']);
24 |
25 | self::assertNull($this->acknowledgeRequest->getData());
26 | }
27 |
28 | public function testSendData()
29 | {
30 | $inputData = ['request-data' => 'yey?'];
31 | $expectedData = [];
32 |
33 | $response = $this->setExpectedPostRequest(
34 | $inputData,
35 | $expectedData,
36 | self::BASE_URL . '/ordermanagement/v1/orders/foo/acknowledge'
37 | );
38 |
39 | $response->expects(self::once())->method('getStatusCode')->willReturn(204);
40 |
41 | $this->acknowledgeRequest->initialize(
42 | [
43 | 'base_url' => self::BASE_URL,
44 | 'username' => self::USERNAME,
45 | 'secret' => self::SECRET,
46 | 'transactionReference' => 'foo',
47 | ]
48 | );
49 |
50 | $acknowledgeResponse = $this->acknowledgeRequest->sendData($inputData);
51 |
52 | self::assertInstanceOf(AcknowledgeResponse::class, $acknowledgeResponse);
53 | self::assertSame($expectedData, $acknowledgeResponse->getData());
54 | }
55 | }
56 |
--------------------------------------------------------------------------------
/tests/Message/AcknowledgeResponseTest.php:
--------------------------------------------------------------------------------
1 | createMock(RequestInterface::class);
27 | $acknowledgeResponse = new AcknowledgeResponse($request, [], 200);
28 |
29 | self::assertNull($acknowledgeResponse->getCode());
30 | }
31 |
32 | public function testGetMessageWillReturnErrorMessage()
33 | {
34 | $request = $this->createMock(RequestInterface::class);
35 | $acknowledgeResponse = new AcknowledgeResponse($request, ['error_message' => 'oh noes!'], 200);
36 |
37 | self::assertSame('oh noes!', $acknowledgeResponse->getMessage());
38 | }
39 |
40 | public function testGetTransactionReferenceReturnsIdFromOrder()
41 | {
42 | $request = $this->createMock(RequestInterface::class);
43 | $acknowledgeResponse = new AcknowledgeResponse($request, ['order_id' => 'foo'], 200);
44 |
45 | self::assertEquals('foo', $acknowledgeResponse->getTransactionReference());
46 | }
47 |
48 | /**
49 | * @dataProvider responseCodeProvider
50 | *
51 | * @param string $responseCode
52 | * @param bool $expectedResult
53 | */
54 | public function testIsSuccessfulWillReturnCorrectStateWithResponseCode($responseCode, $expectedResult)
55 | {
56 | $request = $this->createMock(RequestInterface::class);
57 |
58 | $acknowledgeResponse = new AcknowledgeResponse($request, [], $responseCode);
59 |
60 | self::assertEquals($expectedResult, $acknowledgeResponse->isSuccessful());
61 | }
62 |
63 | public function testIsSuccessfulWillReturnFalseWhenErrorIsFound()
64 | {
65 | $request = $this->createMock(RequestInterface::class);
66 |
67 | $acknowledgeResponse = new AcknowledgeResponse($request, ['error_code' => 'foobar'], 200);
68 |
69 | self::assertFalse($acknowledgeResponse->isSuccessful());
70 | }
71 | }
72 |
--------------------------------------------------------------------------------
/tests/Message/AddressTest.php:
--------------------------------------------------------------------------------
1 | self::ORGANIZATION_NAME,
38 | 'reference' => self::REFERENCE,
39 | 'attention' => self::ATTENTION,
40 | 'family_name' => self::FAMILY_NAME,
41 | 'given_name' => self::GIVEN_NAME,
42 | 'email' => self::EMAIL,
43 | 'title' => self::TITLE,
44 | 'street_address' => self::STREET_ADDRESS_1,
45 | 'street_address2' => self::STREET_ADDRESS_2,
46 | 'street_name' => self::STREET,
47 | 'house_extension' => self::HOUSE_EXTENSION,
48 | 'street_number' => self::STREET_NUMBER,
49 | 'postal_code' => self::POSTAL_CODE,
50 | 'city' => self::CITY,
51 | 'region' => self::REGION,
52 | 'phone' => self::PHONE,
53 | 'country' => self::COUNTRY,
54 | ],
55 | [
56 | 'organization_name' => self::ORGANIZATION_NAME,
57 | 'reference' => self::REFERENCE,
58 | 'attention' => self::ATTENTION,
59 | 'family_name' => self::FAMILY_NAME,
60 | 'given_name' => self::GIVEN_NAME,
61 | 'email' => self::EMAIL,
62 | 'title' => self::TITLE,
63 | 'street_address' => self::STREET_ADDRESS_1,
64 | 'street_address2' => self::STREET_ADDRESS_2,
65 | 'street_name' => self::STREET,
66 | 'house_extension' => self::HOUSE_EXTENSION,
67 | 'street_number' => self::STREET_NUMBER,
68 | 'postal_code' => self::POSTAL_CODE,
69 | 'city' => self::CITY,
70 | 'region' => self::REGION,
71 | 'phone' => self::PHONE,
72 | 'country' => self::COUNTRY,
73 | ],
74 | ],
75 | [
76 | [
77 | 'organization_name' => self::ORGANIZATION_NAME,
78 | 'reference' => self::REFERENCE,
79 | 'attention' => self::ATTENTION,
80 | 'family_name' => self::FAMILY_NAME,
81 | 'given_name' => self::GIVEN_NAME,
82 | 'email' => self::EMAIL,
83 | 'title' => self::TITLE,
84 | 'street_name' => self::STREET,
85 | 'house_extension' => self::HOUSE_EXTENSION,
86 | 'street_number' => self::STREET_NUMBER,
87 | 'postal_code' => self::POSTAL_CODE,
88 | 'city' => self::CITY,
89 | 'region' => self::REGION,
90 | 'phone' => self::PHONE,
91 | 'country' => self::COUNTRY,
92 | ],
93 | [
94 | 'organization_name' => self::ORGANIZATION_NAME,
95 | 'reference' => self::REFERENCE,
96 | 'attention' => self::ATTENTION,
97 | 'family_name' => self::FAMILY_NAME,
98 | 'given_name' => self::GIVEN_NAME,
99 | 'email' => self::EMAIL,
100 | 'title' => self::TITLE,
101 | 'street_address' => null,
102 | 'street_address2' => null,
103 | 'street_name' => self::STREET,
104 | 'house_extension' => self::HOUSE_EXTENSION,
105 | 'street_number' => self::STREET_NUMBER,
106 | 'postal_code' => self::POSTAL_CODE,
107 | 'city' => self::CITY,
108 | 'region' => self::REGION,
109 | 'phone' => self::PHONE,
110 | 'country' => 'NL',
111 | ],
112 | ],
113 | [
114 | [
115 | 'organization_name' => self::ORGANIZATION_NAME,
116 | 'reference' => self::REFERENCE,
117 | 'attention' => self::ATTENTION,
118 | 'family_name' => self::FAMILY_NAME,
119 | 'given_name' => self::GIVEN_NAME,
120 | 'email' => self::EMAIL,
121 | 'title' => self::TITLE,
122 | 'street_name' => self::STREET,
123 | 'house_extension' => self::HOUSE_EXTENSION,
124 | 'street_number' => self::STREET_NUMBER,
125 | 'postal_code' => self::POSTAL_CODE,
126 | 'city' => self::CITY,
127 | 'region' => self::REGION,
128 | 'phone' => self::PHONE,
129 | 'country' => self::COUNTRY,
130 | self::FAMILY_NAME => self::GIVEN_NAME,
131 | ],
132 | [
133 | 'organization_name' => self::ORGANIZATION_NAME,
134 | 'reference' => self::REFERENCE,
135 | 'attention' => self::ATTENTION,
136 | 'family_name' => self::FAMILY_NAME,
137 | 'given_name' => self::GIVEN_NAME,
138 | 'email' => self::EMAIL,
139 | 'title' => self::TITLE,
140 | 'street_address' => null,
141 | 'street_address2' => null,
142 | 'street_name' => self::STREET,
143 | 'house_extension' => self::HOUSE_EXTENSION,
144 | 'street_number' => self::STREET_NUMBER,
145 | 'postal_code' => self::POSTAL_CODE,
146 | 'city' => self::CITY,
147 | 'region' => self::REGION,
148 | 'phone' => self::PHONE,
149 | 'country' => self::COUNTRY,
150 | ],
151 | ],
152 | ];
153 | }
154 |
155 | /**
156 | * @dataProvider fromArrayDataProvider
157 | *
158 | * @param array $data
159 | * @param array $expectedOutcome
160 | */
161 | public function testFromArrayShoulReturnArrayWithCorrectKeys(array $data, array $expectedOutcome)
162 | {
163 | self::assertEquals($expectedOutcome, Address::fromArray($data)->getArrayCopy());
164 | }
165 |
166 | /**
167 | * @return array
168 | */
169 | public function toArrayDataProvider(): array
170 | {
171 | return [
172 | [
173 | [
174 | 'organization_name' => self::ORGANIZATION_NAME,
175 | 'reference' => self::REFERENCE,
176 | 'attention' => self::ATTENTION,
177 | 'family_name' => self::FAMILY_NAME,
178 | 'given_name' => self::GIVEN_NAME,
179 | 'email' => self::EMAIL,
180 | 'title' => self::TITLE,
181 | 'street_address' => self::STREET_ADDRESS_1,
182 | 'street_address2' => self::STREET_ADDRESS_2,
183 | 'street_name' => self::STREET,
184 | 'house_extension' => self::HOUSE_EXTENSION,
185 | 'street_number' => self::STREET_NUMBER,
186 | 'postal_code' => self::POSTAL_CODE,
187 | 'city' => self::CITY,
188 | 'region' => self::REGION,
189 | 'phone' => self::PHONE,
190 | 'country' => self::COUNTRY,
191 | ],
192 | [
193 | 'organization_name' => self::ORGANIZATION_NAME,
194 | 'reference' => self::REFERENCE,
195 | 'attention' => self::ATTENTION,
196 | 'family_name' => self::FAMILY_NAME,
197 | 'given_name' => self::GIVEN_NAME,
198 | 'email' => self::EMAIL,
199 | 'title' => self::TITLE,
200 | 'street_address' => self::STREET_ADDRESS_1,
201 | 'street_address2' => self::STREET_ADDRESS_2,
202 | 'street_name' => self::STREET,
203 | 'house_extension' => self::HOUSE_EXTENSION,
204 | 'street_number' => self::STREET_NUMBER,
205 | 'postal_code' => self::POSTAL_CODE,
206 | 'city' => self::CITY,
207 | 'region' => self::REGION,
208 | 'phone' => self::PHONE,
209 | 'country' => self::COUNTRY,
210 | ],
211 | [],
212 | ],
213 | [
214 | [
215 | 'organization_name' => '',
216 | 'reference' => false,
217 | 'attention' => self::ATTENTION,
218 | 'family_name' => self::FAMILY_NAME,
219 | 'given_name' => self::GIVEN_NAME,
220 | 'email' => self::EMAIL,
221 | 'title' => null,
222 | 'street_name' => self::STREET,
223 | 'house_extension' => self::HOUSE_EXTENSION,
224 | 'street_number' => self::STREET_NUMBER,
225 | 'postal_code' => self::POSTAL_CODE,
226 | 'city' => self::CITY,
227 | 'region' => self::REGION,
228 | 'phone' => self::PHONE,
229 | 'country' => self::COUNTRY,
230 | self::FAMILY_NAME => self::GIVEN_NAME,
231 | ],
232 | [
233 | 'attention' => self::ATTENTION,
234 | 'family_name' => self::FAMILY_NAME,
235 | 'given_name' => self::GIVEN_NAME,
236 | 'email' => self::EMAIL,
237 | 'street_name' => self::STREET,
238 | 'house_extension' => self::HOUSE_EXTENSION,
239 | 'street_number' => self::STREET_NUMBER,
240 | 'postal_code' => self::POSTAL_CODE,
241 | 'city' => self::CITY,
242 | 'region' => self::REGION,
243 | 'phone' => self::PHONE,
244 | 'country' => self::COUNTRY,
245 | 'street_address' => null,
246 | 'street_address2' => null,
247 | ],
248 | ['title', 'organization_name', 'reference'],
249 | ],
250 | ];
251 | }
252 | }
253 |
--------------------------------------------------------------------------------
/tests/Message/AuthorizeRequestTest.php:
--------------------------------------------------------------------------------
1 | authorizeRequest = new AuthorizeRequest($this->httpClient, $this->getHttpRequest());
27 | }
28 |
29 | /**
30 | * @return array
31 | */
32 | public function invalidRequestDataProvider(): array
33 | {
34 | $itemBag = $this->createMock(ItemBag::class);
35 | $itemBag->method('getIterator')->willReturn(new \ArrayIterator([]));
36 |
37 | $data = \array_merge(
38 | [
39 | 'currency' => 'EUR',
40 | 'amount' => true,
41 | 'items' => $itemBag,
42 | 'locale' => true,
43 | 'purchase_country' => true,
44 | 'tax_amount' => new Money(1, new Currency('EUR')),
45 | ],
46 | \array_fill_keys(\array_keys($this->getMinimalValidMerchantUrlData()), true)
47 | );
48 |
49 | $cases = [];
50 |
51 | foreach ($data as $key => $value) {
52 | $cases[] = [\array_diff_key($data, [$key => $value])];
53 | }
54 |
55 | return $cases;
56 | }
57 |
58 | public function testGetDataWillReturnCorrectData()
59 | {
60 | $this->authorizeRequest->initialize(
61 | \array_merge(
62 | [
63 | 'currency' => 'EUR',
64 | 'locale' => 'nl_NL',
65 | 'amount' => '100.00',
66 | 'tax_amount' => 21,
67 | 'purchase_country' => 'NL',
68 | ],
69 | $this->getCompleteValidMerchantUrlData()
70 | )
71 | );
72 |
73 | $this->authorizeRequest->setItems([$this->getItemMock()]);
74 |
75 | self::assertEquals(
76 | [
77 | 'locale' => 'nl-NL',
78 | 'order_amount' => 10000,
79 | 'order_tax_amount' => 2100,
80 | 'order_lines' => [$this->getExpectedOrderLine()],
81 | 'merchant_urls' => $this->getCompleteExpectedMerchantUrlData(),
82 | 'purchase_country' => 'NL',
83 | 'purchase_currency' => 'EUR',
84 | ],
85 | $this->authorizeRequest->getData()
86 | );
87 | }
88 |
89 | /**
90 | * @dataProvider invalidRequestDataProvider
91 | *
92 | * @param array $requestData
93 | *
94 | * @throws InvalidRequestException
95 | */
96 | public function testGetDataWillThrowExceptionForInvalidRequest(array $requestData)
97 | {
98 | $this->authorizeRequest->initialize($requestData);
99 |
100 | $this->expectException(InvalidRequestException::class);
101 | $this->authorizeRequest->getData();
102 | }
103 |
104 | public function testGetDataWithAddressesWillReturnCorrectData()
105 | {
106 | $organization = 'Foo inc';
107 | $reference = 'ref';
108 | $attention = 'quz';
109 | $email = 'foo@bar.com';
110 | $title = 'Mr.';
111 | $streetAddress = 'Foo Street 1';
112 | $streetAddress2 = 'App. 12A';
113 | $streetName = 'Foo Street';
114 | $houseExtension = 'C';
115 | $streetNumber = '1';
116 | $postalCode = '523354';
117 | $city = 'Oss';
118 | $region = 'NB';
119 | $phone = '24234234';
120 | $country = 'NL';
121 |
122 | $shippingAddress = [
123 | 'organization_name' => $organization,
124 | 'reference' => $reference,
125 | 'attention' => $attention,
126 | 'given_name' => 'foo',
127 | 'family_name' => 'bar',
128 | 'email' => $email,
129 | 'title' => $title,
130 | 'street_address' => $streetAddress,
131 | 'street_address2' => $streetAddress2,
132 | 'street_name' => $streetName,
133 | 'street_number' => $streetNumber,
134 | 'house_extension' => $houseExtension,
135 | 'postal_code' => $postalCode,
136 | 'city' => $city,
137 | 'region' => $region,
138 | 'phone' => $phone,
139 | 'country' => $country,
140 | ];
141 | $billingAddress = [
142 | 'organization_name' => $organization,
143 | 'reference' => $reference,
144 | 'attention' => $attention,
145 | 'given_name' => 'bar',
146 | 'family_name' => 'foo',
147 | 'email' => $email,
148 | 'title' => $title,
149 | 'street_address' => $streetAddress,
150 | 'street_address2' => $streetAddress2,
151 | 'street_name' => $streetName,
152 | 'street_number' => $streetNumber,
153 | 'house_extension' => $houseExtension,
154 | 'postal_code' => $postalCode,
155 | 'city' => $city,
156 | 'region' => $region,
157 | 'phone' => $phone,
158 | 'country' => $country,
159 | ];
160 |
161 | $this->authorizeRequest->initialize(
162 | \array_merge(
163 | [
164 | 'currency' => 'EUR',
165 | 'locale' => 'nl_NL',
166 | 'amount' => '100.00',
167 | 'tax_amount' => 21,
168 | 'purchase_country' => 'DE',
169 | ],
170 | $this->getMinimalValidMerchantUrlData()
171 | )
172 | );
173 | $this->authorizeRequest->setItems([$this->getItemMock()]);
174 | $this->authorizeRequest->setBillingAddress($billingAddress);
175 | $this->authorizeRequest->setShippingAddress($shippingAddress);
176 |
177 | self::assertEquals(
178 | [
179 | 'locale' => 'nl-NL',
180 | 'order_amount' => 10000,
181 | 'order_tax_amount' => 2100,
182 | 'order_lines' => [$this->getExpectedOrderLine()],
183 | 'merchant_urls' => $this->getMinimalExpectedMerchantUrlData(),
184 | 'purchase_country' => 'DE',
185 | 'purchase_currency' => 'EUR',
186 | 'shipping_address' => $shippingAddress,
187 | 'billing_address' => $billingAddress,
188 | ],
189 | $this->authorizeRequest->getData()
190 | );
191 | }
192 |
193 | public function testGetDataWithCustomerWillReturnCorrectData()
194 | {
195 | $customer = [
196 | 'date_of_birth' => '1995-10-20',
197 | 'type' => 'organization',
198 | ];
199 |
200 | $this->authorizeRequest->initialize(
201 | \array_merge(
202 | [
203 | 'locale' => 'nl_NL',
204 | 'amount' => '100.00',
205 | 'tax_amount' => 21,
206 | 'currency' => 'EUR',
207 | 'purchase_country' => 'FR',
208 | ],
209 | $this->getCompleteValidMerchantUrlData()
210 | )
211 | );
212 | $this->authorizeRequest->setCustomer($customer);
213 | $this->authorizeRequest->setItems([$this->getItemMock()]);
214 |
215 | self::assertEquals(
216 | [
217 | 'locale' => 'nl-NL',
218 | 'order_amount' => 10000,
219 | 'order_tax_amount' => 2100,
220 | 'order_lines' => [$this->getExpectedOrderLine()],
221 | 'merchant_urls' => $this->getCompleteExpectedMerchantUrlData(),
222 | 'purchase_country' => 'FR',
223 | 'purchase_currency' => 'EUR',
224 | 'customer' => $customer,
225 | ],
226 | $this->authorizeRequest->getData()
227 | );
228 | }
229 |
230 | public function testGetDataWithOptionsWillReturnCorrectData()
231 | {
232 | $widgetOptions = [
233 | 'acquiring_channel' => 'foo',
234 | 'allow_separate_shipping_address' => true,
235 | 'color_button' => '#FFFFF',
236 | 'color_button_text' => '#FFFFF',
237 | 'color_checkbox' => '#FFFFF',
238 | 'color_checkbox_checkmark' => '#FFFFF',
239 | 'color_header' => '#FFFFF',
240 | 'color_link' => '#FFFFF',
241 | 'date_of_birth_mandatory' => true,
242 | 'shipping_details' => 'Delivered within 1-3 working days',
243 | 'title_mandatory' => true,
244 | 'additional_checkbox' => [
245 | 'text' => 'Please add me to the newsletter list',
246 | 'checked' => false,
247 | 'required' => false,
248 | ],
249 | 'radius_border' => '5px',
250 | 'show_subtotal_detail' => true,
251 | 'require_validate_callback_success' => true,
252 | 'allow_global_billing_countries' => false,
253 | ];
254 |
255 | $this->authorizeRequest->initialize(
256 | \array_merge(
257 | [
258 | 'locale' => 'nl_NL',
259 | 'amount' => '100.00',
260 | 'tax_amount' => 21,
261 | 'currency' => 'EUR',
262 | 'shipping_countries' => ['NL', 'DE'],
263 | 'purchase_country' => 'BE',
264 | ],
265 | $this->getMinimalValidMerchantUrlData()
266 | )
267 | );
268 | $this->authorizeRequest->setItems([$this->getItemMock()]);
269 | $this->authorizeRequest->setWidgetOptions($widgetOptions);
270 |
271 | self::assertEquals(
272 | [
273 | 'locale' => 'nl-NL',
274 | 'order_amount' => 10000,
275 | 'order_tax_amount' => 2100,
276 | 'order_lines' => [$this->getExpectedOrderLine()],
277 | 'merchant_urls' => $this->getMinimalExpectedMerchantUrlData(),
278 | 'purchase_country' => 'BE',
279 | 'purchase_currency' => 'EUR',
280 | 'options' => $widgetOptions,
281 | 'shipping_countries' => ['NL', 'DE'],
282 | ],
283 | $this->authorizeRequest->getData()
284 | );
285 | }
286 |
287 | public function testSendDataWillCreateOrderAndReturnResponse()
288 | {
289 | $inputData = ['request-data' => 'yey?'];
290 | $expectedData = ['response-data' => 'yey!'];
291 |
292 | $response = $this->setExpectedPostRequest($inputData, $expectedData, self::BASE_URL . '/checkout/v3/orders');
293 |
294 | $response->expects(self::once())->method('getStatusCode')->willReturn(200);
295 |
296 | $this->authorizeRequest->initialize(
297 | [
298 | 'base_url' => self::BASE_URL,
299 | 'username' => self::USERNAME,
300 | 'secret' => self::SECRET,
301 | ]
302 | );
303 | $this->authorizeRequest->setRenderUrl('localhost/render');
304 |
305 | $authorizeResponse = $this->authorizeRequest->sendData($inputData);
306 |
307 | self::assertInstanceOf(AuthorizeResponse::class, $authorizeResponse);
308 | self::assertSame($expectedData, $authorizeResponse->getData());
309 | self::assertEquals('localhost/render', $authorizeResponse->getRedirectUrl());
310 | }
311 |
312 | public function testSendDataWillFetchOrderAndReturnResponseIfTransactionIdAlreadySet()
313 | {
314 | $inputData = ['request-data' => 'yey?'];
315 | $expectedData = ['response-data' => 'yey!'];
316 |
317 | $response = $this->setExpectedGetRequest(
318 | $expectedData,
319 | self::BASE_URL . '/checkout/v3/orders/f60e69e8-464a-48c0-a452-6fd562540f37'
320 | );
321 |
322 | $response->expects(self::once())->method('getStatusCode')->willReturn(200);
323 |
324 | $this->authorizeRequest->initialize(
325 | [
326 | 'render_url' => 'foobar',
327 | 'base_url' => self::BASE_URL,
328 | 'username' => self::USERNAME,
329 | 'secret' => self::SECRET,
330 | 'transactionReference' => 'f60e69e8-464a-48c0-a452-6fd562540f37',
331 | ]
332 | );
333 |
334 | $response = $this->authorizeRequest->sendData($inputData);
335 |
336 | self::assertInstanceOf(AuthorizeResponse::class, $response);
337 | self::assertSame($expectedData, $response->getData());
338 | }
339 |
340 | public function testSendDataWillRaiseExceptionOnErrorResponses()
341 | {
342 | $response = $this->createMock(ResponseInterface::class);
343 | $this->httpClient->expects(self::once())->method('request')->willReturn($response);
344 |
345 | $response->expects(self::once())->method('getStatusCode')->willReturn(401);
346 |
347 | $responseMessage = 'FooBar';
348 | $response->expects(self::once())->method('getReasonPhrase')->willReturn($responseMessage);
349 |
350 | $this->expectException(InvalidResponseException::class);
351 | $this->expectExceptionMessage($responseMessage);
352 |
353 | $this->authorizeRequest->sendData([]);
354 | }
355 | }
356 |
--------------------------------------------------------------------------------
/tests/Message/AuthorizeResponseTest.php:
--------------------------------------------------------------------------------
1 | createMock(RequestInterface::class);
15 |
16 | $response = new AuthorizeResponse($request, []);
17 |
18 | self::assertFalse($response->isSuccessful());
19 | }
20 |
21 | public function testResponseIsNonRedirectWithoutRenderUrl()
22 | {
23 | $response = new AuthorizeResponse($this->getMockRequest(), [], null);
24 |
25 | self::assertFalse($response->isRedirect());
26 | }
27 |
28 | public function testResponseIsRedirectWithRenderUrl()
29 | {
30 | $request = $this->createMock(RequestInterface::class);
31 | $response = new AuthorizeResponse($request, [], 'localhost/return');
32 |
33 | self::assertNull($response->getRedirectData());
34 | self::assertEquals('GET', $response->getRedirectMethod());
35 | self::assertEquals('localhost/return', $response->getRedirectUrl());
36 | self::assertTrue($response->isRedirect());
37 | }
38 | }
39 |
--------------------------------------------------------------------------------
/tests/Message/CaptureRequestTest.php:
--------------------------------------------------------------------------------
1 | captureRequest = new CaptureRequest($this->httpClient, $this->getHttpRequest());
23 | }
24 |
25 | /**
26 | * @return array
27 | */
28 | public function invalidRequestDataProvider(): array
29 | {
30 | return [
31 | [['transactionReference' => self::TRANSACTION_REF]],
32 | [['amount' => '10.00']],
33 | ];
34 | }
35 |
36 | /**
37 | * @dataProvider validRequestDataProvider
38 | *
39 | * @param array|null $items
40 | * @param array $expectedItemData
41 | */
42 | public function testGetDataWillReturnCorrectData($items, array $expectedItemData)
43 | {
44 | $this->captureRequest->initialize(
45 | [
46 | 'transactionReference' => self::TRANSACTION_REF,
47 | 'amount' => '100',
48 | 'currency' => 'USD',
49 | ]
50 | );
51 | $this->captureRequest->setItems($items);
52 |
53 | /** @noinspection PhpUnhandledExceptionInspection */
54 | self::assertEquals(
55 | ['captured_amount' => 10000] + $expectedItemData,
56 | $this->captureRequest->getData()
57 | );
58 | }
59 |
60 | /**
61 | * @dataProvider invalidRequestDataProvider
62 | *
63 | * @param array $requestData
64 | */
65 | public function testGetDataWillThrowExceptionForInvalidRequest(array $requestData)
66 | {
67 | $this->captureRequest->initialize($requestData);
68 |
69 | $this->expectException(InvalidRequestException::class);
70 |
71 | /** @noinspection PhpUnhandledExceptionInspection */
72 | $this->captureRequest->getData();
73 | }
74 |
75 | public function testSendDataWillCreateCaptureAndReturnResponseWithCaptureData()
76 | {
77 | $requestdata = ['request-data' => 'yey?'];
78 | $responseData = ['response-data' => 'yey!'];
79 |
80 | $response = $this->setExpectedPostRequest(
81 | $requestdata,
82 | $responseData,
83 | self::BASE_URL . '/ordermanagement/v1/orders/' . self::TRANSACTION_REF . '/captures'
84 | );
85 | $response->expects(self::once())->method('getStatusCode')->willReturn(204);
86 |
87 | $this->captureRequest->initialize(
88 | [
89 | 'base_url' => self::BASE_URL,
90 | 'username' => self::USERNAME,
91 | 'secret' => self::SECRET,
92 | 'transactionReference' => self::TRANSACTION_REF,
93 | ]
94 | );
95 |
96 | $captureResponse = $this->captureRequest->sendData($requestdata);
97 |
98 | self::assertInstanceOf(CaptureResponse::class, $captureResponse);
99 | self::assertSame($responseData, $captureResponse->getData());
100 | }
101 |
102 | /**
103 | * @return array
104 | */
105 | public function validRequestDataProvider(): array
106 | {
107 | return [
108 | [null, []], // No item data should return result without order_line entry
109 | [[$this->getItemMock()], ['order_lines' => [$this->getExpectedOrderLine()]]],
110 | ];
111 | }
112 | }
113 |
--------------------------------------------------------------------------------
/tests/Message/CaptureResponseTest.php:
--------------------------------------------------------------------------------
1 | createMock(RequestInterface::class);
27 |
28 | $response = new CaptureResponse($request, [], 'foo', 201);
29 |
30 | self::assertSame('foo', $response->getTransactionReference());
31 | self::assertSame(201, $response->getStatusCode());
32 | }
33 |
34 | /**
35 | * @dataProvider responseCodeProvider
36 | *
37 | * @param string $responseCode
38 | * @param bool $expectedResult
39 | */
40 | public function testIsSuccessfulWillReturnCorrectStateWithResponseCode($responseCode, $expectedResult)
41 | {
42 | $request = $this->createMock(RequestInterface::class);
43 |
44 | $captureResponse = new CaptureResponse($request, [], '123', $responseCode);
45 |
46 | self::assertEquals($expectedResult, $captureResponse->isSuccessful());
47 | }
48 | }
49 |
--------------------------------------------------------------------------------
/tests/Message/CustomerTest.php:
--------------------------------------------------------------------------------
1 | '1995-10-20',
20 | 'type' => 'organization',
21 | ],
22 | [
23 | 'date_of_birth' => '1995-10-20',
24 | 'type' => 'organization',
25 | ],
26 | ],
27 | [
28 | [],
29 | [
30 | 'date_of_birth' => null,
31 | 'type' => 'person',
32 | ],
33 | ],
34 | [
35 | ['foo' => 'bar'],
36 | [
37 | 'date_of_birth' => null,
38 | 'type' => 'person',
39 | ],
40 | ],
41 | ];
42 | }
43 |
44 | /**
45 | * @dataProvider dataProvider
46 | *
47 | * @param array $data
48 | * @param array $expectedOutcome
49 | */
50 | public function testFromArrayShoulReturnArrayWithCorrectKeys($data, $expectedOutcome)
51 | {
52 | self::assertEquals($expectedOutcome, Customer::fromArray($data)->getArrayCopy());
53 | }
54 | }
55 |
--------------------------------------------------------------------------------
/tests/Message/ExtendAuthorizationRequestTest.php:
--------------------------------------------------------------------------------
1 | extendAuthorizationRequest = new ExtendAuthorizationRequest($this->httpClient, $this->getHttpRequest());
20 | }
21 |
22 | public function testGetDataThrowsExceptionWhenMissingTransactionReference()
23 | {
24 | $this->expectException(InvalidRequestException::class);
25 |
26 | $this->extendAuthorizationRequest->initialize([]);
27 | $this->extendAuthorizationRequest->getData();
28 | }
29 |
30 | public function testGetDataWithInvalidDataWillReturnNull()
31 | {
32 | $this->extendAuthorizationRequest->initialize(['transactionReference' => 'foo']);
33 |
34 | self::assertNull($this->extendAuthorizationRequest->getData());
35 | }
36 |
37 | public function testSendDataWillWillSendDataToKlarnaEndPointAndReturnCorrectResponse()
38 | {
39 | $response = $this->createMock(ResponseInterface::class);
40 | $stream = $this->createMock(StreamInterface::class);
41 |
42 | $this->httpClient->expects(self::once())
43 | ->method('request')
44 | ->with(
45 | 'POST',
46 | \sprintf(
47 | '%s/ordermanagement/v1/orders/%s/extend-authorization-time',
48 | self::BASE_URL,
49 | 'foo'
50 | ),
51 | \array_merge(
52 | ['Content-Type' => 'application/json'],
53 | [
54 | 'Authorization' => \sprintf(
55 | 'Basic %s',
56 | \base64_encode(
57 | \sprintf(
58 | '%s:%s',
59 | null,
60 | self::SECRET
61 | )
62 | )
63 | ),
64 | ]
65 | ),
66 | \json_encode([])
67 | )
68 | ->willReturn($response);
69 |
70 | $response->method('getBody')->willReturn($stream);
71 | $stream->method('getContents')->willReturn(\json_encode(['hello' => 'world']));
72 |
73 | $this->extendAuthorizationRequest->initialize(
74 | [
75 | 'base_url' => self::BASE_URL,
76 | 'secret' => self::SECRET,
77 | 'transactionReference' => 'foo',
78 | ]
79 | );
80 |
81 | $extendAuthorizationResponse = $this->extendAuthorizationRequest->sendData([]);
82 |
83 | self::assertSame('foo', $extendAuthorizationResponse->getTransactionReference());
84 | self::assertSame(
85 | [
86 | 'hello' => 'world',
87 | 'order_id' => 'foo',
88 | ],
89 | $extendAuthorizationResponse->getData()
90 | );
91 | }
92 | }
93 |
--------------------------------------------------------------------------------
/tests/Message/ExtendAuthorizationResponseTest.php:
--------------------------------------------------------------------------------
1 | 'oh_noes'], false],
19 | [[], true],
20 | ];
21 | }
22 |
23 | public function testGetters()
24 | {
25 | $request = $this->createMock(RequestInterface::class);
26 |
27 | $responseData = ['order_id' => 'foo'];
28 | $response = new ExtendAuthorizationResponse($request, $responseData);
29 |
30 | self::assertSame('foo', $response->getTransactionReference());
31 | }
32 |
33 | /**
34 | * @dataProvider responseDataProvider
35 | *
36 | * @param array $responseData
37 | * @param bool $expected
38 | */
39 | public function testIsSuccessfulWillReturnWhetherResponseIsSuccessfull($responseData, $expected)
40 | {
41 | $request = $this->createMock(RequestInterface::class);
42 | $response = new ExtendAuthorizationResponse($request, $responseData);
43 |
44 | self::assertEquals($expected, $response->isSuccessful());
45 | }
46 | }
47 |
--------------------------------------------------------------------------------
/tests/Message/FetchTransactionRequestTest.php:
--------------------------------------------------------------------------------
1 | fetchTransactionRequest = new FetchTransactionRequest($this->httpClient, $this->getHttpRequest());
24 | }
25 |
26 | public function testGetDataReturnsNull()
27 | {
28 | $this->fetchTransactionRequest->initialize(['transactionReference' => 'foo']);
29 |
30 | self::assertNull($this->fetchTransactionRequest->getData());
31 | }
32 |
33 | public function testGetDataThrowsExceptionWhenMissingTransactionReference()
34 | {
35 | $this->expectException(InvalidRequestException::class);
36 |
37 | $this->fetchTransactionRequest->initialize([]);
38 | $this->fetchTransactionRequest->getData();
39 | }
40 |
41 | public function testSendDataWillReturnResponseFromCheckoutApiForIncompleteOrder()
42 | {
43 | $expectedCheckoutData = ['status' => 'checkout_incomplete'];
44 |
45 | $response = $this->setExpectedGetRequest(
46 | $expectedCheckoutData,
47 | self::BASE_URL . '/checkout/v3/orders/foo'
48 | );
49 | $response->expects(self::once())->method('getStatusCode')->willReturn(200);
50 |
51 | $this->fetchTransactionRequest->initialize(
52 | [
53 | 'base_url' => self::BASE_URL,
54 | 'username' => self::USERNAME,
55 | 'secret' => self::SECRET,
56 | 'transactionReference' => 'foo',
57 | ]
58 | );
59 |
60 | $fetchResponse = $this->fetchTransactionRequest->sendData([]);
61 |
62 | self::assertInstanceOf(FetchTransactionResponse::class, $fetchResponse);
63 | self::assertSame(['checkout' => $expectedCheckoutData], $fetchResponse->getData());
64 | }
65 |
66 | public function testSendDataWillReturnResponseFromCheckoutApiForUnknownOrder()
67 | {
68 | $expectedCheckoutData = ['response-data' => 'nay!'];
69 |
70 | $response = $this->setExpectedGetRequest(
71 | $expectedCheckoutData,
72 | self::BASE_URL . '/checkout/v3/orders/foo'
73 | );
74 | $response->expects(self::once())->method('getStatusCode')->willReturn(200);
75 |
76 | $this->fetchTransactionRequest->initialize(
77 | [
78 | 'base_url' => self::BASE_URL,
79 | 'username' => self::USERNAME,
80 | 'secret' => self::SECRET,
81 | 'transactionReference' => 'foo',
82 | ]
83 | );
84 |
85 | $fetchResponse = $this->fetchTransactionRequest->sendData([]);
86 |
87 | self::assertInstanceOf(FetchTransactionResponse::class, $fetchResponse);
88 | self::assertSame(['checkout' => $expectedCheckoutData], $fetchResponse->getData());
89 | }
90 |
91 | public function testSendDataWillReturnResponseFromManagementApiForCompleteOrder()
92 | {
93 | $expectedCheckoutData = ['status' => 'checkout_complete'];
94 | $expectedManagementData = ['response-data' => 'yay!'];
95 | $response = $this->createMock(ResponseInterface::class);
96 | $stream = $this->createMock(StreamInterface::class);
97 |
98 | $this->httpClient->expects(self::exactly(2))
99 | ->method('request')
100 | ->withConsecutive(
101 | [
102 | 'GET',
103 | self::BASE_URL . '/checkout/v3/orders/foo',
104 | $this->getExpectedHeaders(),
105 | null,
106 | ],
107 | [
108 | 'GET',
109 | self::BASE_URL . '/ordermanagement/v1/orders/foo',
110 | $this->getExpectedHeaders(),
111 | null,
112 | ]
113 | )->willReturn($response);
114 |
115 | $response->method('getBody')->willReturn($stream);
116 | $stream->expects(self::exactly(2))
117 | ->method('getContents')
118 | ->willReturnOnConsecutiveCalls(
119 | \json_encode($expectedCheckoutData),
120 | \json_encode($expectedManagementData)
121 | );
122 |
123 | $this->fetchTransactionRequest->initialize(
124 | [
125 | 'base_url' => self::BASE_URL,
126 | 'username' => self::USERNAME,
127 | 'secret' => self::SECRET,
128 | 'transactionReference' => 'foo',
129 | ]
130 | );
131 |
132 | $fetchResponse = $this->fetchTransactionRequest->sendData([]);
133 |
134 | self::assertInstanceOf(FetchTransactionResponse::class, $fetchResponse);
135 | self::assertSame(
136 | ['checkout' => $expectedCheckoutData, 'management' => $expectedManagementData],
137 | $fetchResponse->getData()
138 | );
139 | }
140 |
141 | public function testSendDataWillReturnResponseFromManagementApiForDeletedCheckoutOrder()
142 | {
143 | $expectedCheckoutData = [];
144 | $expectedManagementData = ['response-data' => 'yay!'];
145 | $response = $this->createMock(ResponseInterface::class);
146 | $stream = $this->createMock(StreamInterface::class);
147 |
148 | $this->httpClient->expects(self::exactly(2))
149 | ->method('request')
150 | ->withConsecutive(
151 | [
152 | 'GET',
153 | self::BASE_URL . '/checkout/v3/orders/foo',
154 | $this->getExpectedHeaders(),
155 | null,
156 | ],
157 | [
158 | 'GET',
159 | self::BASE_URL . '/ordermanagement/v1/orders/foo',
160 | $this->getExpectedHeaders(),
161 | null,
162 | ]
163 | )->willReturn($response);
164 |
165 | $response->method('getBody')->willReturn($stream);
166 | $stream->expects(self::exactly(2))
167 | ->method('getContents')
168 | ->willReturnOnConsecutiveCalls(
169 | \json_encode($expectedCheckoutData),
170 | \json_encode($expectedManagementData)
171 | );
172 |
173 | $response->expects(self::once())->method('getStatusCode')->willReturn(404);
174 |
175 | $this->fetchTransactionRequest->initialize(
176 | [
177 | 'base_url' => self::BASE_URL,
178 | 'username' => self::USERNAME,
179 | 'secret' => self::SECRET,
180 | 'transactionReference' => 'foo',
181 | ]
182 | );
183 |
184 | $fetchResponse = $this->fetchTransactionRequest->sendData([]);
185 |
186 | self::assertInstanceOf(FetchTransactionResponse::class, $fetchResponse);
187 | self::assertSame(
188 | ['checkout' => $expectedCheckoutData, 'management' => $expectedManagementData],
189 | $fetchResponse->getData()
190 | );
191 | }
192 | }
193 |
--------------------------------------------------------------------------------
/tests/Message/FetchTransactionResponseTest.php:
--------------------------------------------------------------------------------
1 | ['error_code' => 'oh_noes']], false],
19 | [[], false],
20 | [['checkout' => ['status' => 'all_is_well']], true],
21 | [['management' => ['error_code' => 'oh_noes']], false],
22 | [['management' => ['status' => 'all_is_well']], true],
23 | ];
24 | }
25 |
26 | public function testGetTransactionReferenceForCheckoutTransaction()
27 | {
28 | $request = $this->createMock(RequestInterface::class);
29 |
30 | $responseData = ['checkout' => ['order_id' => 'foo']];
31 | $response = new FetchTransactionResponse($request, $responseData);
32 |
33 | self::assertSame($responseData['checkout']['order_id'], $response->getTransactionReference());
34 | }
35 |
36 | public function testGetTransactionReferenceForManagementTransaction()
37 | {
38 | $request = $this->createMock(RequestInterface::class);
39 |
40 | $responseData = ['management' => ['order_id' => 'foo']];
41 | $response = new FetchTransactionResponse($request, $responseData);
42 |
43 | self::assertSame($responseData['management']['order_id'], $response->getTransactionReference());
44 | }
45 |
46 | /**
47 | * @dataProvider responseDataProvider
48 | *
49 | * @param array $responseData
50 | * @param bool $expected
51 | */
52 | public function testIsSuccessfulWillReturnWhetherResponseIsSuccessfull($responseData, $expected)
53 | {
54 | $request = $this->createMock(RequestInterface::class);
55 |
56 | $response = new FetchTransactionResponse($request, $responseData);
57 |
58 | self::assertEquals($expected, $response->isSuccessful());
59 | }
60 | }
61 |
--------------------------------------------------------------------------------
/tests/Message/ItemDataTestTrait.php:
--------------------------------------------------------------------------------
1 | 'shipping_fee',
15 | 'name' => 'item-name',
16 | 'quantity' => 1,
17 | 'tax_rate' => 2003,
18 | 'total_amount' => 10000,
19 | 'total_tax_amount' => 20000,
20 | 'total_discount_amount' => 0,
21 | 'unit_price' => 10000,
22 | 'merchant_data' => 'foobar',
23 | ];
24 | }
25 |
26 | protected function getItemMock(): MockObject
27 | {
28 | $item = $this->createMock(ItemInterface::class);
29 | $item->method('getType')->willReturn('shipping_fee');
30 | $item->method('getName')->willReturn('item-name');
31 | $item->method('getQuantity')->willReturn(1);
32 | $item->method('getTaxRate')->willReturn(20.03);
33 | $item->method('getQuantity')->willReturn(1);
34 | $item->method('getPrice')->willReturn(100);
35 | $item->method('getTotalAmount')->willReturn(100);
36 | $item->method('getTotalTaxAmount')->willReturn(200);
37 | $item->method('getTotalDiscountAmount')->willReturn(0);
38 | $item->method('getMerchantData')->willReturn('foobar');
39 |
40 | return $item;
41 | }
42 | }
43 |
--------------------------------------------------------------------------------
/tests/Message/MerchantUrlsDataTestTrait.php:
--------------------------------------------------------------------------------
1 | 'localhost/address-update',
15 | 'cancellation_terms' => 'localhost/cancellation-terms',
16 | 'checkout' => 'localhost/return',
17 | 'confirmation' => 'localhost/confirm',
18 | 'push' => 'localhost/notify',
19 | 'terms' => 'localhost/terms',
20 | 'validation' => 'localhost/validate',
21 | ];
22 | }
23 |
24 | /**
25 | * @return array
26 | */
27 | public function getCompleteValidMerchantUrlData(): array
28 | {
29 | return [
30 | 'addressUpdateUrl' => 'localhost/address-update',
31 | 'cancellationTermsUrl' => 'localhost/cancellation-terms',
32 | 'returnUrl' => 'localhost/return',
33 | 'confirmationUrl' => 'localhost/confirm',
34 | 'notifyUrl' => 'localhost/notify',
35 | 'termsUrl' => 'localhost/terms',
36 | 'validationUrl' => 'localhost/validate',
37 | ];
38 | }
39 |
40 | /**
41 | * @return array
42 | */
43 | public function getMinimalExpectedMerchantUrlData(): array
44 | {
45 | return [
46 | 'checkout' => 'localhost/return',
47 | 'confirmation' => 'localhost/return',
48 | 'push' => 'localhost/notify',
49 | 'terms' => 'localhost/terms',
50 | 'validation' => 'localhost/validate',
51 | ];
52 | }
53 |
54 | /**
55 | * @return array
56 | */
57 | public function getMinimalValidMerchantUrlData(): array
58 | {
59 | return [
60 | 'returnUrl' => 'localhost/return',
61 | 'notifyUrl' => 'localhost/notify',
62 | 'termsUrl' => 'localhost/terms',
63 | 'validationUrl' => 'localhost/validate',
64 | ];
65 | }
66 | }
67 |
--------------------------------------------------------------------------------
/tests/Message/RefundRequestTest.php:
--------------------------------------------------------------------------------
1 | refundRequest = new RefundRequest($this->httpClient, $this->getHttpRequest());
21 | }
22 |
23 | /**
24 | * @return array
25 | */
26 | public function invalidRequestDataProvider(): array
27 | {
28 | return [
29 | [['transactionReference' => 'foo']],
30 | [['amount' => '10.00']],
31 | ];
32 | }
33 |
34 | /**
35 | * @dataProvider validRequestDataProvider
36 | *
37 | * @param array|null $items
38 | * @param array $expectedItemData
39 | */
40 | public function testGetDataWillReturnCorrectData($items, array $expectedItemData)
41 | {
42 | $this->refundRequest->initialize(['transactionReference' => 'foo', 'amount' => '10.00', 'currency' => 'USD']);
43 | $this->refundRequest->setItems($items);
44 |
45 | /** @noinspection PhpUnhandledExceptionInspection */
46 | self::assertEquals(
47 | ['refunded_amount' => 1000] + $expectedItemData,
48 | $this->refundRequest->getData()
49 | );
50 | }
51 |
52 | /**
53 | * @dataProvider invalidRequestDataProvider
54 | *
55 | * @param array $requestData
56 | */
57 | public function testGetDataWillThrowExceptionForInvalidRequest(array $requestData)
58 | {
59 | $this->refundRequest->initialize($requestData);
60 |
61 | $this->expectException(InvalidRequestException::class);
62 |
63 | /** @noinspection PhpUnhandledExceptionInspection */
64 | $this->refundRequest->getData();
65 | }
66 |
67 | public function testSendDataWillCreateRefundAndReturnResponse()
68 | {
69 | $inputData = ['request-data' => 'yey?'];
70 | $expectedData = [];
71 |
72 | $response = $this->setExpectedPostRequest(
73 | $inputData,
74 | $expectedData,
75 | self::BASE_URL . '/ordermanagement/v1/orders/foo/refunds'
76 | );
77 |
78 | $response->expects(self::once())->method('getStatusCode')->willReturn(204);
79 |
80 | $this->refundRequest->initialize(
81 | [
82 | 'base_url' => self::BASE_URL,
83 | 'username' => self::USERNAME,
84 | 'secret' => self::SECRET,
85 | 'transactionReference' => 'foo',
86 | ]
87 | );
88 |
89 | $refundResponse = $this->refundRequest->sendData($inputData);
90 |
91 | self::assertInstanceOf(RefundResponse::class, $refundResponse);
92 | self::assertSame($expectedData, $refundResponse->getData());
93 | }
94 |
95 | /**
96 | * @return array
97 | */
98 | public function validRequestDataProvider(): array
99 | {
100 | return [
101 | [null, []], // No item data should return result without order_line entry
102 | [[$this->getItemMock()], ['order_lines' => [$this->getExpectedOrderLine()]]],
103 | ];
104 | }
105 | }
106 |
--------------------------------------------------------------------------------
/tests/Message/RefundResponseTest.php:
--------------------------------------------------------------------------------
1 | createMock(RequestInterface::class);
27 |
28 | $response = new RefundResponse($request, [], 201);
29 |
30 | self::assertSame(201, $response->getStatusCode());
31 | }
32 |
33 | /**
34 | * @dataProvider responseCodeProvider
35 | *
36 | * @param string $responseCode
37 | * @param bool $expectedResult
38 | */
39 | public function testIsSuccessfulWillReturnCorrectStateWithResponseCode($responseCode, $expectedResult)
40 | {
41 | $request = $this->createMock(RequestInterface::class);
42 |
43 | $captureResponse = new RefundResponse($request, [], $responseCode);
44 |
45 | self::assertEquals($expectedResult, $captureResponse->isSuccessful());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Message/RequestTestCase.php:
--------------------------------------------------------------------------------
1 | httpClient = $this->createMock(ClientInterface::class);
27 | }
28 |
29 | /**
30 | * @param array $responseData
31 | * @param string $url
32 | *
33 | * @return ResponseInterface|MockObject
34 | */
35 | protected function setExpectedGetRequest(array $responseData, $url)
36 | {
37 | return $this->setExpectedRequest('GET', $url, [], null, $responseData);
38 | }
39 |
40 | /**
41 | * @param array $inputData
42 | * @param array $responseData
43 | * @param string $url
44 | *
45 | * @return ResponseInterface|MockObject
46 | */
47 | protected function setExpectedPatchRequest(array $inputData, array $responseData, $url)
48 | {
49 | return $this->setExpectedRequest(
50 | 'PATCH',
51 | $url,
52 | ['Content-Type' => 'application/json'],
53 | $inputData,
54 | $responseData
55 | );
56 | }
57 |
58 | /**
59 | * @param array $inputData
60 | * @param array $responseData
61 | * @param string $url
62 | *
63 | * @return ResponseInterface|MockObject
64 | */
65 | protected function setExpectedPostRequest(array $inputData, array $responseData, $url)
66 | {
67 | return $this->setExpectedRequest(
68 | 'POST',
69 | $url,
70 | ['Content-Type' => 'application/json'],
71 | $inputData,
72 | $responseData
73 | );
74 | }
75 |
76 | /**
77 | * @param string $requestMethod
78 | * @param string $url
79 | * @param array $headers
80 | * @param array $inputData
81 | * @param array $responseData
82 | *
83 | * @return ResponseInterface|MockObject
84 | */
85 | private function setExpectedRequest(
86 | $requestMethod,
87 | $url,
88 | array $headers,
89 | ?array $inputData = null,
90 | array $responseData
91 | ) {
92 | $response = $this->createMock(ResponseInterface::class);
93 | $stream = $this->createMock(StreamInterface::class);
94 |
95 | $this->httpClient->expects(self::once())
96 | ->method('request')
97 | ->with(
98 | $requestMethod,
99 | $url,
100 | \array_merge(
101 | $headers,
102 | $this->getExpectedHeaders()
103 | ),
104 | null === $inputData ? null : \json_encode($inputData)
105 | )
106 | ->willReturn($response);
107 |
108 | $response->method('getBody')->willReturn($stream);
109 | $stream->method('getContents')->willReturn(\json_encode($responseData));
110 |
111 | return $response;
112 | }
113 | }
114 |
--------------------------------------------------------------------------------
/tests/Message/UpdateCustomerAddressRequestTest.php:
--------------------------------------------------------------------------------
1 | updateCustomerAddressRequest = new UpdateCustomerAddressRequest(
20 | $this->httpClient,
21 | $this->getHttpRequest()
22 | );
23 | }
24 |
25 | /**
26 | * @return array
27 | */
28 | public function addressDataProvider(): array
29 | {
30 | return [
31 | [
32 | [
33 | 'organization_name' => null,
34 | 'reference' => 'ref',
35 | 'attention' => 'quz',
36 | 'given_name' => 'foo',
37 | 'family_name' => 'bar',
38 | 'email' => 'foo@bar.com',
39 | 'title' => 'Mr.',
40 | 'street_address' => 'Foo Street 1',
41 | 'street_address2' => 'App. 12A',
42 | 'street_name' => 'Foo Street',
43 | 'street_number' => '1',
44 | 'house_extension' => 'C',
45 | 'postal_code' => '523354',
46 | 'city' => 'Oss',
47 | 'region' => 'NB',
48 | 'phone' => '24234234',
49 | 'country' => 'NL',
50 | ],
51 | [
52 | 'organization_name' => null,
53 | 'reference' => 'ref',
54 | 'attention' => 'quz',
55 | 'given_name' => 'foo',
56 | 'family_name' => 'bar',
57 | 'email' => 'foo@bar.com',
58 | 'title' => 'Mr.',
59 | 'street_address' => 'Foo Street 1',
60 | 'street_address2' => 'App. 12A',
61 | 'street_name' => 'Foo Street',
62 | 'street_number' => '1',
63 | 'house_extension' => 'C',
64 | 'postal_code' => '523354',
65 | 'city' => 'Oss',
66 | 'region' => 'NB',
67 | 'phone' => '24234234',
68 | 'country' => 'NL',
69 | ],
70 | ],
71 | [
72 | [
73 | 'organization_name' => 'Foobar BV',
74 | 'reference' => 'ref',
75 | 'attention' => 'quz',
76 | 'given_name' => 'foo',
77 | 'family_name' => 'bar',
78 | 'email' => 'foo@bar.com',
79 | 'title' => 'Mr.',
80 | 'street_address' => 'Foo Street 1',
81 | 'street_address2' => 'App. 12A',
82 | 'street_name' => 'Foo Street',
83 | 'street_number' => '1',
84 | 'house_extension' => 'C',
85 | 'postal_code' => '523354',
86 | 'city' => 'Oss',
87 | 'region' => 'NB',
88 | 'phone' => '24234234',
89 | 'country' => 'NL',
90 | ],
91 | [
92 | 'organization_name' => 'Foobar BV',
93 | 'reference' => 'ref',
94 | 'attention' => 'quz',
95 | 'given_name' => 'foo',
96 | 'family_name' => 'bar',
97 | 'email' => 'foo@bar.com',
98 | 'title' => 'Mr.',
99 | 'street_address' => 'Foo Street 1',
100 | 'street_address2' => 'App. 12A',
101 | 'street_name' => 'Foo Street',
102 | 'street_number' => '1',
103 | 'house_extension' => 'C',
104 | 'postal_code' => '523354',
105 | 'city' => 'Oss',
106 | 'region' => 'NB',
107 | 'phone' => '24234234',
108 | 'country' => 'NL',
109 | ],
110 | ],
111 | ];
112 | }
113 |
114 | /**
115 | * @dataProvider addressDataProvider
116 | *
117 | * @param array $addressData
118 | * @param array $expectedOutcome
119 | */
120 | public function testGetDataWillReturnCorrectData(array $addressData, array $expectedOutcome)
121 | {
122 | $this->updateCustomerAddressRequest->initialize(
123 | [
124 | 'transactionReference' => 123,
125 | 'billing_address' => $addressData,
126 | 'shipping_address' => $addressData,
127 | ]
128 | );
129 |
130 | /** @noinspection PhpUnhandledExceptionInspection */
131 | self::assertEquals(
132 | [
133 | 'shipping_address' => $expectedOutcome,
134 | 'billing_address' => $expectedOutcome,
135 | ],
136 | $this->updateCustomerAddressRequest->getData()
137 | );
138 | }
139 |
140 | public function testGetDataWillThrowExceptionOnMissingData()
141 | {
142 | $this->expectException(InvalidRequestException::class);
143 |
144 | $this->updateCustomerAddressRequest->getData();
145 | }
146 |
147 | public function testSendDataWillWillSendDataToKlarnaEndPointAndReturnCorrectResponse()
148 | {
149 | $transactionReference = 'foo';
150 | $data = ['foo' => 'bar'];
151 | $responseData = ['hello' => 'world'];
152 |
153 | $response = $this->setExpectedPatchRequest(
154 | $data,
155 | $responseData,
156 | \sprintf('%s/ordermanagement/v1/orders/%s/customer-details', self::BASE_URL, $transactionReference)
157 | );
158 |
159 | $response->expects(self::once())->method('getStatusCode')->willReturn(204);
160 |
161 | $this->updateCustomerAddressRequest->initialize(
162 | [
163 | 'base_url' => self::BASE_URL,
164 | 'secret' => self::SECRET,
165 | 'username' => self::USERNAME,
166 | 'transactionReference' => $transactionReference,
167 | ]
168 | );
169 |
170 | $updateCustomerAddressResponse = $this->updateCustomerAddressRequest->sendData($data);
171 |
172 | self::assertInstanceOf(UpdateCustomerAddressResponse::class, $updateCustomerAddressResponse);
173 | self::assertSame($transactionReference, $updateCustomerAddressResponse->getTransactionReference());
174 | self::assertSame(
175 | \array_merge($responseData, ['order_id' => $transactionReference]),
176 | $updateCustomerAddressResponse->getData()
177 | );
178 | self::assertTrue($updateCustomerAddressResponse->isSuccessful());
179 | }
180 | }
181 |
--------------------------------------------------------------------------------
/tests/Message/UpdateCustomerAddressResponseTest.php:
--------------------------------------------------------------------------------
1 | 'oh_noes'], false, 403],
19 | [[], false, 200],
20 | [[], true, 204],
21 | ];
22 | }
23 |
24 | public function testGetters()
25 | {
26 | $request = $this->createMock(RequestInterface::class);
27 |
28 | $responseData = ['order_id' => 'foo'];
29 | $response = new UpdateCustomerAddressResponse($request, $responseData, '403');
30 |
31 | self::assertSame('foo', $response->getTransactionReference());
32 | }
33 |
34 | /**
35 | * @dataProvider responseDataProvider
36 | *
37 | * @param array $responseData
38 | * @param bool $expected
39 | * @param int $reponseCode
40 | */
41 | public function testIsSuccessfulWillReturnWhetherResponseIsSuccessfull($responseData, $expected, $reponseCode)
42 | {
43 | $request = $this->createMock(RequestInterface::class);
44 |
45 | $response = new UpdateCustomerAddressResponse($request, $responseData, $reponseCode);
46 |
47 | self::assertEquals($expected, $response->isSuccessful());
48 | }
49 | }
50 |
--------------------------------------------------------------------------------
/tests/Message/UpdateMerchantReferencesRequestTest.php:
--------------------------------------------------------------------------------
1 | updateTransactionRequest = new UpdateMerchantReferencesRequest(
23 | $this->httpClient,
24 | $this->getHttpRequest()
25 | );
26 | }
27 |
28 | public function testGetDataWillReturnCorrectData()
29 | {
30 | $this->updateTransactionRequest->initialize(
31 | [
32 | 'merchant_reference1' => '12345',
33 | 'merchant_reference2' => 678,
34 | 'transactionReference' => self::TRANSACTION_REFERENCE,
35 | ]
36 | );
37 |
38 | self::assertEquals(
39 | ['merchant_reference1' => '12345', 'merchant_reference2' => 678],
40 | $this->updateTransactionRequest->getData()
41 | );
42 | }
43 |
44 | public function testSendDataWillUpdateManagementCustomerDetailsAndFailUpdatingMerchantReferences()
45 | {
46 | $inputData = ['merchant_reference1' => 'foo'];
47 |
48 | $response = $this->createMock(ResponseInterface::class);
49 | $stream = $this->createMock(StreamInterface::class);
50 |
51 | $this->httpClient->expects(self::once())
52 | ->method('request')
53 | ->withConsecutive(
54 | [
55 | 'PATCH',
56 | \sprintf(
57 | '%s/ordermanagement/v1/orders/%s/merchant-references',
58 | self::BASE_URL,
59 | self::TRANSACTION_REFERENCE
60 | ),
61 | \array_merge(
62 | ['Content-Type' => 'application/json'],
63 | $this->getExpectedHeaders()
64 | ),
65 | \json_encode($inputData),
66 | ]
67 | )
68 | ->willReturn($response);
69 |
70 | $response->expects(self::once())
71 | ->method('getBody')
72 | ->willReturn($stream);
73 |
74 | $stream->expects(self::once())
75 | ->method('getContents')
76 | ->willReturnOnConsecutiveCalls(
77 | \json_encode(['error_code' => 'doomsday'])
78 | );
79 |
80 | $this->updateTransactionRequest->initialize(
81 | [
82 | 'base_url' => self::BASE_URL,
83 | 'username' => self::USERNAME,
84 | 'secret' => self::SECRET,
85 | 'transactionReference' => self::TRANSACTION_REFERENCE,
86 | ]
87 | );
88 |
89 | self::assertFalse($this->updateTransactionRequest->sendData($inputData)->isSuccessful());
90 | }
91 |
92 | public function testSendDataWillUpdateOrderManagementMerchantReferences()
93 | {
94 | $merchantReferencesData = ['merchant_reference1' => 'baz', 'merchant_reference2' => 'quz'];
95 |
96 | $response = $this->createMock(ResponseInterface::class);
97 | $stream = $this->createMock(StreamInterface::class);
98 |
99 | $this->httpClient->expects(self::once())
100 | ->method('request')
101 | ->withConsecutive(
102 | [
103 | 'PATCH',
104 | \sprintf(
105 | '%s/ordermanagement/v1/orders/%s/merchant-references',
106 | self::BASE_URL,
107 | self::TRANSACTION_REFERENCE
108 | ),
109 | \array_merge(['Content-Type' => 'application/json'], $this->getExpectedHeaders()),
110 | \json_encode($merchantReferencesData),
111 | ]
112 | )
113 | ->willReturn($response);
114 |
115 | $response->expects(self::once())
116 | ->method('getBody')
117 | ->willReturn($stream);
118 |
119 | $stream->expects(self::once())
120 | ->method('getContents')
121 | ->willReturnOnConsecutiveCalls(\json_encode([]));
122 |
123 | $this->updateTransactionRequest->initialize(
124 | [
125 | 'base_url' => self::BASE_URL,
126 | 'username' => self::USERNAME,
127 | 'secret' => self::SECRET,
128 | 'transactionReference' => self::TRANSACTION_REFERENCE,
129 | ]
130 | );
131 |
132 | $updateTransactionResponse = $this->updateTransactionRequest->sendData($merchantReferencesData);
133 | self::assertEmpty($updateTransactionResponse->getData());
134 | self::assertTrue($updateTransactionResponse->isSuccessful());
135 | }
136 | }
137 |
--------------------------------------------------------------------------------
/tests/Message/UpdateTransactionRequestTest.php:
--------------------------------------------------------------------------------
1 | updateTransactionRequest = new UpdateTransactionRequest($this->httpClient, $this->getHttpRequest());
25 | }
26 |
27 | /**
28 | * @return array
29 | */
30 | public function merchantUrlDataProvider(): array
31 | {
32 | return [
33 | [$this->getMinimalValidMerchantUrlData(), $this->getMinimalExpectedMerchantUrlData()],
34 | [$this->getCompleteValidMerchantUrlData(), $this->getCompleteExpectedMerchantUrlData()],
35 | ];
36 | }
37 |
38 | public function testGetDataWillReturnCorrectData()
39 | {
40 | $this->updateTransactionRequest->initialize(
41 | [
42 | 'amount' => '100.00',
43 | 'tax_amount' => 21,
44 | 'currency' => 'EUR',
45 | 'transactionReference' => self::TRANSACTION_REFERENCE,
46 | 'gui_minimal_confirmation' => true,
47 | 'gui_autofocus' => false,
48 | 'merchant_reference1' => '12345',
49 | 'merchant_reference2' => 678,
50 | 'purchase_country' => 'FR',
51 | ]
52 | );
53 | $this->updateTransactionRequest->setItems([$this->getItemMock()]);
54 |
55 | self::assertEquals(
56 | [
57 | 'order_amount' => 10000,
58 | 'order_tax_amount' => 2100,
59 | 'order_lines' => [$this->getExpectedOrderLine()],
60 | 'purchase_currency' => 'EUR',
61 | 'gui' => ['options' => ['disable_autofocus', 'minimal_confirmation']],
62 | 'merchant_reference1' => '12345',
63 | 'merchant_reference2' => 678,
64 | 'purchase_country' => 'FR',
65 | ],
66 | $this->updateTransactionRequest->getData()
67 | );
68 | }
69 |
70 | public function testGetDataWillReturnCorrectDataForEmptyCart()
71 | {
72 | $this->updateTransactionRequest->initialize(
73 | [
74 | 'amount' => '100.00',
75 | 'tax_amount' => 21,
76 | 'currency' => 'EUR',
77 | 'transactionReference' => self::TRANSACTION_REFERENCE,
78 | 'gui_minimal_confirmation' => true,
79 | 'gui_autofocus' => false,
80 | 'merchant_reference1' => '12345',
81 | 'merchant_reference2' => 678,
82 | 'purchase_country' => 'FR',
83 | ]
84 | );
85 |
86 | self::assertEquals(
87 | [
88 | 'order_amount' => 10000,
89 | 'order_tax_amount' => 2100,
90 | 'order_lines' => [],
91 | 'purchase_currency' => 'EUR',
92 | 'gui' => ['options' => ['disable_autofocus', 'minimal_confirmation']],
93 | 'merchant_reference1' => '12345',
94 | 'merchant_reference2' => 678,
95 | 'purchase_country' => 'FR',
96 | ],
97 | $this->updateTransactionRequest->getData()
98 | );
99 | }
100 |
101 | public function testGetDataWillThrowExceptionForInvalidRequest()
102 | {
103 | $this->updateTransactionRequest->initialize([]);
104 |
105 | $this->expectException(InvalidRequestException::class);
106 | $this->updateTransactionRequest->getData();
107 | }
108 |
109 | public function testGetDataWithAddressWillReturnCorrectData()
110 | {
111 | $organization = 'Foo inc';
112 | $reference = 'ref';
113 | $attention = 'quz';
114 | $email = 'foo@bar.com';
115 | $title = 'Mr.';
116 | $streetAddress = 'Foo Street 1';
117 | $streetAddress2 = 'App. 12A';
118 | $streetName = 'Foo Street';
119 | $houseExtension = 'C';
120 | $streetNumber = '1';
121 | $postalCode = '523354';
122 | $city = 'Oss';
123 | $region = 'NB';
124 | $phone = '24234234';
125 | $country = 'NL';
126 |
127 | $shippingAddress = [
128 | 'organization_name' => $organization,
129 | 'reference' => $reference,
130 | 'attention' => $attention,
131 | 'given_name' => 'foo',
132 | 'family_name' => 'bar',
133 | 'email' => $email,
134 | 'title' => $title,
135 | 'street_address' => $streetAddress,
136 | 'street_address2' => $streetAddress2,
137 | 'street_name' => $streetName,
138 | 'street_number' => $streetNumber,
139 | 'house_extension' => $houseExtension,
140 | 'postal_code' => $postalCode,
141 | 'city' => $city,
142 | 'region' => $region,
143 | 'phone' => $phone,
144 | 'country' => $country,
145 | ];
146 | $billingAddress = [
147 | 'organization_name' => $organization,
148 | 'reference' => $reference,
149 | 'attention' => $attention,
150 | 'given_name' => 'bar',
151 | 'family_name' => 'foo',
152 | 'email' => $email,
153 | 'title' => $title,
154 | 'street_address' => $streetAddress,
155 | 'street_address2' => $streetAddress2,
156 | 'street_name' => $streetName,
157 | 'street_number' => $streetNumber,
158 | 'house_extension' => $houseExtension,
159 | 'postal_code' => $postalCode,
160 | 'city' => $city,
161 | 'region' => $region,
162 | 'phone' => $phone,
163 | 'country' => $country,
164 | ];
165 |
166 | $this->updateTransactionRequest->initialize(
167 | [
168 | 'locale' => 'nl_NL',
169 | 'amount' => '100.00',
170 | 'tax_amount' => 21,
171 | 'currency' => 'EUR',
172 | 'transactionReference' => self::TRANSACTION_REFERENCE,
173 | 'gui_minimal_confirmation' => true,
174 | 'gui_autofocus' => false,
175 | 'merchant_reference1' => '12345',
176 | 'merchant_reference2' => 678,
177 | 'purchase_country' => 'NL',
178 | ]
179 | );
180 | $this->updateTransactionRequest->setItems([$this->getItemMock()]);
181 | $this->updateTransactionRequest->setShippingAddress($shippingAddress);
182 | $this->updateTransactionRequest->setBillingAddress($billingAddress);
183 |
184 | self::assertEquals(
185 | [
186 | 'locale' => 'nl-NL',
187 | 'order_amount' => 10000,
188 | 'order_tax_amount' => 2100,
189 | 'order_lines' => [$this->getExpectedOrderLine()],
190 | 'purchase_country' => 'NL',
191 | 'purchase_currency' => 'EUR',
192 | 'gui' => ['options' => ['disable_autofocus', 'minimal_confirmation']],
193 | 'merchant_reference1' => '12345',
194 | 'merchant_reference2' => 678,
195 | 'shipping_address' => $shippingAddress,
196 | 'billing_address' => $billingAddress,
197 | ],
198 | $this->updateTransactionRequest->getData()
199 | );
200 | }
201 |
202 | public function testGetDataWithCustomerWillReturnCorrectData()
203 | {
204 | $customer = [
205 | 'date_of_birth' => '1995-10-20',
206 | 'type' => 'organization',
207 | ];
208 |
209 | $this->updateTransactionRequest->initialize(
210 | [
211 | 'locale' => 'nl_NL',
212 | 'amount' => '100.00',
213 | 'tax_amount' => 21,
214 | 'currency' => 'EUR',
215 | 'transactionReference' => self::TRANSACTION_REFERENCE,
216 | 'purchase_country' => 'FR',
217 | ]
218 | );
219 | $this->updateTransactionRequest->setItems([$this->getItemMock()]);
220 | $this->updateTransactionRequest->setCustomer($customer);
221 |
222 | self::assertEquals(
223 | [
224 | 'locale' => 'nl-NL',
225 | 'order_amount' => 10000,
226 | 'order_tax_amount' => 2100,
227 | 'order_lines' => [$this->getExpectedOrderLine()],
228 | 'purchase_country' => 'FR',
229 | 'purchase_currency' => 'EUR',
230 | 'customer' => $customer,
231 | ],
232 | $this->updateTransactionRequest->getData()
233 | );
234 | }
235 |
236 | /**
237 | * @dataProvider merchantUrlDataProvider
238 | *
239 | * @param array $merchantUrlData
240 | * @param array $expectedMerchantUrls
241 | */
242 | public function testGetDataWithMerchantUrlsWillReturnCorrectData(
243 | $merchantUrlData,
244 | $expectedMerchantUrls
245 | ) {
246 | $this->updateTransactionRequest->initialize(
247 | \array_merge(
248 | [
249 | 'amount' => '100.00',
250 | 'tax_amount' => 21,
251 | 'currency' => 'EUR',
252 | 'transactionReference' => self::TRANSACTION_REFERENCE,
253 | 'gui_minimal_confirmation' => true,
254 | 'gui_autofocus' => false,
255 | 'merchant_reference1' => '12345',
256 | 'merchant_reference2' => 678,
257 | 'purchase_country' => 'FR',
258 | 'returnUrl' => 'localhost/return',
259 | 'notifyUrl' => 'localhost/notify',
260 | 'termsUrl' => 'localhost/terms',
261 | ],
262 | $merchantUrlData
263 | )
264 | );
265 | $this->updateTransactionRequest->setItems([$this->getItemMock()]);
266 |
267 | self::assertEquals(
268 | [
269 | 'order_amount' => 10000,
270 | 'order_tax_amount' => 2100,
271 | 'order_lines' => [$this->getExpectedOrderLine()],
272 | 'purchase_currency' => 'EUR',
273 | 'gui' => ['options' => ['disable_autofocus', 'minimal_confirmation']],
274 | 'merchant_reference1' => '12345',
275 | 'merchant_reference2' => '678',
276 | 'purchase_country' => 'FR',
277 | 'merchant_urls' => $expectedMerchantUrls,
278 | ],
279 | $this->updateTransactionRequest->getData()
280 | );
281 | }
282 |
283 | public function testGetDataWithOptionsWillReturnCorrectData()
284 | {
285 | $widgetOptions = [
286 | 'acquiring_channel' => 'foo',
287 | 'allow_separate_shipping_address' => true,
288 | 'color_button' => '#FFFFF',
289 | 'color_button_text' => '#FFFFF',
290 | 'color_checkbox' => '#FFFFF',
291 | 'color_checkbox_checkmark' => '#FFFFF',
292 | 'color_header' => '#FFFFF',
293 | 'color_link' => '#FFFFF',
294 | 'date_of_birth_mandatory' => true,
295 | 'shipping_details' => 'Delivered within 1-3 working days',
296 | 'title_mandatory' => true,
297 | 'additional_checkbox' => [
298 | 'text' => 'Please add me to the newsletter list',
299 | 'checked' => false,
300 | 'required' => false,
301 | ],
302 | 'radius_border' => '5px',
303 | 'show_subtotal_detail' => true,
304 | 'require_validate_callback_success' => true,
305 | 'allow_global_billing_countries' => false,
306 | ];
307 |
308 | $this->updateTransactionRequest->initialize(
309 | [
310 | 'locale' => 'nl_NL',
311 | 'amount' => '100.00',
312 | 'tax_amount' => 21,
313 | 'currency' => 'EUR',
314 | 'transactionReference' => self::TRANSACTION_REFERENCE,
315 | 'gui_minimal_confirmation' => true,
316 | 'gui_autofocus' => false,
317 | 'merchant_reference1' => '12345',
318 | 'merchant_reference2' => 678,
319 | 'purchase_country' => 'DE',
320 | ]
321 | );
322 | $this->updateTransactionRequest->setItems([$this->getItemMock()]);
323 | $this->updateTransactionRequest->setWidgetOptions($widgetOptions);
324 |
325 | /** @noinspection PhpUnhandledExceptionInspection */
326 | /** @noinspection PhpUnhandledExceptionInspection */
327 | self::assertEquals(
328 | [
329 | 'locale' => 'nl-NL',
330 | 'order_amount' => 10000,
331 | 'order_tax_amount' => 2100,
332 | 'order_lines' => [$this->getExpectedOrderLine()],
333 | 'purchase_country' => 'DE',
334 | 'purchase_currency' => 'EUR',
335 | 'gui' => ['options' => ['disable_autofocus', 'minimal_confirmation']],
336 | 'merchant_reference1' => '12345',
337 | 'merchant_reference2' => 678,
338 | 'options' => $widgetOptions,
339 | ],
340 | $this->updateTransactionRequest->getData()
341 | );
342 | }
343 |
344 | public function testSendDataWillCreateOrderAndReturnResponse()
345 | {
346 | $inputData = ['request-data' => 'yey?'];
347 | $responseData = [];
348 |
349 | $this->setExpectedPostRequest(
350 | $inputData,
351 | $responseData,
352 | \sprintf('%s/checkout/v3/orders/%s', self::BASE_URL, self::TRANSACTION_REFERENCE)
353 | );
354 |
355 | $this->updateTransactionRequest->initialize(
356 | [
357 | 'base_url' => self::BASE_URL,
358 | 'username' => self::USERNAME,
359 | 'secret' => self::SECRET,
360 | 'transactionReference' => self::TRANSACTION_REFERENCE,
361 | ]
362 | );
363 |
364 | $updateTransactionResponse = $this->updateTransactionRequest->sendData($inputData);
365 |
366 | self::assertInstanceOf(UpdateTransactionResponse::class, $updateTransactionResponse);
367 | self::assertSame($responseData, $updateTransactionResponse->getData());
368 | }
369 | }
370 |
--------------------------------------------------------------------------------
/tests/Message/VoidRequestTest.php:
--------------------------------------------------------------------------------
1 | voidRequest = new VoidRequest($this->httpClient, $this->getHttpRequest());
23 | }
24 |
25 | public function testGetDataWillReturnCorrectData()
26 | {
27 | $this->voidRequest->initialize(['transactionReference' => 'foo']);
28 |
29 | /** @noinspection PhpUnhandledExceptionInspection */
30 | self::assertEquals([], $this->voidRequest->getData());
31 | }
32 |
33 | public function testGetDataWillThrowExceptionForInvalidRequest()
34 | {
35 | $this->voidRequest->initialize([]);
36 |
37 | $this->expectException(InvalidRequestException::class);
38 | /** @noinspection PhpUnhandledExceptionInspection */
39 | $this->voidRequest->getData();
40 | }
41 |
42 | /**
43 | * @dataProvider voidRequestCaptureDataProvider
44 | *
45 | * @param array $captures
46 | * @param string $expectedPostRoute
47 | */
48 | public function testSendDataWillVoidOrderAndReturnResponse(array $captures, $expectedPostRoute)
49 | {
50 | $inputData = ['request-data' => 'yey?'];
51 | $expectedData = [];
52 |
53 | $response = $this->createMock(ResponseInterface::class);
54 | $stream = $this->createMock(StreamInterface::class);
55 |
56 | $this->httpClient->expects(self::exactly(2))
57 | ->method('request')
58 | ->withConsecutive(
59 | [
60 | 'GET',
61 | self::BASE_URL . '/ordermanagement/v1/orders/' . self::TRANSACTION_REF,
62 | $this->getExpectedHeaders(),
63 | null,
64 | ],
65 | [
66 | 'POST',
67 | self::BASE_URL . '/ordermanagement/v1/orders/' . self::TRANSACTION_REF . $expectedPostRoute,
68 | \array_merge(['Content-Type' => 'application/json'], $this->getExpectedHeaders()),
69 | \json_encode($inputData),
70 | ]
71 | )
72 | ->willReturn($response);
73 |
74 | $response->method('getBody')->willReturn($stream);
75 | $stream->expects(self::exactly(2))
76 | ->method('getContents')
77 | ->willReturnOnConsecutiveCalls(
78 | \json_encode(['captures' => $captures]),
79 | \json_encode($expectedData)
80 | );
81 |
82 | $response->expects(self::once())->method('getStatusCode')->willReturn(204);
83 |
84 | $this->voidRequest->initialize(
85 | [
86 | 'base_url' => self::BASE_URL,
87 | 'username' => self::USERNAME,
88 | 'secret' => self::SECRET,
89 | 'transactionReference' => self::TRANSACTION_REF,
90 | ]
91 | );
92 |
93 | $voidResponse = $this->voidRequest->sendData($inputData);
94 |
95 | self::assertInstanceOf(VoidResponse::class, $voidResponse);
96 | self::assertSame($expectedData, $voidResponse->getData());
97 | }
98 |
99 | /**
100 | * @return array
101 | */
102 | public function voidRequestCaptureDataProvider(): array
103 | {
104 | return [
105 | [[], '/cancel'],
106 | [[['capture-id' => 1]], '/release-remaining-authorization'],
107 | ];
108 | }
109 | }
110 |
--------------------------------------------------------------------------------
/tests/Message/VoidResponseTest.php:
--------------------------------------------------------------------------------
1 | createMock(RequestInterface::class);
27 |
28 | $response = new VoidResponse($request, [], 201);
29 |
30 | self::assertSame(201, $response->getStatusCode());
31 | }
32 |
33 | /**
34 | * @dataProvider responseCodeProvider
35 | *
36 | * @param string $responseCode
37 | * @param bool $expectedResult
38 | */
39 | public function testIsSuccessfulWillReturnCorrectStateWithResponseCode($responseCode, $expectedResult)
40 | {
41 | $request = $this->createMock(RequestInterface::class);
42 |
43 | $captureResponse = new VoidResponse($request, [], $responseCode);
44 |
45 | self::assertEquals($expectedResult, $captureResponse->isSuccessful());
46 | }
47 | }
48 |
--------------------------------------------------------------------------------
/tests/Message/WidgetOptionsTest.php:
--------------------------------------------------------------------------------
1 | 'foo',
20 | 'allow_separate_shipping_address' => true,
21 | 'color_button' => '#FFFFF',
22 | 'color_button_text' => '#FFFFF',
23 | 'color_checkbox' => '#FFFFF',
24 | 'color_checkbox_checkmark' => '#FFFFF',
25 | 'color_header' => '#FFFFF',
26 | 'color_link' => '#FFFFF',
27 | 'date_of_birth_mandatory' => true,
28 | 'shipping_details' => 'Delivered within 1-3 working days',
29 | 'title_mandatory' => true,
30 | 'additional_checkbox' => [
31 | 'text' => 'Please add me to the newsletter list',
32 | 'checked' => false,
33 | 'required' => false,
34 | ],
35 | 'radius_border' => '5px',
36 | 'show_subtotal_detail' => true,
37 | 'require_validate_callback_success' => true,
38 | ],
39 | [
40 | 'acquiring_channel' => 'foo',
41 | 'allow_separate_shipping_address' => true,
42 | 'color_button' => '#FFFFF',
43 | 'color_button_text' => '#FFFFF',
44 | 'color_checkbox' => '#FFFFF',
45 | 'color_checkbox_checkmark' => '#FFFFF',
46 | 'color_header' => '#FFFFF',
47 | 'color_link' => '#FFFFF',
48 | 'date_of_birth_mandatory' => true,
49 | 'shipping_details' => 'Delivered within 1-3 working days',
50 | 'title_mandatory' => true,
51 | 'additional_checkbox' => [
52 | 'text' => 'Please add me to the newsletter list',
53 | 'checked' => false,
54 | 'required' => false,
55 | ],
56 | 'radius_border' => '5px',
57 | 'show_subtotal_detail' => true,
58 | 'require_validate_callback_success' => true,
59 | 'allow_global_billing_countries' => false,
60 | ],
61 | ],
62 | [
63 | [],
64 | [
65 | 'acquiring_channel' => 'eCommerce',
66 | 'allow_separate_shipping_address' => false,
67 | 'color_button' => null,
68 | 'color_button_text' => null,
69 | 'color_checkbox' => null,
70 | 'color_checkbox_checkmark' => null,
71 | 'color_header' => null,
72 | 'color_link' => null,
73 | 'date_of_birth_mandatory' => false,
74 | 'shipping_details' => null,
75 | 'title_mandatory' => false,
76 | 'additional_checkbox' => null,
77 | 'radius_border' => null,
78 | 'show_subtotal_detail' => false,
79 | 'require_validate_callback_success' => false,
80 | 'allow_global_billing_countries' => false,
81 | ],
82 | ],
83 | [
84 | ['foo' => 'bar'],
85 | [
86 | 'acquiring_channel' => 'eCommerce',
87 | 'allow_separate_shipping_address' => false,
88 | 'color_button' => null,
89 | 'color_button_text' => null,
90 | 'color_checkbox' => null,
91 | 'color_checkbox_checkmark' => null,
92 | 'color_header' => null,
93 | 'color_link' => null,
94 | 'date_of_birth_mandatory' => false,
95 | 'shipping_details' => null,
96 | 'title_mandatory' => false,
97 | 'additional_checkbox' => null,
98 | 'radius_border' => null,
99 | 'show_subtotal_detail' => false,
100 | 'require_validate_callback_success' => false,
101 | 'allow_global_billing_countries' => false,
102 | ],
103 | ],
104 | ];
105 | }
106 |
107 | /**
108 | * @dataProvider dataProvider
109 | *
110 | * @param array $data
111 | * @param array $expectedOutcome
112 | */
113 | public function testFromArrayShoulReturnArrayWithCorrectKeys($data, $expectedOutcome)
114 | {
115 | self::assertEquals($expectedOutcome, WidgetOptions::fromArray($data)->getArrayCopy());
116 | }
117 | }
118 |
--------------------------------------------------------------------------------