Skip to content

Commit bbbb3b7

Browse files
authored
Merge pull request #21 from PaymentHighway/psd2
Psd2
2 parents 3906a64 + 0443c4f commit bbbb3b7

13 files changed

+844
-5
lines changed

.travis.yml

Lines changed: 12 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,19 @@
11
language: php
2+
dist: xenial
3+
24
php:
3-
- '5.5'
45
- '5.6'
56
- '7.0'
7+
- '7.1'
8+
- '7.2'
69
- nightly
10+
11+
matrix:
12+
include:
13+
- php: '5.5'
14+
dist: trusty
15+
allow_failures:
16+
- php: nightly
17+
718
install: composer install
819
script: composer test

README.md

Lines changed: 47 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ add following to composer
1313
```json
1414
"require" :
1515
{
16-
"solinor/paymenthighwayio" : "1.6.0"
16+
"solinor/paymenthighwayio" : "1.7.0"
1717
}
1818
```
1919

@@ -205,14 +205,59 @@ $response = $paymentApi->initTransaction();
205205
```
206206

207207
### Example Debit with Token
208+
NOTE: The `debitTransaction` method will be deprecated starting from Sep 14th 2019 in favor of the new `chargeCustomerInitiatedTransaction` and `chargeMerchantInitiatedTransaction` in order to comply with the EU's PSD2 directive.
209+
208210
```php
209211
$token = new \Solinor\PaymentHighway\Model\Token( $tokenId );
210212

211-
$transaction = new \Solinor\PaymentHighway\Model\Request\Transaction( $amount, $currency, $token );
213+
$transaction = new \Solinor\PaymentHighway\Model\Request\Transaction( $token, $amount, $currency );
212214

213215
$response = $paymentApi->debitTransaction( $transactionId, $transaction);
214216
```
215217

218+
### Charging a card
219+
220+
After the introduction of the European PSD2 directive the electronic payment transactions are categorised in so called customer initiated transactions (CIT) and merchant initiated transactions (MIT).
221+
222+
Customer initiated transactions are scenarios where the customer takes actively part in the payment process either by providing their card information or selecting a previously stored payment method. Also so-called "one-click" purchases where the transaction uses a previously saved default payment method are CITs.
223+
224+
Merchant initated transactions are transactions which are initated by the merchant without customer's participation. Merchant initated transactions require a prior agreement between the customer and merchant also called the "mandate". Merchant initiated transactions can be used for example in scenarios where the final price is not known at the time of the purchase or the customer is not present when the charge is made.
225+
226+
#### Charging a customer initiated transaction (CIT)
227+
228+
When charging a customer initiated transaction there is always a possibility that the card issuer requires strong customer authentication. In case the issuer requests SCA then the response will contain "soft decline" code 400 and an URL where the customer needs to be redirected to perform authentication. The URLs where the customer will be redirected after completing authentication need to be defined in the [`ReturnUrls`](/src/Model/Sca/ReturnUrls.php) object.
229+
230+
In addition to the return urls the [`StrongCustomerAuthentication`](/src/Model/Sca/StrongCustomerAuthentication.php) object has many optional fields for information about the customer and the transaction. This information is used in transaction risk analysis (TRA) and can increase the likelihood that the transaction is considered low risk so that strong customer authentication is not needed.
231+
232+
```php
233+
$token = new \Solinor\PaymentHighway\Model\Token( $tokenId );
234+
235+
$strongCustomerAuthentication = new \Solinor\PaymentHighway\Model\Sca\StrongCustomerAuthentication(
236+
new \Solinor\PaymentHighway\Model\Sca\ReturnUrls(
237+
"https://example.com/success", // URL the user is redirected after succesful 3D-Secure authentication if strong customer authentication is required
238+
"https://example.com/cancel", // URL the user is redirected after cancelled 3D-Secure authentication if strong customer authentication is required
239+
"https://example.com/failure" // URL the user is redirected after failed 3D-Secure authentication if strong customer authentication is required
240+
)
241+
// Optinally other information about the customer and purchase to help in transaction risk analysis (TRA)
242+
);
243+
244+
$transaction = new \Solinor\PaymentHighway\Model\Request\CustomerInitiatedTransaction( $token, $amount, $currency, $strongCustomerAuthentication );
245+
246+
$response = $paymentApi->chargeCustomerInitiatedTransaction( $transactionId, $transaction);
247+
```
248+
249+
#### Charging a merchant initiated transaction (MIT)
250+
251+
When charging the customer's card in context where the customer is not actively participating in the transaction you should use the `chargeMerchantInitiatedTransaction` method. The MIT transactions are exempt from the strong customer authentication requirements of PSD2 so the request cannot be answered with "soft-decline" response (code 400) unlike customer initated transactions.
252+
253+
```php
254+
$token = new \Solinor\PaymentHighway\Model\Token( $tokenId );
255+
256+
$transaction = new \Solinor\PaymentHighway\Model\Request\Transaction( $token, $amount, $currency );
257+
258+
$response = $paymentApi->chargeMerchantInitiatedTransaction( $transactionId, $transaction);
259+
```
260+
216261
### Example Revert
217262
```php
218263
$response = $paymentApi->revertTransaction("transactionId", "amount");
Lines changed: 58 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,58 @@
1+
<?php namespace Solinor\PaymentHighway\Model\Request;
2+
3+
use Solinor\PaymentHighway\Model\Token;
4+
use Solinor\PaymentHighway\Model\Card;
5+
6+
/**
7+
* Class CustomerInitiatedTransaction
8+
* @package Solinor\PaymentHighway\Model\Request
9+
*/
10+
11+
class CustomerInitiatedTransaction extends \Solinor\PaymentHighway\Model\JsonSerializable
12+
{
13+
public $amount = null;
14+
public $currency = null;
15+
public $order = null;
16+
public $blocking = true;
17+
18+
public $token = null;
19+
public $card = null;
20+
public $splitting = null;
21+
22+
public $strong_customer_authentication = null;
23+
24+
/**
25+
* @param Card|Token|null $request
26+
* @param int $amount
27+
* @param string $currency
28+
* @param \Solinor\PaymentHighway\Model\Sca\StrongCustomerAuthentication $strong_customer_authentication
29+
* @param bool $blocking
30+
* @param string $orderId
31+
* @param \Solinor\PaymentHighway\Model\Splitting $splitting
32+
* @throws \Exception
33+
*/
34+
public function __construct( $request, $amount, $currency, $strong_customer_authentication, $blocking = true, $orderId = null, $splitting = null )
35+
{
36+
$this->amount = $amount;
37+
$this->currency = $currency;
38+
$this->order = $orderId;
39+
$this->blocking = $blocking;
40+
$this->splitting = $splitting;
41+
$this->strong_customer_authentication = $strong_customer_authentication;
42+
43+
$this->setRequestByType($request);
44+
}
45+
46+
/**
47+
* @param $request
48+
*/
49+
private function setRequestByType( $request )
50+
{
51+
if( $request instanceof Token ){
52+
$this->token = $request;
53+
}
54+
elseif( $request instanceof Card ){
55+
$this->card = $request;
56+
}
57+
}
58+
}

src/Model/Request/Transaction.php

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,8 +25,8 @@ class Transaction extends \Solinor\PaymentHighway\Model\JsonSerializable
2525
* @param Card|Token|null $request
2626
* @param bool $blocking
2727
* @param string $orderId
28-
* @param Splitting $splitting
29-
* @throws Exception
28+
* @param \Solinor\PaymentHighway\Model\Splitting $splitting
29+
* @throws \Exception
3030
*/
3131
public function __construct( $request, $amount, $currency, $blocking = true, $orderId = null, $splitting = null )
3232
{

src/Model/Sca/Address.php

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
<?php namespace Solinor\PaymentHighway\Model\Sca;
2+
3+
/**
4+
* Class Address
5+
*
6+
* @package Solinor\PaymentHighway\Model\Sca
7+
*/
8+
9+
class Address extends \Solinor\PaymentHighway\Model\JsonSerializable
10+
{
11+
public $city = null;
12+
public $country = null;
13+
public $address_line_1 = null;
14+
public $address_line_2 = null;
15+
public $address_line_3 = null;
16+
public $post_code = null;
17+
public $state = null;
18+
19+
/**
20+
* @param string $city max length 50, City name
21+
* @param string $country 3 digits country code, 3166-1 numeric (eg. "246")
22+
* @param string $address_line_1 max length 50, Address line 1
23+
* @param string $address_line_2 max length 50, Address line 2
24+
* @param string $address_line_3 max length 50, Address line 3
25+
* @param string $post_code max length 16, Zip code
26+
* @param string $state String length 2, ISO 3166-2 country subdivision code (eg. "18")
27+
*/
28+
public function __construct(
29+
$city = null,
30+
$country = null,
31+
$address_line_1 = null,
32+
$address_line_2 = null,
33+
$address_line_3 = null,
34+
$post_code = null,
35+
$state = null
36+
){
37+
$this->city = $city;
38+
$this->country = $country;
39+
$this->address_line_1 = $address_line_1;
40+
$this->address_line_2 = $address_line_2;
41+
$this->address_line_3 = $address_line_3;
42+
$this->post_code = $post_code;
43+
$this->state = $state;
44+
}
45+
}

src/Model/Sca/CustomerAccount.php

Lines changed: 139 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,139 @@
1+
<?php namespace Solinor\PaymentHighway\Model\Sca;
2+
3+
/**
4+
* Class CustomerAccount
5+
*
6+
* @package Solinor\PaymentHighway\Model\Sca
7+
*/
8+
9+
class CustomerAccount extends \Solinor\PaymentHighway\Model\JsonSerializable
10+
{
11+
public $account_age_indicator = null;
12+
public $account_date = null;
13+
public $change_indicator = null;
14+
public $change_date = null;
15+
public $password_change_indicator = null;
16+
public $password_change_date = null;
17+
public $number_of_recent_purchases = null;
18+
public $number_of_add_card_attempts_day = null;
19+
public $number_of_transaction_activity_day = null;
20+
public $number_of_transaction_activity_year = null;
21+
public $shipping_address_indicator = null;
22+
public $shipping_address_usage_date = null;
23+
public $suspicious_activity = null;
24+
25+
/**
26+
* @param string $account_age_indicator Length of time that the cardholder has had the account.
27+
* @param string $account_date Date, when the cardholder opened the account at merchant (eg. "2019-07-05")
28+
* @param string $change_indicator Length of time since the cardholder’s account information was last changed.
29+
* @param string $change_date Date, when the cardholder’s account was last changed. Including Billing or Shipping address (eg. "2019-07-05")
30+
* @param string $password_change_indicator Length of time since the cardholder’s account had a password change or account reset.
31+
* @param string $password_change_date Date, when cardholder’s account with the 3DS Requestor had a password change or account reset. (eg. "2019-07-05")
32+
* @param int $number_of_recent_purchases Max value: 9999, Number of purchases with this cardholder account during the previous six months.
33+
* @param int $number_of_add_card_attempts_day Max value: 999, Number of Add Card attempts in the last 24 hours.
34+
* @param int $number_of_transaction_activity_day Max value: 999, Number of transactions (successful and abandoned) for this cardholder account across all payment accounts in the previous 24 hours.
35+
* @param int $number_of_transaction_activity_year Max value: 999, Number of transactions (successful and abandoned) for this cardholder account with the 3DS Requestor across all payment accounts in the previous year.
36+
* @param string $shipping_address_indicator Indicates when the shipping address used for this transaction was first used.
37+
* @param string $shipping_address_usage_date Date, when the shipping address used for this transaction was first used. (eg. "2019-07-05")
38+
* @param string $suspicious_activity Indicates whether suspicious activity has been experienced (including previous fraud) on the cardholder account.
39+
*/
40+
public function __construct(
41+
$account_age_indicator = null,
42+
$account_date = null,
43+
$change_indicator = null,
44+
$change_date = null,
45+
$password_change_indicator = null,
46+
$password_change_date = null,
47+
$number_of_recent_purchases = null,
48+
$number_of_add_card_attempts_day = null,
49+
$number_of_transaction_activity_day = null,
50+
$number_of_transaction_activity_year = null,
51+
$shipping_address_indicator = null,
52+
$shipping_address_usage_date = null,
53+
$suspicious_activity = null
54+
){
55+
$this->account_age_indicator = $account_age_indicator;
56+
$this->account_date = $account_date;
57+
$this->change_indicator = $change_indicator;
58+
$this->change_date = $change_date;
59+
$this->password_change_indicator = $password_change_indicator;
60+
$this->password_change_date = $password_change_date;
61+
$this->number_of_recent_purchases = $number_of_recent_purchases;
62+
$this->number_of_add_card_attempts_day = $number_of_add_card_attempts_day;
63+
$this->number_of_transaction_activity_day = $number_of_transaction_activity_day;
64+
$this->number_of_transaction_activity_year = $number_of_transaction_activity_year;
65+
$this->shipping_address_indicator = $shipping_address_indicator;
66+
$this->shipping_address_usage_date = $shipping_address_usage_date;
67+
$this->suspicious_activity = $suspicious_activity;
68+
}
69+
}
70+
71+
/**
72+
* Length of time that the cardholder has had the account.
73+
* 01 = No account (guest check-out)
74+
* 02 = Created during this transaction
75+
* 03 = Less than 30 days
76+
* 04 = 30−60 days
77+
* 05 = More than 60 days
78+
*/
79+
abstract class AccountAgeIndicator {
80+
const NoAccount = "01";
81+
const CreatedDuringTransaction = "02";
82+
const LessThan30Days = "03";
83+
const Between30And60Days = "04";
84+
const MoreThan60Days = "05";
85+
}
86+
87+
/**
88+
* Length of time since the cardholder’s account information was last changed. Including Billing or Shipping address, new payment account, or new user(s) added.
89+
* 01 = Changed during this transaction
90+
* 02 = Less than 30 days
91+
* 03 = 30−60 days
92+
* 04 = More than 60 days
93+
*/
94+
abstract class AccountInformationChangeIndicator {
95+
const ChangedDuringTransaction = "01";
96+
const LessThan30Days = "02";
97+
const Between30And60Days = "03";
98+
const MoreThan60Days = "04";
99+
}
100+
101+
/**
102+
* Length of time since the cardholder’s account had a password change or account reset.
103+
* 01 = No change
104+
* 02 = Changed during this transaction
105+
* 03 = Less than 30 days
106+
* 04 = 30−60 days
107+
* 05 = More than 60 days
108+
*/
109+
abstract class AccountPasswordChangeIndicator {
110+
const NoChange = "01";
111+
const ChangedDuringTransaction = "02";
112+
const LessThan30Days = "03";
113+
const Between30And60Days = "04";
114+
const MoreThan60Days = "05";
115+
}
116+
117+
/**
118+
* Indicates when the shipping address used for this transaction was first used.
119+
* 01 = This transaction
120+
* 02 = Less than 30 days
121+
* 03 = 30−60 days
122+
* 04 = More than 60 days
123+
*/
124+
abstract class ShippingAddressFirstUsedIndicator {
125+
const ThisTransaction = "01";
126+
const LessThan30Days = "02";
127+
const Between30And60Days = "03";
128+
const MoreThan60Days = "04";
129+
}
130+
131+
/**
132+
* Indicates whether suspicious activity has been experienced (including previous fraud) on the cardholder account.
133+
* 01 = No suspicious activity has been observed
134+
* 02 = Suspicious activity has been observed
135+
*/
136+
abstract class SuspiciousActivityIndicator {
137+
const NoSuspiciousActivity = "01";
138+
const SuspiciousActivityObserved = "02";
139+
}

src/Model/Sca/CustomerDetails.php

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
<?php namespace Solinor\PaymentHighway\Model\Sca;
2+
3+
/**
4+
* Class CustomerDetails
5+
*
6+
* @package Solinor\PaymentHighway\Model\Sca
7+
*/
8+
9+
class CustomerDetails extends \Solinor\PaymentHighway\Model\JsonSerializable
10+
{
11+
public $shipping_address_matches_billing_address = null;
12+
public $name = null;
13+
public $email = null;
14+
public $home_phone = null;
15+
public $mobile_phone = null;
16+
public $work_phone = null;
17+
18+
/**
19+
* @param boolean $shipping_address_matches_billing_address Does the shipping address matches the billing address
20+
* @param string $name Customer name. max length 45
21+
* @param string $email Customer email. max length 254
22+
* @param PhoneNumber $home_phone
23+
* @param PhoneNumber $mobile_phone
24+
* @param PhoneNumber $work_phone
25+
*/
26+
public function __construct(
27+
$shipping_address_matches_billing_address = null,
28+
$name = null,
29+
$email = null,
30+
$home_phone = null,
31+
$mobile_phone = null,
32+
$work_phone = null
33+
){
34+
$this->shipping_address_matches_billing_address = $shipping_address_matches_billing_address;
35+
$this->name = $name;
36+
$this->email = $email;
37+
$this->home_phone = $home_phone;
38+
$this->mobile_phone = $mobile_phone;
39+
$this->work_phone = $work_phone;
40+
}
41+
}

0 commit comments

Comments
 (0)