diff --git a/app/Http/Controllers/WalletController.php b/app/Http/Controllers/WalletController.php index 4e29148..e859fe8 100755 --- a/app/Http/Controllers/WalletController.php +++ b/app/Http/Controllers/WalletController.php @@ -8,6 +8,9 @@ use App\Models\User; use App\Models\UsersBankingAccountVerification; use App\Models\WalletAgent; use App\Models\WalletsUser; +use App\Models\Operator; +use App\Models\OperatorsCountry; +use App\Models\UserBankAccount; use Illuminate\Http\Request; use Illuminate\Http\Response; use Illuminate\Support\Facades\DB; @@ -585,4 +588,199 @@ INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON } while ($codeCorrect); return $code; } + + /** + * @OA\Post( + * path="/wallets/users/create_bank_account", + * summary="Créer un compte bancaire pour un utilisateur simple", + * tags={"Créer un compte bancaire pour un utilisateur simple"}, + * security={{"api_key":{}}}, + * @OA\RequestBody( + * description="Corps de la requete", + * required=true, + * @OA\MediaType( + * mediaType="application/json", + * @OA\Schema( + * @OA\Property(property="id_user", + * type="integer", + * example=39, + * description="ID de l'utilisateur enregistré dans la base de données" + * ), + * @OA\Property(property="id_operator", + * type="integer", + * example=4, + * description="ID de la banque enregistré dans la base de données" + * ), + * @OA\Property(property="id_wallet_network", + * type="integer", + * example=243, + * description="ID du réseau auquel appartient le wallet exemple reseau Ilink World" + * ), + * @OA\Property(property="lastname", + * type="string", + * example = "Doe", + * description="Nom de famille de l'utilisateur" + * ), + * // ... Autres propriétés ici ... + * ) + * ) + * ), + * @OA\Response( + * response=200, + * description="OK", + * @OA\JsonContent( + * ref="#/components/schemas/ApiResponse", + * example = { + * "status" : 200, + * "response" : "Votre demande de création de compte bancaire a été prise en compte, vous recevrez un mail de confirmation dès lors que la banque aura validé votre demande", + * "error":null + * } + * ) + * ) + * ) + */ + public function createUserBankAccount(Request $request) + { + $this->validate($request, [ + 'id_user' => 'required|integer|exists:users,id', + 'id_operator' => 'required|integer|exists:operators,id', + 'id_wallet_network' => 'required|integer|exists:networks,id', + 'lastname' => 'required|string', + 'firstname' => 'required|string', + 'nationality' => 'required|string', + 'birth_date' => 'required|date', + 'birth_country' => 'required|string', + 'birth_city' => 'required|string', + 'father_firstname' => 'required|string', + 'father_lastname' => 'required|string', + 'mother_firstname' => 'required|string', + 'mother_lastname' => 'required|string', + 'marital_name' => 'nullable|string', + 'marital_status' => 'nullable|string', + 'profession' => 'required|string', + 'sector_activity' => 'required|string', + 'subsector_activity' => 'nullable|string', + 'tax_number' => 'required|string', + 'employee_number' => 'nullable|string', + 'position' => 'nullable|string', + 'employer_name' => 'nullable|string', + 'employer_address' => 'nullable|string', + ]); + + // Vérifier que l’utilisateur est identifié + $user = User::findOrFail($request->id_user); + $identification = $this->checkUserIdentification($user->id); + + $operateur_country = OperatorsCountry::where('id_operator', $request->id_operator)->first(); + + if (!$operateur_country) { + return $this->errorResponse(trans('errors.bank_not_associated_with_network')); + } + + // 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', $operateur_country->id) + ->first(); + + if (!$network_bank) { + return $this->errorResponse(trans('errors.bank_not_associated_with_network')); + } + + if ($network_bank->operators_country->operator->type != 'bank') { + return $this->errorResponse(trans('errors.not_banking_operator')); + } + + $exist_user_request_create_account = UserBankAccount::where('id_user', $request->id_user) + ->where('id_operator', $request->id_operator) + ->first(); + + if (isset($exist_user_request_create_account)){ + if ($exist_user_request_create_account->status == 'pending') { + return $this->errorResponse(trans('errors.request_create_account_already_sended')); + } + } + + if(isset($exist_user_request_create_account)){ + if ($exist_user_request_create_account->status == 'active') { + return $this->errorResponse(trans('messages.user_already_has_bank_account_with_this_operator', ['user_lastname' => $user->lastname])); + } + } + + $bankAccount = new UserBankAccount(); + $bankAccount->id_user = $user->id; + $bankAccount->id_operator = $request->id_operator; + $bankAccount->lastname = $request->lastname; + $bankAccount->firstname = $request->firstname; + $bankAccount->marital_name = $request->marital_name ?? 'null'; + $bankAccount->nationality = $request->nationality; + $bankAccount->birth_date = $request->birth_date; + $bankAccount->birth_country = $request->birth_country; + $bankAccount->birth_city = $request->birth_city; + $bankAccount->father_firstname = $request->father_firstname; + $bankAccount->father_lastname = $request->father_lastname; + $bankAccount->mother_firstname = $request->mother_firstname; + $bankAccount->mother_lastname = $request->mother_lastname; + $bankAccount->marital_status = $request->marital_status ?? 'celibataire'; + $bankAccount->profession = $request->profession; + $bankAccount->sector_activity = $request->sector_activity; + $bankAccount->subsector_activity = $request->subsector_activity ?? 'null'; + $bankAccount->tax_number = $request->tax_number; + $bankAccount->employee_number = $request->employee_number; + $bankAccount->position = $request->position; + $bankAccount->employer_name = $request->employer_name ?? 'null'; + $bankAccount->employer_address = $request->employer_address ?? 'null'; + $bankAccount->balance = 0; + $bankAccount->status = 'pending'; + $bankAccount->created_at = date('Y-m-d H:i:s'); + $bankAccount->updated_at = date('Y-m-d H:i:s'); + $bankAccount->save(); + + // Envoi des informations à la banque partenaire (via API) + // $payload = [ + // 'account_number' => $bankAccount->account_number, + // 'iban' => $bankAccount->iban, + // 'swift_code' => $bankAccount->swift_code, + // 'lastname' => $bankAccount->lastname, + // 'firstname' => $bankAccount->firstname, + // 'birth_date' => $bankAccount->birth_date, + // 'nationality' => $bankAccount->nationality, + // 'birth_country' => $bankAccount->birth_country, + // 'network_code' => $network_bank->network->code ?? null, + // ]; + + Log::info('--- Envoi création compte bancaire à la banque partenaire ---'); + // Log::info(json_encode($payload)); + + try { + // // Envoi à une API bancaire + // $response = Http::withHeaders([ + // 'Accept' => 'application/json', + // 'Authorization' => 'Bearer ' . env('BANK_API_TOKEN'), + // ])->post(env('BANK_API_URL') . '/accounts/create', $payload); + + // if ($response->failed()) { + // $bankAccount->status = 'rejected'; + // $bankAccount->reason = $response->json('message') ?? 'Erreur API bancaire'; + // $bankAccount->save(); + // return $this->errorResponse(trans('errors.bank_api_failed')); + // } + + // $bankAccount->status = 'active'; + $bankAccount->reason = 'Demande de compte bancaire envoyée via API en attente de validation'; + $bankAccount->save(); + Log::info('Réponse API Banque: Compte bancaire créé avec succès'); + + } catch (\Exception $e) { + $bankAccount->status = 'rejected'; + $bankAccount->reason = $e->getMessage(); + $bankAccount->save(); + Log::error('Erreur API Banque: ' . $e->getMessage()); + return $this->errorResponse(trans('errors.bank_api_exception')); + } + + return $this->successResponse([ + 'message' => trans('messages.successful_bank_account_creation') + ]); + } + } diff --git a/app/Models/User.php b/app/Models/User.php index 0478a91..ea398d7 100755 --- a/app/Models/User.php +++ b/app/Models/User.php @@ -9,6 +9,8 @@ namespace App\Models; use Carbon\Carbon; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\SoftDeletes; +use App\Models\UserBankAccount; /** * Class User @@ -117,4 +119,8 @@ class User extends Model { return $this->belongsTo(NetworksOperator::class, 'id_bank_country', 'id_operator_country'); } + public function bankAccounts() + { + return $this->hasMany(UserBankAccount::class); + } } diff --git a/app/Models/UserBankAccount.php b/app/Models/UserBankAccount.php new file mode 100755 index 0000000..8b234fa --- /dev/null +++ b/app/Models/UserBankAccount.php @@ -0,0 +1,60 @@ +belongsTo(User::class); + } + + public function bank() + { + return $this->belongsTo(Operator::class); + } + +} diff --git a/database/migrations/2025_11_13_105829_create_user_bank_accounts_table.php b/database/migrations/2025_11_13_105829_create_user_bank_accounts_table.php new file mode 100755 index 0000000..605d6b7 --- /dev/null +++ b/database/migrations/2025_11_13_105829_create_user_bank_accounts_table.php @@ -0,0 +1,82 @@ +id(); + + // Référence utilisateur + $table->unsignedInteger('id_user'); + $table->unsignedInteger('id_operator') + ->comment('Identifiant de l’opérateur (banque partenaire)'); + + // Informations bancaires principales + $table->string('account_number')->unique() + ->nullable() + ->comment('Numéro de compte bancaire attribué par la banque'); + $table->string('iban')->nullable()->comment('Numéro IBAN du compte si disponible'); + $table->string('swift_code')->nullable()->comment('Code SWIFT/BIC de la banque'); + $table->string('account_type')->nullable()->comment('Type de compte : courant, épargne, etc.'); + $table->decimal('balance', 20, 2)->default(0); + $table->string('status')->default('pending')->comment('Statut du compte : pending, active, rejected, closed'); + $table->string('reason')->nullable()->comment('Raison ou message en cas de rejet ou erreur API'); + + // Informations personnelles + $table->string('lastname')->comment('Nom de famille'); + $table->string('firstname')->comment('Prénom'); + $table->string('marital_name')->nullable()->comment('Nom marital si applicable'); + $table->string('nationality'); + $table->date('birth_date'); + $table->string('birth_country')->comment('Pays de naissance'); + $table->string('birth_city')->nullable()->comment('Ville de naissance'); + + // Parents + $table->string('father_firstname')->nullable()->comment('Prénom du père'); + $table->string('father_lastname')->nullable()->comment('Nom du père'); + $table->string('mother_firstname')->nullable()->comment('Prénom de la mère'); + $table->string('mother_lastname')->nullable()->comment('Nom de la mère'); + + // Situation sociale et professionnelle + $table->enum('marital_status', ['celibataire', 'marie', 'veuf', 'divorce']) + ->default('celibataire'); + + $table->string('profession')->nullable(); + $table->string('sector_activity')->nullable(); + $table->string('subsector_activity')->nullable(); + $table->string('tax_number')->nullable()->comment('Numéro fiscal'); + $table->string('employee_number')->nullable()->comment('Matricule employé'); + $table->string('position')->nullable()->comment('Fonction ou poste occupé'); + $table->string('employer_name')->nullable()->comment('Nom de l’employeur'); + $table->string('employer_address')->nullable()->comment('Adresse de l’employeur'); + $table->timestamps(); + }); + + Schema::table('user_bank_accounts', function (Blueprint $table) { + $table->foreign('id_user')->references('id')->on('users')->onDelete('cascade'); + $table->foreign('id_operator')->references('id')->on('operators')->onDelete('cascade'); + }); + + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('user_bank_accounts'); + } +} diff --git a/resources/lang/en/errors.php b/resources/lang/en/errors.php index c68be53..2ff3e80 100755 --- a/resources/lang/en/errors.php +++ b/resources/lang/en/errors.php @@ -91,6 +91,8 @@ Paying network : :network :country', 'transaction_not_supported' => "This transaction is not supported", 'payment_invalid' => "Invalid payment", 'service_unavailable_in_country' => 'Service not available in this country', - 'recipient_not_found' => "This recipient does not exist" - + 'recipient_not_found' => "This recipient does not exist", + 'bank_api_exception' => 'An error occurred while creating the bank account', + 'request_create_account_already_sended' => "A request to create a bank account has already been sent for this bank", + 'user_not_found' => "User not found", ]; diff --git a/resources/lang/en/messages.php b/resources/lang/en/messages.php index 3c9b9aa..6f68702 100755 --- a/resources/lang/en/messages.php +++ b/resources/lang/en/messages.php @@ -16,6 +16,8 @@ return [ 'validated_identification'=>'Validated identification', 'identification_already_validated'=>'Identification already validated', 'successful_card_attachment' => 'Attachment of your card made', + 'user_already_has_bank_account_with_this_operator' => ":user_lastname already has a active bank account with this operator", + 'successful_bank_account_creation' => 'The bank account creation request has been successfully sent you will be notified by email once the account is created', 'successful_identification_message' => 'Hi :name, Your identification has been taken into account. Approach an iLink World agent with your ID to validate your identity. diff --git a/resources/lang/fr/errors.php b/resources/lang/fr/errors.php index 16b0941..1064b1f 100755 --- a/resources/lang/fr/errors.php +++ b/resources/lang/fr/errors.php @@ -91,5 +91,8 @@ Réseau payeur : :network :country', 'transaction_not_supported' => "Cette transaction n'est pas supportée", 'payment_invalid' => "Paiement invalide", 'service_unavailable_in_country' => 'Service non disponible dans ce pays', - 'recipient_not_found' => "Ce destinataire n'existe pas" + 'recipient_not_found' => "Ce destinataire n'existe pas", + 'bank_api_exception' => 'Une erreur est survenue lors de la création du compte bancaire', + 'request_create_account_already_sended' => "Une demande de création de compte bancaire a déjà été envoyée pour cette banque", + 'user_not_found' => "Utilisateur non trouvé", ]; diff --git a/resources/lang/fr/messages.php b/resources/lang/fr/messages.php index f441d73..9fddac5 100755 --- a/resources/lang/fr/messages.php +++ b/resources/lang/fr/messages.php @@ -16,6 +16,8 @@ return [ 'user_not_identificated' => 'Utilisateur non identifié', 'identification_already_validated' => 'Identification deja validée', 'successful_card_attachment' => 'Rattachement de votre carte effectuée', + 'user_already_has_bank_account_with_this_operator' => ":user_lastname possède déjà un compte bancaire actif avec cet opérateur", + 'successful_bank_account_creation' => 'La demande de création de compte bancaire a été envoyée avec succès vous serez notifié par email une fois le compte créé', 'successful_identification_message' => 'Salut :name, Votre identification a été prise en compte . Rapprochez vous d\'un agent iLink World muni de votre pièce d\'identité pour valider votre identité. diff --git a/routes/web.php b/routes/web.php index 3db3513..2055a0a 100755 --- a/routes/web.php +++ b/routes/web.php @@ -72,6 +72,8 @@ $router->group(['prefix' => '', 'middleware' => 'auth'], function () use ($route $router->get('operators/{type}/{id_wallet_network}', 'WalletController@getWalletOperators'); $router->get('banks_for_link/{id_wallet_network}', 'WalletController@getBanksInNetworkForLink'); $router->post('link_bank_account', 'WalletController@linkBankAccount'); + //Creation d'un compte bancaire utilisateur (Agency Banking) + $router->post('create_user_bank_account', 'WalletController@createUserBankAccount'); }); });