finish with debit operation

This commit is contained in:
root 2026-02-24 14:03:58 +01:00
parent 313507835c
commit f82fd804a2
4 changed files with 337 additions and 118 deletions

View File

@ -55,3 +55,5 @@ BANK_API_BRANCH_CODE=99001
BANK_API_LOGIN=admin BANK_API_LOGIN=admin
BANK_API_PASSWORD=admin BANK_API_PASSWORD=admin
BANK_API_OPERATION_TYPE_CODE=MOMODE
BANK_API_CUSTOMER_REL_CODE=399

View File

@ -15,7 +15,7 @@ use Illuminate\Http\Request;
use Illuminate\Http\Response; use Illuminate\Http\Response;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log; use Illuminate\Support\Facades\Log;
use App\Mail\BankAccountCreatedMail; use App\Mail\BankAccountLinked;
use App\Mail\BankAccountActivated; use App\Mail\BankAccountActivated;
use App\Models\CustomerAccountType; use App\Models\CustomerAccountType;
use Illuminate\Support\Facades\Mail; use Illuminate\Support\Facades\Mail;
@ -898,7 +898,7 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON
'identificationNumber' => $bank_account->identification_number, 'identificationNumber' => $bank_account->identification_number,
'paySlip' => $request->doc_front, 'paySlip' => $request->doc_front,
'signatureCard' => $request->doc_back, 'signatureCard' => $request->doc_back,
'custRelCode' => '399' 'custRelCode' => env('BANK_API_CUSTOMER_REL_CODE', '399')
]; ];
try { try {
@ -944,7 +944,7 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON
LOG::info(' Compte activé avec succès ! Numero du compte bancaire du User : ' . $user->id . ' : ' . ($user->iban ?? 'N/A')); LOG::info(' Compte activé avec succès ! Numero du compte bancaire du User : ' . $user->id . ' : ' . ($user->iban ?? 'N/A'));
try { try {
// Mail::to($user->email)->send(new BankAccountActivated($bank_account, $name_of_account_type)); Mail::to($user->email)->send(new BankAccountActivated($bank_account, $name_of_account_type));
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error("Mail error lors de l'activation: " . $e->getMessage()); Log::error("Mail error lors de l'activation: " . $e->getMessage());
return $this->successResponse(trans('messages.user_bank_account_activated_successfully', ['bank' => 'SunEx','account_number' => $bank_account->account_number]), 200); return $this->successResponse(trans('messages.user_bank_account_activated_successfully', ['bank' => 'SunEx','account_number' => $bank_account->account_number]), 200);
@ -1045,24 +1045,27 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON
Log::info('Compte bancaire rattaché avec succès pour transaction: ' . $request->id_transaction); Log::info('Compte bancaire rattaché avec succès pour transaction: ' . $request->id_transaction);
try { try {
// Mail::to($user->email)->send(new BankAccountLinked($user_bank_account_verfication)); Mail::to($user->email)->send(new BankAccountLinked($user_bank_account_verfication));
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error("Mail error: " . $e->getMessage()); Log::error("Mail error: " . $e->getMessage());
return $this->successResponse(trans('messages.create_bank_account_linked_successfully'), 200);
} }
return $this->successResponse(trans('messages.create_bank_account_linked_successfully'), 200); return $this->successResponse(trans('messages.create_bank_account_linked_successfully'), 200);
} }
} catch (RequestException $e) { } catch (RequestException $e) {
$errorBody = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage(); $errorBody = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage();
$decodedBody = json_decode($errorBody, true);
$extractedMessage = $decodedBody['message'] ?? $errorBody;
$user_bank_account_verfication->update([ $user_bank_account_verfication->update([
'is_verified' => 2, 'is_verified' => 2,
'was_traited' => 0, 'was_treated' => 0,
]); ]);
Log::error('Erreur API Bank Link pour transaction ' . $request->id_transaction . ' : ' . $errorBody); Log::error('Erreur API Bank Link pour transaction ' . $request->id_transaction . ' : ' . $extractedMessage);
return $this->errorResponse(trans('errors.Error_occurred')); return $this->errorResponse('Account: '. $request->iban . ', ' . $extractedMessage ?? trans('errors.Error_occurred'), 500);
} catch (\Exception $e) { } catch (\Exception $e) {
Log::error('Erreur inattendue Bank Link : ' . $e->getMessage()); Log::error('Erreur inattendue Bank Link : ' . $e->getMessage());
return $this->errorResponse(trans('errors.Error_occurred')); return $this->errorResponse(trans('errors.Error_occurred'));

View File

@ -625,16 +625,14 @@ class iLinkTransactionController extends Controller
'id_wallet_network' => 'required|integer|min:0|not_in:0', 'id_wallet_network' => 'required|integer|min:0|not_in:0',
'montant' => 'required|numeric|min:0', 'montant' => 'required|numeric|min:0',
]); ]);
$response_message = '';
$user = $walletUser->user; $user = $walletUser->user;
$this->validatePassword($request->password, $user->encrypted_password, $user->salt); $this->validatePassword($request->password, $user->encrypted_password, $user->salt);
$this->checkUserIdentification($user->id); $this->checkUserIdentification($user->id);
$userBankAccountVerification = UsersBankingAccountVerification::where('user_code', $user->user_code) // Vérification des prérequis
->first();
$accountNumber = $user->iban; $accountNumber = $user->iban;
if (!$accountNumber || !$user->id_bank_country) {
if ((!$accountNumber || !$user->id_bank_country) && !$userBankAccountVerification) {
throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422); throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422);
} }
@ -642,7 +640,6 @@ class iLinkTransactionController extends Controller
throw new Exception(trans('errors.insufficient_balance'), 422); throw new Exception(trans('errors.insufficient_balance'), 422);
} }
// Vérification de l'opérateur réseau
$network_bank = NetworksOperator::where('id_network', $request->id_wallet_network) $network_bank = NetworksOperator::where('id_network', $request->id_wallet_network)
->where('id_operator_country', $user->id_bank_country) ->where('id_operator_country', $user->id_bank_country)
->first(); ->first();
@ -651,7 +648,24 @@ class iLinkTransactionController extends Controller
throw new Exception(trans('errors.not_banking_operator')); throw new Exception(trans('errors.not_banking_operator'));
} }
// Préparation des données de transaction // Récupération du matricule (Customer Code)
$verification = UsersBankingAccountVerification::where('user_code', $user->user_code)
->where('account_number', $accountNumber)->first();
$accountInfo = UserBankAccount::where('id_user', $user->id)
->where('account_number', $accountNumber)->first();
if ($verification) {
$customer_code = $verification->iban;
} elseif ($accountInfo) {
$customer_code = $accountInfo->customer_number;
} else {
throw new Exception(trans('errors.bank_account_not_found'), 422);
}
$bankName = $network_bank->operators_country->operator->nom;
$countryName = $network_bank->operators_country->country->name;
// Préparation de la transaction
$transaction->id_transaction = $this->getTransactionID(); $transaction->id_transaction = $this->getTransactionID();
$transaction->montant = $request->montant; $transaction->montant = $request->montant;
$transaction->frais = 0; $transaction->frais = 0;
@ -660,54 +674,62 @@ class iLinkTransactionController extends Controller
$transaction->prenom_emetteur = $user->firstname; $transaction->prenom_emetteur = $user->firstname;
$transaction->email_emetteur = $user->email; $transaction->email_emetteur = $user->email;
$transaction->network_emetteur = $network_bank->id_network; $transaction->network_emetteur = $network_bank->id_network;
$transaction->bank = $network_bank->operators_country->operator->nom; $transaction->init_country = 38;
$transaction->country = $network_bank->operators_country->country->name; $transaction->final_country = 38;
$transaction->iban = $accountNumber; $transaction->bank_account_number = $accountNumber;
$transaction->bank_name = $bankName;
$transaction->date = $this->getCurrentTime($init_country); $transaction->date = $this->getCurrentTime($init_country);
$transaction->status = 'PENDING';
// --- DÉBUT DE LA TRANSACTION DB --- // --- DÉBUT DE LA TRANSACTION DB ---
DB::beginTransaction();
try { try {
// Débit provisoire du Wallet // Débit provisoire du Wallet
$oldBalance = $walletUser->balance;
$walletUser->balance -= $transaction->montant; $walletUser->balance -= $transaction->montant;
$walletUser->save(); $walletUser->save();
$transaction->save();
$baseUrl = env('BANK_API_BASE_URL'); $baseUrl = env('BANK_API_BASE_URL');
$client = new Client(['connect_timeout' => 60]); $client = new Client(['connect_timeout' => 60]);
// Authentification (Bearer Token)
$authResponse = $client->post($baseUrl . '/auth/authenticate', [ $authResponse = $client->post($baseUrl . '/auth/authenticate', [
'json' => ['login' => env('BANK_API_LOGIN'), 'password' => env('BANK_API_PASSWORD')] 'json' => ['login' => env('BANK_API_LOGIN'), 'password' => env('BANK_API_PASSWORD')]
]); ]);
$token = json_decode($authResponse->getBody(), true)['data']['token'] ?? null;
$authData = json_decode($authResponse->getBody(), true);
$token = $authData['data']['token'] ?? null;
if (!$token) throw new Exception(trans('errors.token_not_found')); if (!$token) throw new Exception(trans('errors.token_not_found'));
// Disbursement Payload // Appel API Disbursement
$payload = [ $apiResponse = $client->post($baseUrl . '/account/disbursement', [
"clientMatricule" => $userBankAccountVerification->iban, 'headers' => ['Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json'],
"crAccountId" => $accountNumber, 'json' => [
"clientMatricule" => (string)$customer_code,
"crAccountId" => (string)$accountNumber,
"description" => "Credit wallet sunEx vers compte bancaire", "description" => "Credit wallet sunEx vers compte bancaire",
"operationDate" => $transaction->date, "operationDate" => $transaction->date,
"operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE' ), "operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE'),
"traceNo" => $transaction->id_transaction, "traceNo" => $transaction->id_transaction,
"transactionAmt" => (float)$transaction->montant "transactionAmt" => (float)$transaction->montant
]; ]
$apiResponse = $client->post($baseUrl . '/account/disbursement', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
],
'json' => $payload
]); ]);
$result = json_decode($apiResponse->getBody(), true); $result = json_decode($apiResponse->getBody(), true);
if ($apiResponse->getStatusCode() <= 301 && ($result['success'] ?? true) != false) { // Analyse de la réponse
$transaction->canceled = 0; if ($apiResponse->getStatusCode() <= 301 && isset($result['message']) && $result['message'] == 'Success') {
// Sécurisation des données de retour
$apiData = $result['data'] ?? [];
$transaction->status = 'Success';
$transaction->payment_transaction_id = $apiData['transactionId'] ?? null;
$transaction->save(); $transaction->save();
DB::commit();
if(isset($accountInfo)){
$accountInfo->balance = $apiData['realBalance'] ?? $accountInfo->balance;
$accountInfo->save();
}
// Envoi Mail // Envoi Mail
$message = trans('messages.successful_user_send_to_bank', [ $message = trans('messages.successful_user_send_to_bank', [
@ -716,20 +738,42 @@ class iLinkTransactionController extends Controller
'iban' => $accountNumber, 'iban' => $accountNumber,
'net' => $this->toMoney($transaction->montant, $init_country), 'net' => $this->toMoney($transaction->montant, $init_country),
'sender_code' => $user->user_code, 'sender_code' => $user->user_code,
'country' => $network_bank->operators_country->country->name, 'country' => $countryName,
'bank' => $network_bank->operators_country->operator->nom 'bank' => $bankName
]); ]);
$this->sendMail($user->email, trans('messages.successful_transaction'), $message);
Log::info("SUCCESS: Wallet to Bank - Trx: " . $transaction->id_transaction); // Log de succès
$this->sendMail($user->email, trans('messages.successful_transaction'), $message);
Log::info($result['data']['outMessage']. ' Transaction ID: ' . $result['data']['transactionId'].' Bank Account: ' . $result['data']['accountId'] . ' -Wallet New Balance: ' . $walletUser->balance.' -Old Wallet Balance: ' . $oldBalance);
$response_message =
(($apiData['outMessage'] ?? 'Success') .
' | ID: ' . ($apiData['transactionId'] ?? 'N/A') .
' | Bank New Balance: ' . ($apiData['realBalance'] ?? 'N/A'));
} else { } else {
throw new Exception("API Bank Refused: " . $apiResponse->getBody()); // La banque a refusé l'opération
DB::rollBack();
// Optionnel : Enregistrer l'échec en base (nécessite une nouvelle instance car le rollback a tout annulé)
Log::warning("BANK REFUSED: " . ($result['message'] ?? 'Unknown error'));
return $this->errorResponse($result['message'] ?? trans('errors.Error_occurred'), 400);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
DB::rollBack(); DB::rollBack();
Log::error("FAILED: Wallet to Bank - Error: " . $e->getMessage()); $errorMessage = $e->getMessage();
throw new Exception(trans('errors.bank_api_exception'), 500);
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
$body = (string) $response->getBody();
$result = json_decode($body, true);
if (isset($result['message'])) {
$errorMessage = $result['message'];
}
}
Log::error("CRITICAL ERROR Wallet2Bank: " . $errorMessage);
return $this->errorResponse($errorMessage, 500);
} }
break; break;
// case 5: //User - Envoi de carte à wallet // case 5: //User - Envoi de carte à wallet
@ -1599,14 +1643,16 @@ class iLinkTransactionController extends Controller
'prenom_destinataire' => 'required', 'prenom_destinataire' => 'required',
]); ]);
$response_message = '';
$agent = AgentPlus::findOrFail($network_agent->agent_id); $agent = AgentPlus::findOrFail($network_agent->agent_id);
$this->validatePassword($request->password, $agent->encrypted_password, $agent->salt); $this->validatePassword($request->password, $agent->encrypted_password, $agent->salt);
// Vérifications de solde et réseau // 1. Vérifications de solde
if ($request->montant > $walletAgent->balance_princ) { if ($request->montant > $walletAgent->balance_princ) {
throw new Exception(trans('errors.insufficient_balance'), 422); throw new Exception(trans('errors.insufficient_balance'), 422);
} }
// 2. Vérification réseau et banque
$network_bank = NetworksOperator::where('id_network', $request->id_wallet_network) $network_bank = NetworksOperator::where('id_network', $request->id_wallet_network)
->where('id_operator_country', $request->id_bank) ->where('id_operator_country', $request->id_bank)
->first(); ->first();
@ -1615,7 +1661,34 @@ class iLinkTransactionController extends Controller
throw new Exception(trans('errors.bank_not_associated_with_network')); throw new Exception(trans('errors.bank_not_associated_with_network'));
} }
// Préparation des données de la transaction // Récupération du matricule (Customer Code)
$accountInfo = UserBankAccount::where('account_number', $request->iban)->first();
$verification = UsersBankingAccountVerification::where('account_number', $request->iban)->first();
if ($verification) {
$client_matricule = $verification->iban;
$beneficiary_user = User::where('user_code', $verification->user_code)->first();
} elseif ($accountInfo) {
$client_matricule = $accountInfo->customer_number;
$beneficiary_user = User::where('id', $accountInfo->id_user)->first();
} else {
throw new Exception(trans('errors.bank_account_not_found'), 422);
}
if (!$beneficiary_user) {
throw new Exception(trans('errors.user_not_found'), 422);
}
if (!$beneficiary_user->iban && !$beneficiary_user->id_bank_country) {
throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422);
}
$accout_number = $beneficiary_user->iban;
// Préparation des variables de texte
$bankName = $network_bank->operators_country->operator->nom;
$countryName = $network_bank->network->country->name;
// 4. Préparation de la transaction
$transaction->id_transaction = $this->getTransactionID(); $transaction->id_transaction = $this->getTransactionID();
$transaction->montant = $request->montant; $transaction->montant = $request->montant;
$transaction->frais = 0; $transaction->frais = 0;
@ -1635,37 +1708,39 @@ class iLinkTransactionController extends Controller
$transaction->nom_destinataire = $request->nom_destinataire; $transaction->nom_destinataire = $request->nom_destinataire;
$transaction->prenom_destinataire = $request->prenom_destinataire; $transaction->prenom_destinataire = $request->prenom_destinataire;
$transaction->bank = $network_bank->operators_country->operator->nom; $transaction->bank_name = $bankName;
$transaction->country = $network_bank->network->country->name; $transaction->init_country = 38;
$transaction->id_bank = $request->id_bank; $transaction->final_country = 38;
$transaction->iban = $request->iban; $transaction->bank_account_number = $accout_number;
$transaction->date = $this->getCurrentTime($init_country); $transaction->date = $this->getCurrentTime($init_country);
$receiver_client_matricule = UserBankAccount::where('iban', $request->iban)->first()->customer_number ?? null; $transaction->status = 'PENDING';
// --- DÉBUT DE LA TRANSACTION DB ---
DB::beginTransaction();
try { try {
// Débit du compte Agent (balance_princ car c'est une opération Cash) // Débit provisoire du Wallet Agent
$oldBalance = $walletAgent->balance_princ;
$walletAgent->balance_princ -= $transaction->montant; $walletAgent->balance_princ -= $transaction->montant;
$walletAgent->save(); $walletAgent->save();
$transaction->save();
$baseUrl = env('BANK_API_BASE_URL'); $baseUrl = env('BANK_API_BASE_URL');
$client = new Client(['connect_timeout' => 60]); $client = new Client(['connect_timeout' => 60]);
// Authentification Bearer // Authentification Bearer
$authResponse = $client->post($baseUrl . '/auth/authenticate', [ $authResponse = $client->post($baseUrl . '/auth/authenticate', [
'json' => ['login' => env('BANK_API_LOGIN'), 'password' => env('BANK_API_PASSWORD')] 'json' => [
'login' => env('BANK_API_LOGIN'),
'password' => env('BANK_API_PASSWORD')
]
]); ]);
$token = json_decode($authResponse->getBody(), true)['data']['token'] ?? null; $authData = json_decode($authResponse->getBody(), true);
$token = $authData['data']['token'] ?? null;
if (!$token) throw new Exception(trans('errors.token_not_found')); if (!$token) throw new Exception(trans('errors.token_not_found'));
// Payload de décaissement (Disbursement) // Payload de décaissement
// Note: Ici le clientMatricule est souvent un matricule système ou celui de l'agent
// s'il possède un compte banque rattaché.
$payload = [ $payload = [
"clientMatricule" => $receiver_client_matricule, // Matricule receveur "clientMatricule" => (string)$client_matricule,
"crAccountId" => $request->iban, //Numero de compte bancaire receveur "crAccountId" => (string)$accout_number,
"description" => "Transfert Cash vers Banque - Emetteur: " . $request->prenom_emetteur . ' ' . $request->nom_emetteur, "description" => "Transfert Cash vers Banque - Emetteur: " . $request->prenom_emetteur . ' ' . $request->nom_emetteur,
"operationDate" => $transaction->date, "operationDate" => $transaction->date,
"operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE'), "operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE'),
@ -1683,36 +1758,53 @@ class iLinkTransactionController extends Controller
$result = json_decode($apiResponse->getBody(), true); $result = json_decode($apiResponse->getBody(), true);
if ($apiResponse->getStatusCode() <= 301 && ($result['success'] ?? true) != false) { // Analyse de la réponse
$transaction->canceled = 0; if ($apiResponse->getStatusCode() <= 301 && isset($result['message']) && $result['message'] == 'Success') {
// Sécurisation des données de retour
$apiData = $result['data'] ?? [];
$transaction->status = 'Success';
$transaction->payment_transaction_id = $apiData['transactionId'] ?? null;
$transaction->save(); $transaction->save();
DB::commit();
// Logs et Envoi Mail if(isset($accountInfo)){
Log::info('SUCCESS: Agent Cash to Bank - Trx: ' . $transaction->id_transaction); $accountInfo->balance = $apiData['realBalance'] ?? $accountInfo->balance;
$accountInfo->save();
}
// Envoi Mail (Commenté comme demandé pour correspondre au Case 4)
$message = trans('messages.successful_agent_send_from_cash_to_bank', [ $message = trans('messages.successful_agent_send_from_cash_to_bank', [
'id_transaction' => $transaction->id_transaction, 'id_transaction' => $transaction->id_transaction,
'amount' => $this->toMoney($transaction->montant, $init_country), 'amount' => $this->toMoney($transaction->montant, $init_country),
'receiver_name' => $request->prenom_destinataire . ' ' . $request->nom_destinataire, 'receiver_name' => $request->prenom_destinataire . ' ' . $request->nom_destinataire,
'iban' => $request->iban, 'iban' => $request->iban,
'sender_name' => $request->prenom_emetteur . ' ' . $request->nom_emetteur, 'sender_name' => $request->prenom_emetteur . ' ' . $request->nom_emetteur,
'bank' => $transaction->bank, 'bank' => $bankName,
'country' => $transaction->country 'country' => $countryName
]); ]);
$this->sendMail($request->email_emetteur, trans('messages.successful_transaction'), $message); $this->sendMail($request->email_emetteur, trans('messages.successful_transaction'), $message);
$response_message = ($message . trans('messages.sent_by_mail'));
Log::info($result['data']['outMessage']. ' Transaction ID: ' . $result['data']['transactionId'].' Bank Account: ' . $result['data']['accountId'] . ' -Agent New Balance: ' . $walletAgent->balance_princ.' -Old Agent Balance: ' . $oldBalance);
$response_message =
(($apiData['outMessage'] ?? 'Success') .
' | ID: ' . ($apiData['transactionId'] ?? 'N/A') .
' | Bank New Balance: ' . ($apiData['realBalance'] ?? 'N/A'));
} else { } else {
throw new Exception("API Bank Refused: " . $apiResponse->getBody()); // La banque a refusé l'opération
DB::rollBack();
Log::warning("BANK REFUSED Agent Cash to Bank: " . ($result['message'] ?? 'Unknown error'));
return $this->errorResponse($result['message'] ?? trans('errors.Error_occurred'), 400);
} }
} catch (\Exception $e) { } catch (\Exception $e) {
// D. Échec : Annulation du débit agent
DB::rollBack(); DB::rollBack();
Log::error("FAILED: Agent Cash to Bank - Error: " . $e->getMessage()); Log::error("CRITICAL ERROR AgentCash2Bank: " . $e->getMessage());
throw new Exception(trans('errors.bank_api_exception'), 500); throw new Exception(trans('errors.Error_occurred'), 500);
} }
break; break;
@ -1845,29 +1937,49 @@ class iLinkTransactionController extends Controller
* ) * )
* ) * )
*/ */
case 20: //User - Retrait de la banque vers le wallet case 20: // User - Retrait de la banque vers le wallet (Bank to Wallet)
$this->validate($request, [
//$this->validate($request, [ 'montant' => 'required|numeric|min:1',
//'code_retrait' => 'required', 'password' => 'required'
//]); ]);
$response_message = '';
$user = $walletUser->user; $user = $walletUser->user;
$this->validatePassword($request->password, $user->encrypted_password, $user->salt); $this->validatePassword($request->password, $user->encrypted_password, $user->salt);
$this->checkUserIdentification($user->id); $this->checkUserIdentification($user->id);
if (!(isset($user->iban) && isset($user->id_bank_country))) // Vérification des prérequis de liaison
throw new Exception(trans('errors.wallet_not_linked_to_bank_account')); $accountNumber = $user->iban;
if (!$accountNumber || !$user->id_bank_country) {
throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422);
}
//Reverifier si l'operateur est toujours associé au reseau $verification = UsersBankingAccountVerification::where('user_code', $user->user_code)
$network_bank = NetworksOperator::where('id_network', $transaction->network_emetteur)->where('id_operator_country', $user->id_bank_country)->first(); ->where('account_number', $accountNumber)
if (!$network_bank) ->first();
$accountInfo = UserBankAccount::where('id_user', $user->id)
->where('account_number', $accountNumber)
->first();
if ($verification) {
$customer_code = $verification->iban;
} elseif ($accountInfo) {
$customer_code = $accountInfo->customer_number;
} else {
throw new Exception(trans('errors.bank_account_not_found'), 422);
}
// Re-vérifier si l'opérateur est toujours associé au réseau
$network_bank = NetworksOperator::where('id_network', $transaction->network_emetteur)
->where('id_operator_country', $user->id_bank_country)
->first();
if (!$network_bank || $network_bank->operators_country->operator->type != 'bank') {
throw new Exception(trans('errors.operator_not_associated_with_network') . '. ' . trans('errors.update_banking_information')); throw new Exception(trans('errors.operator_not_associated_with_network') . '. ' . trans('errors.update_banking_information'));
}
if ($network_bank->operators_country->operator->type != 'bank') // Reverifier le code IBAN correspond toujours
throw new Exception(trans('errors.not_banking_operator') . '. ' . trans('errors.update_banking_information'));
//Reverifier le code IBAN correspond toujours
// $country_code = $network_bank->network->country->code_country; // $country_code = $network_bank->network->country->code_country;
// $bank_code = $network_bank->operators_country->code; // $bank_code = $network_bank->operators_country->code;
// switch ($this->checkIBAN($user->iban, $country_code, $bank_code)) { // switch ($this->checkIBAN($user->iban, $country_code, $bank_code)) {
@ -1879,35 +1991,134 @@ class iLinkTransactionController extends Controller
// throw new Exception(trans('errors.bank_not_match_iban') . '. ' . trans('errors.update_banking_information')); // throw new Exception(trans('errors.bank_not_match_iban') . '. ' . trans('errors.update_banking_information'));
// } // }
// 4. Préparation des données de transaction
$transaction->id_transaction = $this->getTransactionID();
$transaction->montant = $request->montant;
$transaction->frais = $frais = 0; $transaction->frais = $frais = 0;
$transaction->taxe = $taxe = 0; $transaction->taxe = $taxe = 0;
//$walletUser->balance += $transaction->montant;
$transaction->commission_banque = 0; $transaction->commission_banque = 0;
$transaction->commission_hyp = 0; $transaction->commission_hyp = 0;
$transaction->id_wallet_hyp = $walletHyperviseur->id; $transaction->id_wallet_hyp = $walletHyperviseur->id;
$transaction->frais = $frais;
$bankName = $network_bank->operators_country->operator->nom;
$countryName = $network_bank->network->country->name;
$transaction->init_country = 38;
$transaction->final_country = 38;
$transaction->bank_account_number = $accountNumber;
$transaction->bank_name = $bankName;
$transaction->date = $this->getCurrentTime($init_country); $transaction->date = $this->getCurrentTime($init_country);
$transaction->bank = $user->bank->operators_country->operator->nom; $transaction->status = 'PENDING';
$transaction->country = $user->bank->network->country->name;
$transaction->id_bank = $user->id_bank_country;
$transaction->iban = $user->iban;
//$walletUser->save();
$transaction->id_transaction = $this->getTransactionID();
//$transaction->save();
Log::info('-------------------------- User - Retrait de la banque vers le wallet ------------------------------------');
Log::info(json_encode($transaction));
Log::info('------------------------------------------------------------------------------------------------');
$message = trans('messages.successful_user_remove_from_bank_to_wallet', try {
['id_transaction' => $transaction->id_transaction, 'amount' => $this->toMoney($transaction->montant, $init_country), // Sauvegarde initiale de la transaction
'net' => $this->toMoney($transaction->montant, $init_country), 'iban' => $user->iban, 'fees' => $this->toMoney($frais, $init_country), $transaction->save();
'sender_code' => $user->user_code, 'bank' => $transaction->bank, 'country' => $transaction->country]); $oldBalance = $walletUser->balance;
$baseUrl = env('BANK_API_BASE_URL');
$client = new Client(['connect_timeout' => 60]);
// Authentification Bearer Token
$authResponse = $client->post($baseUrl . '/auth/authenticate', [
'json' => [
'login' => env('BANK_API_LOGIN'),
'password' => env('BANK_API_PASSWORD')
]
]);
$authData = json_decode($authResponse->getBody(), true);
$token = $authData['data']['token'] ?? null;
if (!$token) throw new Exception(trans('errors.token_not_found'));
// Payload de débit
$payload = [
"clientMatricule" => (string)$customer_code,
"crAccountId" => (string)$accountNumber,
"drAccountId" => (string)$accountNumber,
"description" => "Retrait Banque vers Wallet SunEx",
"operationDate" => $transaction->date,
"operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE'),
"traceNo" => $transaction->id_transaction,
"transactionAmt" => (float)$transaction->montant
];
$apiResponse = $client->post($baseUrl . '/account/debit', [
'headers' => [
'Authorization' => 'Bearer ' . $token,
'Accept' => 'application/json',
],
'json' => $payload
]);
$result = json_decode($apiResponse->getBody(), true);
// Analyse de la réponse
if ($apiResponse->getStatusCode() <= 301 && isset($result['message']) && $result['message'] == 'Success') {
// Sécurisation des données de retour
$apiData = $result['data'] ?? [];
// Crédit du Wallet du user dans notre système
$walletUser->balance += $transaction->montant;
$walletUser->save();
$transaction->status = $result['message'] ?? 'SUCCESS';
$transaction->payment_transaction_id = $apiData['transactionId'] ?? null;
$transaction->save();
if(isset($accountInfo)){
$accountInfo->balance = $apiData['realBalance'] ?? $accountInfo->balance;
$accountInfo->save();
}
// Préparation du message
$message = trans('messages.successful_user_remove_from_bank_to_wallet', [
'id_transaction' => $transaction->id_transaction,
'amount' => $this->toMoney($transaction->montant, $init_country),
'net' => $this->toMoney($transaction->montant, $init_country),
'iban' => $accountNumber,
'fees' => $this->toMoney($frais, $init_country),
'sender_code' => $user->user_code,
'bank' => $bankName,
'country' => $countryName
]);
// Envoi Mail
$this->sendMail($user->email, trans('messages.successful_transaction'), $message); $this->sendMail($user->email, trans('messages.successful_transaction'), $message);
$response_message = ($message . trans('messages.sent_by_mail'));
Log::info($apiData['outMessage']. ' Transaction ID: ' . ($apiData['transactionId'] ?? 'N/A') . ' Bank Account: ' . ($apiData['accountId'] ?? 'N/A') . ' -Wallet New Balance: ' . $walletUser->balance . ' -Old Wallet Balance: ' . $oldBalance);
$response_message = (($apiData['outMessage'] ?? 'Success') .
' | ID: ' . ($apiData['transactionId'] ?? 'N/A') .
' | Bank New Balance: ' . ($apiData['realBalance'] ?? 'N/A'));
} else {
// La banque a refusé l'opération
DB::rollBack();
Log::warning("BANK REFUSED Bank to Wallet: " . ($result['message'] ?? 'Unknown error'));
return $this->errorResponse($result['message'] ?? trans('errors.Error_occurred'), 400);
}
} catch (\Exception $e) {
DB::rollBack();
$errorMessage = $e->getMessage();
if ($e instanceof \GuzzleHttp\Exception\RequestException && $e->hasResponse()) {
$response = $e->getResponse();
$body = (string) $response->getBody();
$result = json_decode($body, true);
if (isset($result['message'])) {
$errorMessage = $result['message'];
}
}
Log::error("CRITICAL ERROR Bank2Wallet: " . $errorMessage);
return $this->errorResponse($errorMessage, 400);
}
break; break;
case 21: //User - Retrait de carte vers autre wallet case 21: //User - Retrait de carte vers autre wallet
@ -2125,7 +2336,7 @@ class iLinkTransactionController extends Controller
throw $e; throw $e;
} }
Log::error($e->getMessage() . "\n" . $e->getTraceAsString()); Log::error($e->getMessage() . "\n" . $e->getTraceAsString());
return $this->errorResponse($e->getMessage(), $e->getCode()); return $this->errorResponse(trans('errors.Error_occurred'), $e->getCode());
} }
} }

View File

@ -159,7 +159,10 @@ class WalletIlinkTransaction extends Model
'pspReference', 'pspReference',
'from_network_emetteur', 'from_network_emetteur',
'id_transaction_network_emetteur', 'id_transaction_network_emetteur',
'montant_commission' 'montant_commission',
'status',
'bank_account_number',
'bank_name'
]; ];
public function country() public function country()