Skip to content

Commit

Permalink
First commit
Browse files Browse the repository at this point in the history
  • Loading branch information
rawahamid committed Apr 27, 2023
0 parents commit 12460f3
Show file tree
Hide file tree
Showing 9 changed files with 343 additions and 0 deletions.
19 changes: 19 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
/.phpunit.cache
/node_modules
/public/build
/public/hot
/public/storage
/storage/*.key
/vendor
.env
.env.backup
.env.production
.phpunit.result.cache
Homestead.json
Homestead.yaml
auth.json
npm-debug.log
yarn-error.log
/.fleet
/.idea
/.vscode
117 changes: 117 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,117 @@
# Laravel FIB Integration

Laravel integration for first iraqi bank payment

## Features
- Authentication
- Payment Creation
- Checking payment status
- Payment Cancellation

## Installation

You can install the package through Composer
```bash
composer require rawahamid/laravel-fib-integration
```

Then publish the config file of the package using the vendor publish command
```bash
php artisan vendor:publish --tag="fib"
```

## Configuration variables
All that is left to do is to define four env configuration variables inside `.env` file
```dotenv
FIB_ENVIRONMENT="staging"
FIB_CALLBACK_URL="https://localhost:8000/fib-callback-url"
FIB_CLIENT_ID="client-id"
FIB_CLIENT_SECRET="client-secret"
```

- `FIB_ENVIRONMENT` This value is the environment that you want to choose for FIB integration to your application
- `FIB_CALLBACK_URL` The callback url that FIB will send a POST request to when status of the created payment changes
- `FIB_CLIENT_ID` The account client id you use to authenticate the request determines whether the request is live mode or test mode
- `FIB_CLIENT_SECRET` The account client secret you use to authenticate the request determines whether the request is live mode or test mode

## Usage

#### Payment Creation
```php
use Rawahamid\FibIntegration\Payments\FibPayment;

$response = FibPayment::create(100);
```

Response structure
```json
{
"paymentId": "string",
"readableCode": "string",
"qrCode": "base64 string",
"validUntil": "datetime",
"personalAppLink": "link",
"businessAppLink": "link",
"corporateAppLink": "link"
}
```
- `paymentId` A unique identifier of the payment, used later to check the status.
- `readableCode` A payment code that the user can enter manually in case he cannot scan the QR code.
- `qrCode` A base64-encoded data URL of the QR code image that the user can scan with the FIB mobile app.
- `validUntil` an ISO-8601-formatted date-time string, representing a moment in time when the payment expires
- `personalAppLink` A link that the user can tap on his mobile phone to go to the corresponding payment screen in the FIB Personal app
- `businessAppLink` A link that the user can tap on his mobile phone to go to the corresponding payment screen in the FIB Business app
- `corporateAppLink` A link that the user can tap on his mobile phone to go to the corresponding payment screen in the FIB Corporate app

#### Payment Status
```php
use Rawahamid\FibIntegration\Payments\FibPayment;

$response = FibPayment::status('payment-uuid');
```
Response structure will be:
```json
{
"paymentId": "string",
"status": "string",
"validUntil": "string",
"amount": {
"amount": "number",
"currency": "string"
},
"decliningReason": "string",
"declinedAt": "string",
"paidBy": {
"name": "string",
"iban": "string"
}
}
```
- `paymentId` A unique identifier of the payment, used later to check the status.
- `status` one of these values: `PAID` | `UNPAID` | `DECLINED`
- `validUntil` an ISO-8601-formatted date-time string, representing a moment in time when the payment expires
- `amount` contains payment amount and its currency
- `decliningReason` can be nullable or one of these values `SERVER_FAILURE` | `PAYMENT_EXPIRATION` | `PAYMENT_CANCELLATION`
- `declinedAt` datetime that represents the time of payment decline
- `paidBy` is nullable object if the payment is still not paid but if paid will contain the name and iban of the user

#### Payment Cancel
```php
use Rawahamid\FibIntegration\Payments\FibPayment;

$response = FibPayment::cancel('payment-uuid');
```
response will be empty if success

## IMPORTANT NOTE**
In every request of these if the response is 500 mean the creation, status or cancellation request something wrong happened

## License

The FIB Integration package is open source software licensed under the [License MIT](https://choosealicense.com/licenses/mit/)

## Contributing
Contributions are always welcome!

## Report & Feedback
If you face any problem feel free to contact me :) [rawahamid](mailto://[email protected])
34 changes: 34 additions & 0 deletions composer.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "rawahamid/laravel-fib-integration",
"description": "Laravel FIB Integration",
"keywords": ["fib", "integration", "laravel-fib-integration"],
"type": "library",
"require": {
"php": ">=8.2",
"laravel/framework": ">=10.0"
},
"license": "MIT",
"autoload": {
"psr-4": {
"Rawahamid\\FibIntegration\\": "src/"
}
},
"extra": {
"laravel": {
"providers": [
"Rawahamid\\FibIntegration\\FibIntegrationServiceProvider"
]
}
},
"authors": [
{
"name": "Rawa Hamid",
"email": "[email protected]"
}
],
"config": {
"sort-packages": true
},
"minimum-stability": "dev",
"prefer-stable": true
}
36 changes: 36 additions & 0 deletions config/fib.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

return [
/*
|--------------------------------------------------------------------------
| Integration Environment
|--------------------------------------------------------------------------
|
| This value is the environment that you want to choose for FIB integration to your application.
| values are (staging, production)
|
*/
'environment' => env('FIB_ENVIRONMENT', 'stage'),

/*
|--------------------------------------------------------------------------
| Callback URL
|--------------------------------------------------------------------------
|
| The callback url that FIB will send a POST request to when status of the created payment changes.
| Callback URL should be able to handle POST requests with request body that contains two properties: id and status
*/
'callback_url' => env('FIB_CALLBACK_URL', 'http://127.0.0.1:8000'),

/*
|--------------------------------------------------------------------------
| Client ID
|--------------------------------------------------------------------------
|
| The account credentials you use to authenticate the request determines whether the request is live mode or test mode
| FIB will provide it for you
*/
'client_id' => env('FIB_CLIENT_ID'),

'client_secret' => env('FIB_CLIENT_SECRET'),
];
36 changes: 36 additions & 0 deletions src/FIB.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
<?php

namespace Rawahamid\FibIntegration;

use Illuminate\Http\JsonResponse;
use Symfony\Component\CssSelector\Exception\InternalErrorException;

class Fib
{
protected static function baseUrl(): string
{
return match (config('fib.environment')) {
'production' => 'https://fib.prod.fib.iq',
default => 'https://fib.stage.fib.iq'
};
}

protected static function checkResponse($response, $message = 'Internal Server Error')
{
if ($response->failed()) {
throw new InternalErrorException($message, JsonResponse::HTTP_INTERNAL_SERVER_ERROR);
}

return $response->json();
}

protected static function trimDescription($description)
{
if (strlen($description) > 50) {
$description = substr($description, 0, 50 - 3);
$description .= '...';
}

return $description;
}
}
13 changes: 13 additions & 0 deletions src/FibIntegration.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
<?php

namespace Rawahamid\FibIntegration;

use Illuminate\Support\Facades\Facade;

class FibIntegration extends Facade
{
public static function getFacadeAccessor(): string
{
return 'laravel-fib-integration';
}
}
20 changes: 20 additions & 0 deletions src/FibIntegrationServiceProvider.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<?php

namespace Rawahamid\FibIntegration;

use Illuminate\Support\ServiceProvider;

class FibIntegrationServiceProvider extends ServiceProvider
{
public function register(): void
{
//
}

public function boot(): void
{
$this->publishes([
__DIR__.'/../config/fib.php' => config_path('fib.php'),
], ['fib']);
}
}
14 changes: 14 additions & 0 deletions src/Interfaces/PaymentInterface.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
<?php

namespace Rawahamid\FibIntegration\Interfaces;

interface PaymentInterface
{
public static function authenticate();

public static function create($amount, $description);

public static function status($paymentId);

public static function cancel($paymentId);
}
54 changes: 54 additions & 0 deletions src/Payments/FibPayment.php
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
<?php

namespace Rawahamid\FibIntegration\Payments;

use Illuminate\Support\Facades\Http;
use Rawahamid\FibIntegration\Fib;
use Rawahamid\FibIntegration\Interfaces\PaymentInterface;

class FibPayment extends Fib implements PaymentInterface
{
public static function authenticate()
{
$response = Http::asForm()->post(self::baseUrl() . '/auth/realms/fib-online-shop/protocol/openid-connect/token', [
'grant_type' => 'client_credentials',
'client_id' => config('fib.client_id'),
'client_secret' => config('fib.client_secret'),
]);

return self::checkResponse($response, 'Payment Creation Failed');
}

public static function create($amount, $description = '')
{
$description = self::trimDescription($description);

$response = Http::withToken(self::authenticate()['access_token'])
->post(self::baseUrl() . '/protected/v1/payments', [
'monetaryValue' => [
'amount' => $amount,
'currency' => 'IQD',
],
'statusCallbackUrl' => config('fib.callback_url'),
'description' => $description,
]);

return self::checkResponse($response, 'Payment Creation Failed');
}

public static function cancel($paymentId)
{
$response = Http::withToken(self::authenticate()['access_token'])
->post(self::baseUrl() . '/protected/v1/payments/'.$paymentId.'/cancel');

return self::checkResponse($response, 'Cancel Payment Failed');
}

public static function status($paymentId)
{
$response = Http::withToken(self::authenticate()['access_token'])
->get(self::baseUrl() . '/protected/v1/payments/'.$paymentId.'/status');

return self::checkResponse($response, 'Check Payment Status Failed');
}
}

0 comments on commit 12460f3

Please sign in to comment.