Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Support payment orders upload #25

Open
wants to merge 5 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
22 changes: 20 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

[![Latest Stable Version](https://poser.pugx.org/mhujer/fio-api-php/version.png)](https://packagist.org/packages/mhujer/fio-api-php) [![Total Downloads](https://poser.pugx.org/mhujer/fio-api-php/downloads.png)](https://packagist.org/packages/mhujer/fio-api-php) [![License](https://poser.pugx.org/mhujer/fio-api-php/license.svg)](https://packagist.org/packages/mhujer/fio-api-php) [![Coverage Status](https://coveralls.io/repos/mhujer/fio-api-php/badge.svg?branch=master)](https://coveralls.io/r/mhujer/fio-api-php?branch=master)

Fio bank REST API implementation in PHP. It allows you to download and iterate through account balance changes.
Fio bank REST API implementation in PHP. It allows you to download and iterate through account balance changes. You can also upload payment orders.

[There is a Symfony Bundle](https://github.com/mhujer/fio-api-bundle) for using this library in a Symfony app.

Expand All @@ -12,11 +12,13 @@ Usage
2. Create a *token* in the ebanking (Nastavení / API)
3. Use it according to the example bellow and check the docblocks

### Download

```php
<?php
require_once 'vendor/autoload.php';

$downloader = new FioApi\Downloader('TOKEN@todo');
$downloader = new FioApi\Download\Downloader('TOKEN@todo');
$transactionList = $downloader->downloadSince(new \DateTimeImmutable('-1 week'));

foreach ($transactionList->getTransactions() as $transaction) {
Expand All @@ -31,6 +33,22 @@ foreach ($transactionList->getTransactions() as $transaction) {
- `downloadLast(): TransactionList`
- `setLastId(string $id)` - sets the last downloaded ID through the API

### Upload

```php
<?php
require_once 'vendor/autoload.php';

$uploader = new FioApi\Upload\Uploader('TOKEN@todo', 'accountFromWithoutBankCode@todo');
$uploader->addPaymentOrder(new FioApi\Upload\Entity\PaymentOrderCzech(...$params));
$response = $uploader->uploadPaymentOrders();
if ($response->hasUploadSucceeded()) {
// ...
}

```


Requirements
------------
Fio API PHP works with PHP 7.4 or higher.
Expand Down
3 changes: 3 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,9 @@
"require": {
"php": ">=7.4",
"ext-curl": "*",
"ext-mbstring": "*",
"ext-simplexml": "*",
"ext-xmlwriter": "*",
"guzzlehttp/guzzle": "~6.1|~7.0"
},
"require-dev": {
Expand Down
49 changes: 6 additions & 43 deletions src/FioApi/Downloader.php → src/FioApi/Download/Downloader.php
Original file line number Diff line number Diff line change
@@ -1,59 +1,22 @@
<?php
declare(strict_types = 1);

namespace FioApi;
namespace FioApi\Download;

use FioApi\Download\Entity\TransactionList;
use FioApi\Exceptions\InternalErrorException;
use FioApi\Exceptions\TooGreedyException;
use FioApi\Transferrer;
use GuzzleHttp\ClientInterface;
use Psr\Http\Message\ResponseInterface;

class Downloader
class Downloader extends Transferrer
{
/** @var UrlBuilder */
protected $urlBuilder;

/** @var \GuzzleHttp\Client */
protected $client;

/** @var string */
protected $certificatePath;

public function __construct(
string $token,
\GuzzleHttp\ClientInterface $client = null
ClientInterface $client = null
) {
$this->urlBuilder = new UrlBuilder($token);
$this->client = $client;
}

public function setCertificatePath(string $path)
{
$this->certificatePath = $path;
}

public function getCertificatePath(): string
{
if ($this->certificatePath) {
return $this->certificatePath;
}

if (class_exists('\Composer\CaBundle\CaBundle')) {
return \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
} elseif (class_exists('\Kdyby\CurlCaBundle\CertificateHelper')) {
return \Kdyby\CurlCaBundle\CertificateHelper::getCaInfoFile();
}

//Key downloaded from https://www.geotrust.com/resources/root-certificates/
return __DIR__ . '/keys/Geotrust_PCA_G3_Root.pem';
}

public function getClient(): ClientInterface
{
if (!$this->client) {
$this->client = new \GuzzleHttp\Client();
}
return $this->client;
parent::__construct($token, $client);
}

public function downloadFromTo(\DateTimeInterface $from, \DateTimeInterface $to): TransactionList
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types = 1);

namespace FioApi;
namespace FioApi\Download\Entity;

class Account
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types = 1);

namespace FioApi;
namespace FioApi\Download\Entity;

class Transaction
{
Expand Down
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<?php
declare(strict_types = 1);

namespace FioApi;
namespace FioApi\Download\Entity;

class TransactionList
{
Expand Down
9 changes: 9 additions & 0 deletions src/FioApi/Exceptions/MissingPaymentOrderException.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types = 1);

namespace FioApi\Exceptions;

class MissingPaymentOrderException extends \RuntimeException
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types = 1);

namespace FioApi\Exceptions;

class UnexpectedPaymentOrderClassException extends \UnexpectedValueException
{

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
<?php
declare(strict_types = 1);

namespace FioApi\Exceptions;

class UnexpectedPaymentOrderValueException extends \UnexpectedValueException
{

}
50 changes: 50 additions & 0 deletions src/FioApi/Transferrer.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,50 @@
<?php
declare(strict_types = 1);

namespace FioApi;

use GuzzleHttp\ClientInterface;

abstract class Transferrer
{
protected UrlBuilder $urlBuilder;
protected ?ClientInterface $client;
protected string $certificatePath;

protected function __construct(
string $token,
ClientInterface $client = null
) {
$this->urlBuilder = new UrlBuilder($token);
$this->client = $client;
}

public function setCertificatePath(string $path)
{
$this->certificatePath = $path;
}

public function getCertificatePath(): string
{
if (isset($this->certificatePath)) {
return $this->certificatePath;
}

if (class_exists('\Composer\CaBundle\CaBundle')) {
return \Composer\CaBundle\CaBundle::getSystemCaRootBundlePath();
} elseif (class_exists('\Kdyby\CurlCaBundle\CertificateHelper')) {
return \Kdyby\CurlCaBundle\CertificateHelper::getCaInfoFile();
}

//Key downloaded from https://www.geotrust.com/resources/root-certificates/
return __DIR__ . '/keys/Geotrust_PCA_G3_Root.pem';
}

public function getClient(): ClientInterface
{
if (isset($this->client) === false) {
$this->client = new \GuzzleHttp\Client();
}
return $this->client;
}
}
154 changes: 154 additions & 0 deletions src/FioApi/Upload/Entity/PaymentOrder.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,154 @@
<?php
declare(strict_types = 1);

namespace FioApi\Upload\Entity;

use FioApi\Exceptions\UnexpectedPaymentOrderValueException;

abstract class PaymentOrder
{
protected const CURRENCY_NAME = 'currency';
protected const AMOUNT_NAME = 'amount';
protected const ACCOUNT_TO_NAME = 'accountTo';
protected const DATE_NAME = 'date';
protected const COMMENT_NAME = 'comment';
protected const PAYMENT_REASON_NAME = 'paymentReason';
protected const PAYMENT_TYPE_NAME = 'paymentType';

protected const COMMENT_MAX_LENGTH = 255;
protected const PAYMENT_REASON_MIN = 100;
protected const PAYMENT_REASON_MAX = 999;

protected string $currency;
protected float $amount;
protected string $accountTo;
protected string $date;
protected string $comment;
protected int $paymentReason;

protected function __construct(
string $currency,
float $amount,
string $accountTo,
\DateTimeInterface $date,
?string $comment = null
) {
$this->setCurrency($currency)
->setAmount($amount)
->setAccountTo($accountTo)
->setDate($date);
if ($comment !== null) {
$this->setComment($comment);
}
}

public function toArray(): array {
return [
static::CURRENCY_NAME => $this->getCurrency(),
static::AMOUNT_NAME => $this->getAmount(),
static::ACCOUNT_TO_NAME => $this->getAccountTo(),
];
}

public abstract function getPaymentReason(): ?int;

public function getCurrency(): string
{
return $this->currency;
}

public function getAmount(): float
{
return $this->amount;
}

public function getAccountTo(): string
{
return $this->accountTo;
}

public function getDate(): string
{
return $this->date;
}

public function getComment(): ?string
{
return $this->comment ?? null;
}

/** @return static */
protected function setCurrency(string $currency)
{
if (!preg_match('/^[a-z]{3}$/i', $currency)) {
throw new UnexpectedPaymentOrderValueException('Currency code has to match ISO 4217.');
}
$this->currency = strtoupper($currency);
return $this;
}

/** @return static */
protected function setAmount(float $amount)
{
if ($amount <= 0) {
throw new UnexpectedPaymentOrderValueException('Amount has to be positive number.');
}
$this->amount = $amount;
return $this;
}

/** @return static */
protected function setAccountTo(string $accountTo)
{
$this->accountTo = static::validateAccountTo($accountTo);
return $this;
}

/** @return static */
protected function setDate(\DateTimeInterface $date)
{
$this->date = $date->format('Y-m-d');
return $this;
}

/** @return static */
protected function setComment(string $comment)
{
$this->comment = static::validateStringMaxLength($comment, static::COMMENT_MAX_LENGTH);
return $this;
}

/** @return static */
protected function setPaymentReason(int $paymentReason)
{
if ($paymentReason < self::PAYMENT_REASON_MIN || $paymentReason > self::PAYMENT_REASON_MAX) {
throw new UnexpectedPaymentOrderValueException(
sprintf('Payment reason "%s" is out of allowed range %s - %s.', $paymentReason, self::PAYMENT_REASON_MIN, self::PAYMENT_REASON_MAX)
);
}
$this->paymentReason = $paymentReason;
return $this;
}

abstract protected static function validateAccountTo(string $accountTo): string;

protected static function validateStringMaxLength(string $text, int $maxLength): string
{
if (mb_strlen($text) > $maxLength) {
throw new UnexpectedPaymentOrderValueException(
sprintf('Value "%s" has to contain %s characters at maximum.', $text, $maxLength)
);
}
return $text;
}

protected static function validateValueIsInList(int $value, array $list): int
{
if (in_array($value, $list, true) === false) {
throw new UnexpectedPaymentOrderValueException(
sprintf('Value "%s" is out of allowed set [%s].', $value, implode(', ', $list))
);
}
return $value;
}
}
Loading