diff --git a/app/Http/Controllers/WalletController.php b/app/Http/Controllers/WalletController.php index 2f3594d..6dc7096 100755 --- a/app/Http/Controllers/WalletController.php +++ b/app/Http/Controllers/WalletController.php @@ -541,53 +541,68 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON $user = User::findOrFail($request->id_user); - if (isset($user->iban) && isset($user->id_bank_country)) - return $this->errorResponse(trans('errors.wallet_already_linked_to_bank_account')); - - //Verifier si l'utilisateur est identifié + // 1. Vérifier si l'utilisateur est identifié $this->checkUserIdentification($user->id); - //Verifier si la banque est associée au reseau - $network_bank = NetworksOperator::where('id_network', $request->id_wallet_network)->where('id_operator_country', $request->id_bank)->first(); - if (!$network_bank) + // 2. Vérifier si la banque est associée au réseau + $network_bank = NetworksOperator::where('id_network', $request->id_wallet_network) + ->where('id_operator_country', $request->id_bank) + ->first(); + + if (!$network_bank) { return $this->errorResponse(trans('errors.bank_not_associated_with_network')); + } - if ($network_bank->operators_country->operator->type != 'bank') + if ($network_bank->operators_country->operator->type != 'bank') { return $this->errorResponse(trans('errors.not_banking_operator')); + } - //Verifier le code IBAN - // $country_code = $network_bank->network->country->code_country; - // $bank_code = $network_bank->operators_country->code; - // switch ($this->checkIBAN($request->iban, $country_code, $bank_code)) { - // case 0: - // return $this->errorResponse(trans('errors.invalid_iban')); - // case 1: - // return $this->errorResponse(trans('errors.country_not_match_iban')); - // case 2: - // return $this->errorResponse(trans('errors.bank_not_match_iban')); - // } + // Récupérer toutes les demandes pour cet utilisateur et cet opérateur + $existingRequests = UsersBankingAccountVerification::where('id_user', $user->id) + ->where('id_bank_country', $request->id_bank) + ->get(); - $existingLinkingAccount = UsersBankingAccountVerification::where('iban', $request->iban) - ->where('is_verified', 1) - ->first(); + if ($existingRequests->isNotEmpty()) { - if ($existingLinkingAccount) - if ($existingLinkingAccount->is_verified == 1 && $existingLinkingAccount->was_treated == 0){ - return $this->errorResponse(trans('errors.you_already_have_request_in_progress_for_this_account')); - }else if ($existingLinkingAccount->is_verified == 1 && $existingLinkingAccount->was_treated == 1){ + // CAS 1 : Une demande est déjà validée (is_verified=1, was_treated=1) pour cet IBAN + $alreadyLinked = $existingRequests->where('is_verified', 1) + ->where('was_treated', 1) + ->where('iban', $request->iban) + ->first(); + + if ($alreadyLinked) { return $this->errorResponse(trans('errors.wallet_already_linked_to_bank_account')); } + // CAS 2 : Une demande est déjà en cours de traitement (was_treated=0) + // On ne permet pas une nouvelle demande si une précédente n'est pas encore traitée + $inProgress = $existingRequests->where('was_treated', 0) + ->orWhere('is_verified', 0) + ->first(); + + if ($inProgress) { + return $this->errorResponse(trans('errors.you_already_have_request_in_progress_for_this_account')); + } + + // Note : Si une demande a été traitée (was_treated=1) mais concerne un autre IBAN, le code continuera et permettra une nouvelle demande. + } + + // 3. Création de la nouvelle demande de liaison $user_banking_account_verif = new UsersBankingAccountVerification(); $user_banking_account_verif->id_transaction = $this->getTransactionID(); $user_banking_account_verif->iban = $request->iban; + $user_banking_account_verif->id_user = $user->id; // Ajouté pour la cohérence $user_banking_account_verif->user_code = $user->user_code; $user_banking_account_verif->id_bank_country = $request->id_bank; - $user_banking_account_verif->is_verified = $user_banking_account_verif->was_treated = 0; + $user_banking_account_verif->is_verified = 0; + $user_banking_account_verif->was_treated = 0; $user_banking_account_verif->id_network = $request->id_wallet_network; - $user_banking_account_verif->save(); - return $this->successResponse(trans('messages.successful_bank_account_attachment_taken')); + if ($user_banking_account_verif->save()) { + return $this->successResponse(trans('messages.successful_bank_account_attachment_taken')); + } + + return $this->errorResponse(trans('errors.error_occurred')); } private function getTransactionID() @@ -776,9 +791,26 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON 'id_bank_country' => $newAccount->id_operator_country, 'iban' => $result['accountNumber'] ?? null ]); - LOG::info('Autre compte bancaire activé pour user: ' . $request->id_user . ' numero de compte: ' . $newAccount->account_number); + $message = trans('messages.user_bank_account_activated_successfully', [ + 'bank' => $network_bank->operators_country->operator->nom ?? 'votre banque', + 'account_number' => $newAccount->account_number + ]); - return $this->successResponse(trans('messages.user_bank_account_activated_successfully'), 200); + // Envoi du Mail + try { + $this->sendMail($user->email, trans('messages.creation_bank_account'), $message); + } catch (\Exception $e) { + Log::error("Erreur envoi mail compte rattaché: " . $e->getMessage()); + return $this->successResponse(trans('messages.user_bank_account_activated_successfully',[ + 'bank' => $network_bank->operators_country->operator->nom ?? 'votre banque', + 'account_number' => $newAccount->account_number + ]), 200); + } + + return $this->successResponse(trans('messages.user_bank_account_activated_successfully',[ + 'bank' => $network_bank->operators_country->operator->nom ?? 'votre banque', + 'account_number' => $newAccount->account_number + ]), 200); } Log::error('Échec API Banque User: ' . $request->id_user . ' Response: ' . $response->getBody()); @@ -915,9 +947,10 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON // Mail::to($user->email)->send(new BankAccountActivated($bank_account, $name_of_account_type)); } catch (\Exception $e) { 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'), 200); + return $this->successResponse(trans('messages.user_bank_account_activated_successfully', ['bank' => 'SunEx','account_number' => $bank_account->account_number]), 200); } return $this->errorResponse('Erreur lors de l\'activation API', 500); @@ -997,16 +1030,16 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON ]); $result = json_decode($response->getBody(), true); - - if (($response->getStatusCode() == 200 || $response->getStatusCode() <= 301) && ($result['data']['accountID'] == $user_bank_account_verfication->iban)) { + if (($result['status'] == 200 || $result['message'] == 'Success') && ($result['data']['clientID'] == $user_bank_account_verfication->iban)) { $user_bank_account_verfication->update([ + 'account_number' => $result['data']['accountID'] ?? null, 'is_verified' => 1, 'was_treated' => 1 ]); $user->update([ - 'iban' => $user_bank_account_verfication->iban, + 'iban' => $user_bank_account_verfication->account_number, 'id_bank_country' => $user_bank_account_verfication->id_bank_country ]); diff --git a/app/Http/Controllers/iLinkTransactionController.php b/app/Http/Controllers/iLinkTransactionController.php index 444c08a..ea893a7 100755 --- a/app/Http/Controllers/iLinkTransactionController.php +++ b/app/Http/Controllers/iLinkTransactionController.php @@ -19,6 +19,7 @@ use App\Models\TypeIlinkTransaction; use App\Models\TypeOperator; use App\Models\User; use App\Models\UserBankAccount; +use App\Models\UsersBankingAccountVerification; use App\Models\Wallet; use App\Models\WalletAgent; use App\Models\WalletIlinkTransaction; @@ -629,13 +630,12 @@ class iLinkTransactionController extends Controller $this->validatePassword($request->password, $user->encrypted_password, $user->salt); $this->checkUserIdentification($user->id); - $userBankAccount = UserBankAccount::where('id_user', $user->id) - ->where('id_operator_country', $user->id_bank_country) - ->where('status', 'actived') - ->first(); + $userBankAccountVerification = UsersBankingAccountVerification::where('user_code', $user->user_code) + ->first(); + $accountNumber = $user->iban; - if (!$userBankAccount || !$userBankAccount->account_number) { - throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422); + if ((!$accountNumber || !$user->id_bank_country) && !$userBankAccountVerification) { + throw new Exception(trans('errors.wallet_not_linked_to_bank_account'), 422); } if ($request->montant > $walletUser->balance) { @@ -662,7 +662,7 @@ class iLinkTransactionController extends Controller $transaction->network_emetteur = $network_bank->id_network; $transaction->bank = $network_bank->operators_country->operator->nom; $transaction->country = $network_bank->operators_country->country->name; - $transaction->iban = $userBankAccount->account_number; + $transaction->iban = $accountNumber; $transaction->date = $this->getCurrentTime($init_country); // --- DÉBUT DE LA TRANSACTION DB --- @@ -685,11 +685,11 @@ class iLinkTransactionController extends Controller // Disbursement Payload $payload = [ - "clientMatricule" => $userBankAccount->customer_number, - "crAccountId" => $userBankAccount->account_number, + "clientMatricule" => $userBankAccountVerification->iban, + "crAccountId" => $accountNumber, "description" => "Credit wallet sunEx vers compte bancaire", "operationDate" => $transaction->date, - "operationTypeCode" => "MOMODE", + "operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE' ), "traceNo" => $transaction->id_transaction, "transactionAmt" => (float)$transaction->montant ]; @@ -713,7 +713,11 @@ class iLinkTransactionController extends Controller $message = trans('messages.successful_user_send_to_bank', [ 'id_transaction' => $transaction->id_transaction, 'amount' => $this->toMoney($transaction->montant, $init_country), - 'account_Number' => $userBankAccount->account_number + 'iban' => $accountNumber, + 'net' => $this->toMoney($transaction->montant, $init_country), + 'sender_code' => $user->user_code, + 'country' => $network_bank->operators_country->country->name, + 'bank' => $network_bank->operators_country->operator->nom ]); $this->sendMail($user->email, trans('messages.successful_transaction'), $message); @@ -1664,7 +1668,7 @@ class iLinkTransactionController extends Controller "crAccountId" => $request->iban, //Numero de compte bancaire receveur "description" => "Transfert Cash vers Banque - Emetteur: " . $request->prenom_emetteur . ' ' . $request->nom_emetteur, "operationDate" => $transaction->date, - "operationTypeCode" => "MOMODE", + "operationTypeCode" => env('BANK_API_OPERATION_TYPE_CODE'), "traceNo" => $transaction->id_transaction, "transactionAmt" => (float)$transaction->montant ]; @@ -1864,19 +1868,17 @@ class iLinkTransactionController extends Controller 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; - $bank_code = $network_bank->operators_country->code; - switch ($this->checkIBAN($user->iban, $country_code, $bank_code)) { - case 0: - throw new Exception(trans('errors.invalid_iban') . '. ' . trans('errors.update_banking_information')); - case 1: - throw new Exception(trans('errors.country_not_match_iban') . '. ' . trans('errors.update_banking_information')); - case 2: - throw new Exception(trans('errors.bank_not_match_iban') . '. ' . trans('errors.update_banking_information')); - } + // $country_code = $network_bank->network->country->code_country; + // $bank_code = $network_bank->operators_country->code; + // switch ($this->checkIBAN($user->iban, $country_code, $bank_code)) { + // case 0: + // throw new Exception(trans('errors.invalid_iban') . '. ' . trans('errors.update_banking_information')); + // case 1: + // throw new Exception(trans('errors.country_not_match_iban') . '. ' . trans('errors.update_banking_information')); + // case 2: + // throw new Exception(trans('errors.bank_not_match_iban') . '. ' . trans('errors.update_banking_information')); + // } - // Envoyer la trame vers banque pour debiter le compte client et recharger le compte bancaire de iLink - // -----> $transaction->frais = $frais = 0; $transaction->taxe = $taxe = 0; diff --git a/app/Models/UsersBankingAccountVerification.php b/app/Models/UsersBankingAccountVerification.php index 23db113..c894ed1 100755 --- a/app/Models/UsersBankingAccountVerification.php +++ b/app/Models/UsersBankingAccountVerification.php @@ -40,6 +40,8 @@ class UsersBankingAccountVerification extends Model 'id_transaction', 'user_code', 'iban', + 'account_number', + 'bank_code', 'id_bank_country', 'id_network', 'is_verified', diff --git a/app/Traits/Helper.php b/app/Traits/Helper.php index 8522cb2..0d38b91 100755 --- a/app/Traits/Helper.php +++ b/app/Traits/Helper.php @@ -354,13 +354,19 @@ trait Helper public function generateTransactionCode() { - $data = random_bytes(16); + try { + $data = random_bytes(16); - // Manipulation binaire pour respecter la norme UUID v4 - $data = chr(ord($data) & 0x0f | 0x40); // Version 4 - $data = chr(ord($data) & 0x3f | 0x80); // Variante RFC 4122 + // On modifie l'octet à la position 6 et 8 uniquement + $data[6] = chr(ord($data[6]) & 0x0f | 0x40); // Version 4 + $data[8] = chr(ord($data[8]) & 0x3f | 0x80); // Variante RFC 4122 - return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + // Transformation en format UUID (8-4-4-4-12) + return vsprintf('%s%s-%s-%s-%s-%s%s%s', str_split(bin2hex($data), 4)); + } catch (\Exception $e) { + // Fallback au cas où random_bytes échoue + return uniqid('TXN-', true); + } } // Fonction de tri par date diff --git a/database/migrations/2026_02_20_154911_add_account_number_to_users_banking_account_verification_table.php b/database/migrations/2026_02_20_154911_add_account_number_to_users_banking_account_verification_table.php new file mode 100755 index 0000000..14afaf8 --- /dev/null +++ b/database/migrations/2026_02_20_154911_add_account_number_to_users_banking_account_verification_table.php @@ -0,0 +1,38 @@ +string('account_number')->nullable()->after('iban'); + $table->string('bank_code')->nullable()->after('account_number'); + } + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('users_banking_account_verification', function (Blueprint $table) { + if (Schema::hasColumn('users_banking_account_verification', 'account_number')) { + $table->dropColumn('account_number'); + $table->dropColumn('bank_code'); + } + }); + } +} diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index b03b693..f684ba1 100755 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -104,5 +104,6 @@ Paying network : :network :country', 'your_previous_request_for_this_product_was_rejected' => 'Your previous request for this product was rejected', 'your_previous_request_for_this_product_was_closed' => 'Your previous request for this product was closed', 'you_already_have_request_in_progress_unvalidated' => 'You already have a request in progress that is not yet validated', + 'bank_account_not_found' => 'Bank account not found', ]; diff --git a/resources/lang/en/messages.php b/resources/lang/en/messages.php index a14bfb5..5bde07b 100755 --- a/resources/lang/en/messages.php +++ b/resources/lang/en/messages.php @@ -335,8 +335,9 @@ Transaction information : - Destination account: :sender_code - Amount: :net_final", 'create_bank_account_linked_successfully' => 'Bank account successfully linked to your user account', -'user_bank_account_activated_successfully' => 'User bank account activated successfully', +'user_bank_account_activated_successfully' => 'Congratulations! Your new bank account at :bank has been successfully created. Your account number :account_number is automatically linked to your wallet.', 'wallet_already_linked_to_bank_account' => 'This wallet is already linked to a bank account', 'request_bank_account_pending_validation_by_administrator' => 'Your bank account creation request is pending validation by an administrator', + 'creation_bank_account' => 'Bank account opening', ]; diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index 77adfde..3ee813d 100755 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -104,4 +104,5 @@ Réseau payeur : :network :country', 'your_previous_request_for_this_product_was_rejected' => 'Votre précédente demande pour ce produit a été rejetée', 'your_previous_request_for_this_product_was_closed' => 'Votre précédente demande pour ce produit a été clôturée', 'you_already_have_request_in_progress_unvalidated' => 'Vous avez déjà une demande en cours qui n\'est pas encore validée', + 'bank_account_not_found' => 'Compte bancaire non trouvé', ]; diff --git a/resources/lang/fr/messages.php b/resources/lang/fr/messages.php index c2fbad8..ef729c1 100755 --- a/resources/lang/fr/messages.php +++ b/resources/lang/fr/messages.php @@ -336,7 +336,8 @@ Informations de la transaction : - Compte destinataire : :sender_code - Montant : :net_final", 'create_bank_account_linked_successfully' => 'Compte bancaire rattaché avec succès', - 'user_bank_account_activated_successfully' => 'Compte bancaire activé avec succès', + 'user_bank_account_activated_successfully' => 'Félicitations ! Votre nouveau compte bancaire chez :bank a été créé avec succès. Votre numéro de compte :account_number est automatiquement rattaché à votre wallet/portefeuille.', 'wallet_already_linked_to_bank_account' => 'Votre wallet est deja rattaché à votre compte bancaire', 'request_bank_account_pending_validation_by_administrator' => 'Votre demande de création de compte bancaire est en attente de validation par un administrateur', + 'creation_bank_account' => 'Ouverture de compte bancaire', ];