feat: add route to calculate fees

This commit is contained in:
Djery-Tom 2023-07-12 20:27:10 +01:00
parent 457df41c9c
commit 81796c15bb
11 changed files with 332 additions and 4 deletions

11
app/Enums/PaymentType.php Normal file
View File

@ -0,0 +1,11 @@
<?php
namespace App\Enums;
abstract class PaymentType
{
const CASH_IN = 'CASH_IN'; // Les remboursements ou recharges vers des clients
const CASH_OUT = 'CASH_OUT'; // Les paiements effectués par les clients
}

View File

@ -3,6 +3,7 @@
namespace App\Http\Controllers;
use App\Enums\PaymentTransactionStatus;
use App\Models\Country;
use App\Models\PaymentAggregator;
use App\Models\PaymentTransaction;
use GuzzleHttp\Client;
@ -147,4 +148,59 @@ class PaymentController extends Controller
}
}
public function getFees(Request $request)
{
$this->validate($request, [
'amount' => 'required|numeric|min:0',
'country_id' => 'required|integer|exists:countries,id',
'payment_type' => 'required|string|in:CASH_IN,CASH_OUT',
'payment_method' => 'required|string|in:CARD,WALLET',
'payment_channel' => 'nullable|string',
]);
$fees = 0;
$amount = $request->input('amount');
$paymentChannel = $request->input('payment_channel');
$paymentMethod = $request->input('payment_method');
$paymentType = $request->input('payment_type');
$countryId = $request->input('country_id');
$country = Country::where('id', $countryId)->firstOrFail();
$countryCode = $country->code_country;
if($paymentMethod == 'CARD'){
$aggregator = PaymentAggregator::where('name','like','%stripe%')->first();
}
if($paymentMethod == 'WALLET'){
$aggregator = PaymentAggregator::where('status',1)->first();
}
if(!empty($aggregator)){
$rate = $aggregator->rates()->where('country', $countryCode)->orWhere('country','ALL')->where('type', $paymentType)
->where('method', $paymentMethod)->when($paymentChannel, function ($q) use($paymentChannel){
return $q->where('channel',$paymentChannel);
})->first();
if(!empty($rate)){
if(!empty($rate->fixed_fees)){
$targetCurrency = $country->currency->code;
$sourceCurrency = $targetCurrency;
if(!empty($rate->fixed_fees_currency)){
$sourceCurrency = $rate->fixed_fees_currency;
}
$fixed_fees = $this->toMoneyAmount($rate->fixed_fees, $sourceCurrency, $targetCurrency);
$fees = (($amount - $fixed_fees) * $rate->rate / 100 ) + $fixed_fees;
}else{
$fees = $amount * $rate->rate / 100;
}
}
return $this->successResponse(['fees' => round($fees, 2)]);
}else {
return $this->errorResponse("Aggregateur non disponible");
}
}
}

56
app/Models/Country.php Executable file
View File

@ -0,0 +1,56 @@
<?php
/**
* Created by Reliese Model.
*/
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
/**
* Class Country
*
* @property int $id
* @property string $code_dial
* @property string $name
* @property string $code_country
* @property float $longitude
* @property float $latitude
* @property int $idCurrency
*
* @property Currency $currency
* @property Collection|Admin[] $admins
* @property Collection|ConfigGame[] $config_games
* @property Collection|Identification[] $identifications
* @property Collection|WalletIlinkTransaction[] $wallet_ilink_transactions
*
* @package App\Models
*/
class Country extends Model
{
protected $table = 'countries';
public $timestamps = false;
protected $guarded = ['id'];
protected $casts = [
'longitude' => 'float',
'latitude' => 'float',
'idCurrency' => 'int'
];
protected $fillable = [
'code_dial',
'name',
'code_country',
'longitude',
'latitude',
'idCurrency'
];
public function currency()
{
return $this->belongsTo(Currency::class, 'idCurrency');
}
}

47
app/Models/Currency.php Normal file
View File

@ -0,0 +1,47 @@
<?php
/**
* Created by Reliese Model.
*/
namespace App\Models;
use Illuminate\Database\Eloquent\Collection;
use Illuminate\Database\Eloquent\Model;
/**
* Class Currency
*
* @property int $id
* @property string $code
* @property int $numeric
* @property string $symbol
* @property string $name_en
* @property string $name_fr
*
* @property Collection|Country[] $countries
*
* @package App\Models
*/
class Currency extends Model
{
protected $table = 'currencies';
public $timestamps = false;
protected $casts = [
'numeric' => 'int'
];
protected $fillable = [
'code',
'numeric',
'symbol',
'name_en',
'name_fr'
];
public function countries()
{
return $this->hasMany(Country::class, 'idCurrency');
}
}

View File

@ -8,4 +8,8 @@ class PaymentAggregator extends Model
{
protected $table = 'payment_aggregators';
protected $guarded = ['id'];
public function rates(){
return $this->hasMany(PaymentAggregatorRate::class,'aggregator_id');
}
}

View File

@ -0,0 +1,12 @@
<?php
namespace App\Models;
use Illuminate\Database\Eloquent\Model;
class PaymentAggregatorRate extends Model
{
//
protected $table = 'payment_aggregator_rates';
protected $guarded = ['id'];
}

View File

@ -3,7 +3,17 @@
namespace App\Traits;
use App\Models\Country;
use Brick\Math\RoundingMode;
use Brick\Money\Context\AutoContext;
use Brick\Money\Context\CashContext;
use Brick\Money\CurrencyConverter;
use Brick\Money\ExchangeRateProvider\BaseCurrencyProvider;
use Brick\Money\ExchangeRateProvider\PDOProvider;
use Brick\Money\ExchangeRateProvider\PDOProviderConfiguration;
use Brick\Money\Money;
use Illuminate\Support\Facades\DB;
use PDO;
trait Helper
{
@ -18,8 +28,40 @@ trait Helper
}
// Convertir vers le multiple de 5 le plus proche
function roundUpToAny($n,$x=5) {
return (ceil($n)%$x === 0) ? ceil($n) : round(($n+$x/2)/$x)*$x;
function roundUpToAny($n, $x = 5)
{
return (ceil($n) % $x === 0) ? ceil($n) : round(($n + $x / 2) / $x) * $x;
}
private function convertMoney($amount, $sourceCurrency, $targetCurrency)
{
// set to whatever your rates are relative to
$baseCurrency = 'USD';
// use your own credentials, or re-use your existing PDO connection
$pdo = new PDO('mysql:host=' . env('DB_HOST') . ';dbname=' . env('DB_DATABASE'), env('DB_USERNAME'), env('DB_PASSWORD'));
$configuration = new PDOProviderConfiguration(
tableName: 'exchange_rate',
exchangeRateColumnName: 'exchange_rate',
sourceCurrencyCode: $baseCurrency,
targetCurrencyColumnName: 'target_currency'
);
// this provider loads exchange rates from your database
$provider = new PDOProvider($pdo, $configuration);
// this provider calculates exchange rates relative to the base currency
$provider = new BaseCurrencyProvider($provider, $baseCurrency);
$converter = new CurrencyConverter($provider);
$sourceMoney = Money::of(round($amount, 2), $sourceCurrency, new AutoContext());
return $converter->convert($sourceMoney, $targetCurrency, null, RoundingMode::UP);
}
public function toMoneyAmount($amount, $sourceCurrency, $targetCurrency)
{
return $this->convertMoney($amount, $sourceCurrency, $targetCurrency)->getAmount()->toFloat();
}
}

View File

@ -7,6 +7,7 @@
"require": {
"php": "^8.0",
"ext-json": "*",
"brick/money": "^0.8.0",
"cknow/laravel-money": "^7.0",
"darkaonline/swagger-lume": "^9.0",
"doctrine/dbal": "^3.6",
@ -15,7 +16,8 @@
"illuminate/session": "^9.52",
"laravel/lumen-framework": "^9.0",
"propaganistas/laravel-phone": "^5.0",
"stripe/stripe-php": "^10.13"
"stripe/stripe-php": "^10.13",
"ext-pdo": "*"
},
"require-dev": {
"fakerphp/faker": "^1.9.1",

60
composer.lock generated
View File

@ -4,7 +4,7 @@
"Read more about it at https://getcomposer.org/doc/01-basic-usage.md#installing-dependencies",
"This file is @generated automatically"
],
"content-hash": "81090437c0e646c7e1df7fd291f0a3ac",
"content-hash": "4835260236c50e25a136ef532dcb5875",
"packages": [
{
"name": "brick/math",
@ -61,6 +61,64 @@
],
"time": "2023-01-15T23:15:59+00:00"
},
{
"name": "brick/money",
"version": "0.8.0",
"source": {
"type": "git",
"url": "https://github.com/brick/money.git",
"reference": "b530ab64d7f85fdfd5858cde8c57f2f587c8aab8"
},
"dist": {
"type": "zip",
"url": "https://api.github.com/repos/brick/money/zipball/b530ab64d7f85fdfd5858cde8c57f2f587c8aab8",
"reference": "b530ab64d7f85fdfd5858cde8c57f2f587c8aab8",
"shasum": ""
},
"require": {
"brick/math": "~0.10.1 || ~0.11.0",
"ext-json": "*",
"php": "^8.0"
},
"require-dev": {
"brick/varexporter": "~0.3.0",
"ext-dom": "*",
"ext-pdo": "*",
"php-coveralls/php-coveralls": "^2.2",
"phpunit/phpunit": "^9.4.3",
"vimeo/psalm": "5.4.0"
},
"suggest": {
"ext-intl": "Required to format Money objects"
},
"type": "library",
"autoload": {
"psr-4": {
"Brick\\Money\\": "src/"
}
},
"notification-url": "https://packagist.org/downloads/",
"license": [
"MIT"
],
"description": "Money and currency library",
"keywords": [
"brick",
"currency",
"money"
],
"support": {
"issues": "https://github.com/brick/money/issues",
"source": "https://github.com/brick/money/tree/0.8.0"
},
"funding": [
{
"url": "https://github.com/BenMorel",
"type": "github"
}
],
"time": "2023-01-15T23:59:01+00:00"
},
{
"name": "cknow/laravel-money",
"version": "v7.1.0",

View File

@ -0,0 +1,39 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
return new class extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('payment_aggregator_rates', function (Blueprint $table) {
$table->id();
$table->string('aggregator_id');
$table->string('country')->comment("ALL : Pour tous les pays");
$table->string('type')->comment("Cash In or Cash Out");
$table->string('method')->comment("Methode de paiements");
$table->string('channel')->nullable()->comment("Canal ou Reseau concerné");
$table->decimal('rate')->default(0)->comment("Taux de commission");
$table->decimal('fixed_fees')->nullable()->comment("Frais fixe");
$table->string('fixed_fees_currency')->nullable()->comment("Monnaie des frais fixes");
$table->timestamps();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('payment_aggregator_rates');
}
};

View File

@ -53,6 +53,7 @@ $router->group(['middleware' => 'auth'], function () use ($router) {
$router->post('pay','PaymentController@pay');
$router->get('checkStatus/{transaction_id}','PaymentController@checkStatus');
$router->post('payOut','PaymentController@payOut');
$router->get('fees','PaymentController@getFees');
/**
* Yoomee Endpoints