Skip to content

Commit

Permalink
Support for paymentPage recurring payments.
Browse files Browse the repository at this point in the history
  • Loading branch information
judgej committed Apr 4, 2020
1 parent 8d87875 commit 7804e58
Show file tree
Hide file tree
Showing 13 changed files with 537 additions and 39 deletions.
55 changes: 55 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@ Table of Contents
* [Payment Page](#payment-page)
* [Purchase (redirect)](#purchase-redirect)
* [Payment Page Complete Payment](#payment-page-complete-payment)
* [Payment Page Recurring Profiles](#payment-page-recurring-profiles)
* [Notification Handler](#notification-handler)

# mPAY24 Driver for Omnipay v3
Expand Down Expand Up @@ -111,6 +112,12 @@ but could be carried forward through the session instead.

The `/pay` endpoint handles the actual payment.

The above form does not redirect the user to a payment page.
Instead, it sends the card details to the gateway, with the token as a key.
So in the next step, the gateway will already have the card details and the
merchant site will just use the pre-generated token to reference them when
completing the payment.

### Payment Using Token

```php
Expand Down Expand Up @@ -265,6 +272,54 @@ Alternatively a range of payment methods can be supplied as a JSON string:

The transaction is completed in exactly the same way as for the seamless payments.

### Payment Page Recurring Profiles

The gateway supports two types of profile: a single recurring payment profile for a customer,
and up to 20 interactive profiles for each customer.
The *Payment Page* API will support only ONE of these profile types at a time.
This driver presently support ONLY recurrent payment profiles for *Payment Page*.

To create or update a customer's recurring payment profile, when making a purchase,
set the `createCard` flag and provide a `customerId`:

'createCard' => true,
'customerId' => 'cust-12345',

On completing the payment, you can check if the customer recurring profile was created
or updated by checking the profile status:

$profileWasCreatedOrUpdates = $completeResult->isProfileChanged();

If this returns true, then it means the payment details for the current transaction
have been saved against the customer ID.
Use the customer ID as though it were a card reference when making a backend payment.

A customer ID can be used to make a recurring payment (an offline payment) liek this:

```php
$gateway = Omnipay::create('Mpay24_Backend');

// Set the usual merchant ID and test mode flags.

$request = $gateway->purchase([
'amount' => '9.99',
'currency' => 'EUR',
'transactionId' => 'new-transaction-id',
'description' => 'Recurring Payment Description',
'card' => [
'name' => 'Customer Name',
],
'notifyUrl' => 'https://omnipay.acadweb.co.uk/mpay24/notify.php?foo=bar&fee=fah', // mandatory
'language' => 'de',
// Either
'customerId' => 'cust-12345',
// or
'cardReference' => 'cust-12345',
]);
```

This will return the details of the successful payment, or error details if not successful.

## Notification Handler

The notification handler will accept notification server requests,
Expand Down
57 changes: 57 additions & 0 deletions src/BackendGateway.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,57 @@
<?php

namespace Omnipay\Mpay24;

use Omnipay\Mpay24\Messages\Backend\ListProfilesRequest;
use Omnipay\Mpay24\Messages\Backend\DeleteProfileRequest;
use Omnipay\Mpay24\Messages\FetchTransactionRequest;
use Omnipay\Mpay24\Messages\Backend\PurchaseRequest;
use Omnipay\Mpay24\Messages\AcceptNotification;

class BackendGateway extends PaymentPageGateway
{
/**
* @param array $parameters
* @return PurchaseRequest
*/
public function purchase(array $parameters = [])
{
return $this->createRequest(PurchaseRequest::class, $parameters);
}

/**
* @param array $parameters
* @return PurchaseRequest
*/
public function authorize(array $parameters = [])
{
return $this->purchase($parameters);
}

/**
* @param array $parameters
* @return ListProfilesRequest
*/
public function listProfiles(array $parameters = [])
{
return $this->createRequest(ListProfilesRequest::class, $parameters);
}

/**
* @param array $parameters
* @return DeleteProfileRequest
*/
public function deleteProfile(array $parameters = [])
{
return $this->createRequest(DeleteProfileRequest::class, $parameters);
}

/**
* @param array $parameters
* @return DeleteProfileRequest
*/
public function deleteCard(array $parameters = [])
{
return $this->deletePofile($parameters);
}
}
12 changes: 12 additions & 0 deletions src/ConstantsInterface.php
Original file line number Diff line number Diff line change
Expand Up @@ -165,6 +165,7 @@ interface ConstantsInterface
const PTYPE_PAYOLUTION = 'PAYOLUTION';
const PTYPE_SOFORT = 'SOFORT';
const PTYPE_MASTERPASS = 'MASTERPASS';
const PTYPE_PROFILE = 'PROFILE';

/**
* Brands.
Expand Down Expand Up @@ -221,4 +222,15 @@ interface ConstantsInterface
const CSS_NAME_WEB = 'WEB';
const CSS_NAME_MOBILE = 'MOBILE';
const CSS_NAME_MODERN = 'MODERN';

/**
*
*/

const PROFILE_STATUS_IGNORED = 'IGNORED';
const PROFILE_STATUS_USED = 'USED';
const PROFILE_STATUS_ERROR = 'ERROR';
const PROFILE_STATUS_CREATED = 'CREATED';
const PROFILE_STATUS_UPDATED = 'UPDATED';
const PROFILE_STATUS_DELETED = 'DELETED';
}
38 changes: 36 additions & 2 deletions src/Messages/AbstractMpay24Request.php
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,11 @@
use Omnipay\Mpay24\ConstantsInterface;
use Mpay24\Mpay24;
use Mpay24\Mpay24Config;
use Money\Money;
use Money\Number;
//use Money\Currencies\ISOCurrencies;
use Money\Currency;
use Money\Parser\DecimalMoneyParser;

abstract class AbstractMpay24Request extends AbstractRequest implements ConstantsInterface
{
Expand Down Expand Up @@ -135,9 +140,38 @@ protected function getShippingAddressData()
}

/**
* @return array
* Return the items basket/cart as data with mPAY24 key names.
*/
protected function getShoppingCartData()
public function getShoppingCartData(): array
{
$data = [];

if (! empty($this->getItems())) {
$itemNumber = 0;

foreach ($this->getItems() as $item) {
$itemNumber++;

$currencyCode = $this->getCurrency();
$currency = new Currency($currencyCode);

$moneyParser = new DecimalMoneyParser($this->getCurrencies());

$number = Number::fromString($item->getPrice());

$money = $moneyParser->parse((string) $number, $currency);

$data[$itemNumber] = [
'number' => $itemNumber,
'productNr' => $item->getName(),
'description' => $item->getDescription() ?: $item->getName(),
'quantity' => $item->getQuantity(),
'itemPrice' => $item->getPrice(), // Major units
'amount' => $money->getAmount(), // Minor units
];
}
}

return $data;
}
}
45 changes: 45 additions & 0 deletions src/Messages/Backend/DeleteProfileRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
<?php

namespace Omnipay\Mpay24\Messages\Backend;

use Omnipay\Mpay24\Messages\AbstractMpay24Request;
use Mpay24\Mpay24Order;

class DeleteProfileRequest extends AbstractMpay24Request
{
/**
* The data key names are from the mPAY24 spec, but lower camelCase.
*
* @return array
* @throws InvalidRequestException
* @throws \Omnipay\Common\Exception\InvalidRequestException
*/
public function getData()
{
return [
'customerId' => $this->getCustomerId() ?? $this->getCardReference(),
'profileId' => $this->getProfileId(),
];
}

/**
* @param array $data
* @return ResponseInterface|ListProfilesResponse
*/
public function sendData($data)
{
$mpay24 = $this->getMpay();

$result = $mpay24->deleteProfile(
$data['customerId'],
$data['profileId']
);

$resultData = [
'operationStatus' => $result->getStatus(),
'returnCode' => $result->getReturnCode(),
];

return new Response($this, $resultData);
}
}
50 changes: 50 additions & 0 deletions src/Messages/Backend/ListProfilesRequest.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php

namespace Omnipay\Mpay24\Messages\Backend;

use Omnipay\Mpay24\Messages\AbstractMpay24Request;
use Mpay24\Mpay24Order;

class ListProfilesRequest extends AbstractMpay24Request
{
/**
* The data key names are from the mPAY24 spec, but lower camelCase.
*
* @return array
* @throws InvalidRequestException
* @throws \Omnipay\Common\Exception\InvalidRequestException
*/
public function getData()
{
return [
'customerId' => $this->getCustomerId() ?? $this->getCardReference(),
'expiredBy' => $this->getExpiredBy(),
'begin' => $this->getBegin(),
'size' => $this->getSize(),
];
}

/**
* @param array $data
* @return ResponseInterface|ListProfilesResponse
*/
public function sendData($data)
{
$mpay24 = $this->getMpay();

$result = $mpay24->listCustomers(
$data['customerId'],
$data['expiredBy'],
$data['begin'],
$data['size']
);

$resultData = [
'operationStatus' => $result->getStatus(),
'returnCode' => $result->getReturnCode(),
'profiles' => $result->getProfiles(),
];

return new ListProfilesResponse($this, $resultData);
}
}
23 changes: 23 additions & 0 deletions src/Messages/Backend/ListProfilesResponse.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?php

namespace Omnipay\Mpay24\Messages\Backend;

/**
* Lists matching profiles (customers).
*/

use Omnipay\Mpay24\Messages\AbstractMpay24Response;
use Omnipay\Mpay24\Messages\NotificationValuesTrait;

class ListProfilesResponse extends AbstractMpay24Response
{
use NotificationValuesTrait;

/**
* Returns an array of arrays containing "customerID" and "updated" elements.
*/
public function getProfiles()
{
return $this->getDataItem('profiles');
}
}
Loading

0 comments on commit 7804e58

Please sign in to comment.