$id_agent]); // Create wallet if is not exist $category = null; if ($networks) { $reload = false; $id = $id_agent; foreach ($networks as $network) { $category = $network->category; // Create wallet if is not exist if (!$network->id) { $datetime = $this->getCurrentTimeByCountryCode($network->code_country); DB::insert('INSERT INTO wallets (id_networkAgent , created_date) VALUES (? , ?);', [$network->network_agent_id, $datetime]); $reload = true; } } if ($reload) return $this->activated($id); } // Return only single wallet if it is hypervisor or supervisor if (in_array($category, ['hyper', 'super'])) { // Remove unnecessary fields // $networks = $this->array_except($networks, ['category']); return $this->successResponse(collect($networks)->first()); } else { // Remove unnecessary fields $networks = $this->array_except($networks, ['balance_princ', 'balance_com', 'created_date', 'taux_com_client_depot']); return $this->successResponse($networks); } } private function array_except($array, $keys) { foreach ($array as $row) { foreach ($keys as $key) { unset($row->$key); } } return $array; } public function show($id_wallet) { // $wallet = Wallet::findOrFail($id_wallet); $wallet = collect(DB::select('SELECT wa.wallet_id AS id, wa.balance_princ, wa.balance_com, wa.created_date, wa.network , cw.taux_com_client_depot, c.name AS country, cw.type, wa.networks_agent_id as network_agent_id, c.currency_code , cw.id_network , cw.has_nano_credit , cG.category FROM wallet_agent wa INNER JOIN configWallet cw ON wa.network_id = cw.id_network INNER JOIN networks n ON n.id = wa.network_id INNER JOIN countries_currencies c ON c.id = n.country_id INNER JOIN networks_agents na on na.id = wa.networks_agent_id INNER JOIN codeGenerer cG on na.codeGenerer_id = cG.id WHERE wa.wallet_id = :id', ['id' => $id_wallet]))->first(); if ($wallet) { // Recuperer la config du nano santé $nhConfig = collect(DB::select('SELECT * FROM nh_networks_configs WHERE network_id = :network_id LIMIT 50', ['network_id' => $wallet->id_network]))->first(); if (isset($nhConfig)) { $wallet->password_validation = $nhConfig->password_validation ?? "MAX"; } return $this->successResponse($wallet); } else return $this->errorResponse(trans('errors.model_not_found', ['model' => 'wallet']), Response::HTTP_BAD_REQUEST); } public function create(Request $request) { $rules = [ 'id_networkAgent' => 'required|integer|min:1' ]; $this->validate($request, $rules); DB::insert('INSERT INTO wallets (id_networkAgent) VALUES (?);', [$request->id_networkAgent]); return $this->successResponse(trans('messages.new_wallet_added')); } // Wallets users iLink public function showWalletUser($id_user) { $wallet = collect(DB::select('SELECT wu.*, u.user_code , u.numero_carte , u.expiration_date ,n2.id as id_wallet_network, n2.name as network , cc.name as country, cc.currency_code , card_cc.currency_code as card_currency_code, cw.has_nano_credit from wallets_users wu INNER JOIN users u ON u.id = wu.idUser INNER JOIN networks n1 ON n1.id = u.network_id INNER JOIN networks n2 ON n2.country_id = n1.country_id INNER JOIN configWallet cw ON cw.id_network = n2.id INNER JOIN countries_currencies cc ON cc.id = n2.country_id LEFT JOIN countries_currencies card_cc ON card_cc.id = u.card_country_id WHERE wu.idUser = :id_user AND cw.type = \'ilink\' LIMIT 1', ['id_user' => $id_user]))->first(); if ($wallet) { return $this->successResponse($wallet); } else return $this->errorResponse(trans('errors.model_not_found', ['model' => 'wallet']), Response::HTTP_BAD_REQUEST); } //Les historiques globals des hyperviseur et superviseur public function hyperHistory($id_network, Request $request) { $demandes = DB::select("SELECT 'N' as type_historique, i.montant , i.user as destinataire , i.* FROM infos_users_demandes_credits i WHERE id_network = :id ;", ['id' => $id_network]); $savings = DB::select("SELECT 'E' as type_historique , i.montant , i.user as destinataire , i.* FROM infos_users_epargnes i WHERE id_network = :id;", ['id' => $id_network]); $transactions = DB::select("SELECT 'T' as type_historique, wit.id_transaction, tit.nom as operation_fr , tit.name as operation_en , wit.montant ,wit.nom_emetteur, wit.prenom_emetteur, wit.id_wallet_user,wit.frais,wit.taxe,wit.id_destinataire, wit.nom_destinataire, wit.prenom_destinataire, wit.type , wit.id_wallet_user, wit.init_country, wit.final_country , wit.network_destinataire , wit.montant_net_final_country , wit.date as date_creation , wit.id , wit.numero_carte, wit.montant_net FROM wallet_ilink_transaction wit INNER JOIN type_ilink_transaction tit ON wit.type = tit.id WHERE wit.network_emetteur = :id ;", ['id' => $id_network]); $transactions_mapped = array_map(function ($data) { $data->operation = app()->isLocale('en') ? $data->operation_en : $data->operation_fr; $date = $data->date_creation; unset($data->date_creation); $wallet_user = isset($data->id_wallet_user) ? WalletsUser::findOrFail($data->id_wallet_user) : null; $user_destinataire = isset($data->id_destinataire) ? User::where('user_code', $data->id_destinataire)->first() : null; $emetteur = $wallet_user ? $wallet_user->user->lastname . ' ' . $wallet_user->user->firstname : $data->prenom_emetteur . ' ' . $data->nom_emetteur; if (!$wallet_user && !$data->nom_emetteur) $emetteur = $data->numero_carte; $destinataire = in_array($data->type, [12, 16]) ? $emetteur : ($user_destinataire ? $user_destinataire->lastname . ' ' . $user_destinataire->firstname : $data->prenom_destinataire . ' ' . $data->nom_destinataire); $data->emetteur = $emetteur; $data->destinataire = $destinataire; $data->frais = $this->toMoney($data->frais + $data->taxe, $data->init_country); $data->montant_net_init = $this->toMoney($data->montant_net, $data->init_country); $data->montant_net_final = $data->montant_net_final_country ? $this->toMoney($data->montant_net_final_country, $data->final_country) : $data->montant_net_init; $data->montant2 = $this->toMoney($data->montant, $data->init_country); $data->init_country = $this->getCountryName($data->init_country); $data->final_country = $data->montant_net_final_country ? $this->getCountryName($data->final_country) : ''; $data->reseau_payeur = isset($data->network_destinataire) ? $this->getNetworkName($data->network_destinataire) . ' ' . $data->final_country : null; if ($data->type == 13) $data->destinataire = $data->numero_carte; if (ctype_space($data->destinataire)) { $data->destinataire = $data->emetteur; } $data->date_creation = $date; unset($data->type, $data->id_wallet_user, $data->network_destinataire, $data->nom_destinataire, $data->prenom_destinataire, $data->taxe, $data->numero_carte, $data->montant_net_final_country, $data->montant_net, $data->nom_emetteur, $data->prenom_emetteur, $data->id_destinataire, $data->operation_fr, $data->operation_en); return $data; }, $transactions); // Supprimer les underscore sur les etats $merge = array_map(function ($demand) { $demand->etat = trans('states.' . $demand->etat); if (isset($demand->type)) $demand->type = trans('states.' . $demand->type); if (isset($demand->type_caution)) $demand->type_caution = trans('states.' . $demand->type_caution); return $demand; }, array_merge($demandes, $savings)); $result = array_merge($transactions_mapped, $merge); usort($result, array($this, 'sortFunction')); // Trier le tout par date return $this->successResponse($this->arrayPaginator($result, $request)); } public function superHistory($agent_code, Request $request) { $walletSup = WalletAgent::where('codeMembre', $agent_code)->firstOrFail(); $id_wallet = $walletSup->wallet_id; $demandes = DB::select("SELECT 'N' as type_historique , i.montant ,i.user as destinataire , i.* FROM infos_users_demandes_credits i WHERE codeParrain = :code ;", ['code' => $walletSup->codeMembre]); $transactions = DB::select("SELECT 'T' as type_historique, wit.id_transaction, tit.nom as operation_fr , tit.name as operation_en , wit.montant ,wit.nom_emetteur, wit.prenom_emetteur, wit.id_wallet_user,wit.frais,wit.taxe,wit.id_destinataire, wit.nom_destinataire, wit.prenom_destinataire, wit.type , wit.id_wallet_user, wit.init_country, wit.final_country , wit.network_destinataire , wit.montant_net_final_country , wit.date as date_creation , wit.id , wit.numero_carte, wit.montant_net FROM wallet_ilink_transaction wit INNER JOIN type_ilink_transaction tit ON wit.type = tit.id WHERE wit.id_wallet_sup = :id ;", ['id' => $id_wallet]); $transactions_mapped = array_map(function ($data) { $data->operation = app()->isLocale('en') ? $data->operation_en : $data->operation_fr; $date = $data->date_creation; unset($data->date_creation); $wallet_user = isset($data->id_wallet_user) ? WalletsUser::findOrFail($data->id_wallet_user) : null; $user_destinataire = isset($data->id_destinataire) ? User::where('user_code', $data->id_destinataire)->first() : null; $emetteur = $wallet_user ? $wallet_user->user->lastname . ' ' . $wallet_user->user->firstname : $data->prenom_emetteur . ' ' . $data->nom_emetteur; if (!$wallet_user && !$data->nom_emetteur) $emetteur = $data->numero_carte; $destinataire = in_array($data->type, [12, 16]) ? $emetteur : ($user_destinataire ? $user_destinataire->lastname . ' ' . $user_destinataire->firstname : $data->prenom_destinataire . ' ' . $data->nom_destinataire); $data->emetteur = $emetteur; $data->destinataire = $destinataire; $data->frais = $this->toMoney($data->frais + $data->taxe, $data->init_country); $data->montant_net_init = $this->toMoney($data->montant_net, $data->init_country); $data->montant_net_final = $data->montant_net_final_country ? $this->toMoney($data->montant_net_final_country, $data->final_country) : $data->montant_net_init; $data->montant2 = $this->toMoney($data->montant, $data->init_country); $data->init_country = $this->getCountryName($data->init_country); $data->final_country = $data->montant_net_final_country ? $this->getCountryName($data->final_country) : ''; $data->reseau_payeur = isset($data->network_destinataire) ? $this->getNetworkName($data->network_destinataire) . ' ' . $data->final_country : null; if ($data->type == 13) $data->destinataire = $data->numero_carte; $data->date_creation = $date; unset($data->type, $data->id_wallet_user, $data->network_destinataire, $data->nom_destinataire, $data->prenom_destinataire, $data->taxe, $data->numero_carte, $data->montant_net_final_country, $data->montant_net, $data->nom_emetteur, $data->prenom_emetteur, $data->id_destinataire, $data->operation_fr, $data->operation_en); return $data; }, $transactions); // Supprimer les underscore sur les etats $demandes_mapped = array_map(function ($demand) { $demand->etat = trans('states.' . $demand->etat); $demand->type_caution = trans('states.' . $demand->type_caution); return $demand; }, $demandes); $result = array_merge($transactions_mapped, $demandes_mapped); usort($result, array($this, 'sortFunction')); // Trier le tout par date return $this->successResponse($this->arrayPaginator($result, $request)); } // Routes sans pagination public function allHyperHistory($id_network) { $demandes = DB::select("SELECT 'N' as type_historique, i.montant , i.user as destinataire , i.* FROM infos_users_demandes_credits i WHERE id_network = :id ;", ['id' => $id_network]); $savings = DB::select("SELECT 'E' as type_historique , i.montant , i.user as destinataire , i.* FROM infos_users_epargnes i WHERE id_network = :id;", ['id' => $id_network]); $transactions = DB::select("SELECT 'T' as type_historique, wit.id_transaction, tit.nom as operation_fr , tit.name as operation_en , wit.montant ,wit.nom_emetteur, wit.prenom_emetteur, wit.id_wallet_user,wit.frais,wit.taxe,wit.id_destinataire, wit.nom_destinataire, wit.prenom_destinataire, wit.type , wit.id_wallet_user, wit.init_country, wit.final_country , wit.network_destinataire , wit.montant_net_final_country , wit.date as date_creation , wit.id , wit.numero_carte, wit.montant_net FROM wallet_ilink_transaction wit INNER JOIN type_ilink_transaction tit ON wit.type = tit.id WHERE wit.network_emetteur = :id ;", ['id' => $id_network]); $transactions_mapped = array_map(function ($data) { $data->operation = app()->isLocale('en') ? $data->operation_en : $data->operation_fr; $date = $data->date_creation; unset($data->date_creation); $wallet_user = isset($data->id_wallet_user) ? WalletsUser::findOrFail($data->id_wallet_user) : null; $user_destinataire = isset($data->id_destinataire) ? User::where('user_code', $data->id_destinataire)->first() : null; $emetteur = $wallet_user ? $wallet_user->user->lastname . ' ' . $wallet_user->user->firstname : $data->prenom_emetteur . ' ' . $data->nom_emetteur; if (!$wallet_user && !$data->nom_emetteur) $emetteur = $data->numero_carte; $destinataire = in_array($data->type, [12, 16]) ? $emetteur : ($user_destinataire ? $user_destinataire->lastname . ' ' . $user_destinataire->firstname : $data->prenom_destinataire . ' ' . $data->nom_destinataire); $data->emetteur = $emetteur; $data->destinataire = $destinataire; $data->frais = $this->toMoney($data->frais + $data->taxe, $data->init_country); $data->montant_net_init = $this->toMoney($data->montant_net, $data->init_country); $data->montant_net_final = $data->montant_net_final_country ? $this->toMoney($data->montant_net_final_country, $data->final_country) : $data->montant_net_init; $data->montant2 = $this->toMoney($data->montant, $data->init_country); $data->init_country = $this->getCountryName($data->init_country); $data->final_country = $data->montant_net_final_country ? $this->getCountryName($data->final_country) : ''; $data->reseau_payeur = isset($data->network_destinataire) ? $this->getNetworkName($data->network_destinataire) . ' ' . $data->final_country : null; if ($data->type == 13) $data->destinataire = $data->numero_carte; if (ctype_space($data->destinataire)) { $data->destinataire = $data->emetteur; } $data->date_creation = $date; unset($data->type, $data->id_wallet_user, $data->network_destinataire, $data->nom_destinataire, $data->prenom_destinataire, $data->taxe, $data->numero_carte, $data->montant_net_final_country, $data->montant_net, $data->nom_emetteur, $data->prenom_emetteur, $data->id_destinataire, $data->operation_fr, $data->operation_en); return $data; }, $transactions); // Supprimer les underscore sur les etats $merge = array_map(function ($demand) { $demand->etat = trans('states.' . $demand->etat); if (isset($demand->type)) $demand->type = trans('states.' . $demand->type); if (isset($demand->type_caution)) $demand->type_caution = trans('states.' . $demand->type_caution); return $demand; }, array_merge($demandes, $savings)); $result = array_merge($transactions_mapped, $merge); usort($result, array($this, 'sortFunction')); // Trier le tout par date return $this->successResponse($result); } public function allSuperHistory($agent_code) { $walletSup = WalletAgent::where('codeMembre', $agent_code)->firstOrFail(); $id_wallet = $walletSup->wallet_id; $demandes = DB::select("SELECT 'N' as type_historique, i.montant , i.user as destinataire , i.* FROM infos_users_demandes_credits i WHERE codeParrain = :code ;", ['code' => $walletSup->codeMembre]); $transactions = DB::select("SELECT 'T' as type_historique, wit.id_transaction, tit.nom as operation_fr , tit.name as operation_en , wit.montant ,wit.nom_emetteur, wit.prenom_emetteur, wit.id_wallet_user,wit.frais,wit.taxe,wit.id_destinataire, wit.nom_destinataire, wit.prenom_destinataire, wit.type , wit.id_wallet_user, wit.init_country, wit.final_country , wit.network_destinataire , wit.montant_net_final_country , wit.date as date_creation , wit.id , wit.numero_carte, wit.montant_net FROM wallet_ilink_transaction wit INNER JOIN type_ilink_transaction tit ON wit.type = tit.id WHERE wit.id_wallet_sup = :id ;", ['id' => $id_wallet]); $transactions_mapped = array_map(function ($data) { $data->operation = app()->isLocale('en') ? $data->operation_en : $data->operation_fr; $date = $data->date_creation; unset($data->date_creation); $wallet_user = isset($data->id_wallet_user) ? WalletsUser::findOrFail($data->id_wallet_user) : null; $user_destinataire = isset($data->id_destinataire) ? User::where('user_code', $data->id_destinataire)->first() : null; $emetteur = $wallet_user ? $wallet_user->user->lastname . ' ' . $wallet_user->user->firstname : $data->prenom_emetteur . ' ' . $data->nom_emetteur; if (!$wallet_user && !$data->nom_emetteur) $emetteur = $data->numero_carte; $destinataire = in_array($data->type, [12, 16]) ? $emetteur : ($user_destinataire ? $user_destinataire->lastname . ' ' . $user_destinataire->firstname : $data->prenom_destinataire . ' ' . $data->nom_destinataire); $data->emetteur = $emetteur; $data->destinataire = $destinataire; $data->frais = $this->toMoney($data->frais + $data->taxe, $data->init_country); $data->montant_net_init = $this->toMoney($data->montant_net, $data->init_country); $data->montant_net_final = $data->montant_net_final_country ? $this->toMoney($data->montant_net_final_country, $data->final_country) : $data->montant_net_init; $data->montant2 = $this->toMoney($data->montant, $data->init_country); $data->init_country = $this->getCountryName($data->init_country); $data->final_country = $data->montant_net_final_country ? $this->getCountryName($data->final_country) : ''; $data->reseau_payeur = isset($data->network_destinataire) ? $this->getNetworkName($data->network_destinataire) . ' ' . $data->final_country : null; if ($data->type == 13) $data->destinataire = $data->numero_carte; if (ctype_space($data->destinataire)) { $data->destinataire = $data->emetteur; } $data->date_creation = $date; unset($data->type, $data->id_wallet_user, $data->network_destinataire, $data->nom_destinataire, $data->prenom_destinataire, $data->taxe, $data->numero_carte, $data->montant_net_final_country, $data->montant_net, $data->nom_emetteur, $data->prenom_emetteur, $data->id_destinataire, $data->operation_fr, $data->operation_en); return $data; }, $transactions); // Supprimer les underscore sur les etats $demandes_mapped = array_map(function ($demand) { $demand->etat = trans('states.' . $demand->etat); $demand->type_caution = trans('states.' . $demand->type_caution); return $demand; }, $demandes); $result = array_merge($transactions_mapped, $demandes_mapped); usort($result, array($this, 'sortFunction')); // Trier le tout par date return $this->successResponse($result); } /** * @OA\Get( * path="/wallets/users/operators/{type}/{id_wallet_network}", * summary="Afficher la liste des opérateurs d'un reseau", * tags={"Liste des opérateurs d'un reseau"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="type", * name="type", * description="Type d'operateur", * in="path", * required=true, * @OA\Schema( * type="string", * enum={"bank", "electricity", "phone" , "tv" ,"school" , "water"}, * default="bank" * ) * ), * @OA\Parameter( * parameter="id_wallet_network", * name="id_wallet_network", * description="ID du reseau enregistré dans la base de données auquel appartient le wallet", * in="path", * required=true, * @OA\Schema( * type="integer", default=101 * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {{ * "id_operator" : 1, * "operator_name" : "ENEO", * "operator_address" : "Bonamoussadi", * "country": "Cameroon" * }}, * "error":null * } * ) * ) * ) */ public function getWalletOperators($type, $id_wallet_network) { $operators = DB::select("SELECT oc.id as id_operator, o.nom as operator_name , oc.adresse as operator_address, c.name as country FROM networks_operators nop INNER JOIN operators_countries oc ON oc.id = nop.id_operator_country INNER JOIN operators o ON o.id = oc.id_operator INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON o.type = top.code WHERE nop.id_network = :id_network AND o.type = :type_operator ;", ['id_network' => $id_wallet_network, 'type_operator' => $type]); return $this->successResponse($operators); } /** * @OA\Get( * path="/wallets/users/banks_for_link/{id_wallet_network}", * summary="Afficher la liste des banques d'un réseau pour le rattachement à un wallet", * tags={"Rattacher un compte bancaire à un wallet utilisateur simple"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="id_wallet_network", * name="id_wallet_network", * description="ID du reseau enregistré dans la base de données auquel appartient le wallet", * in="path", * required=true, * @OA\Schema( * type="integer", default=101 * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {{ * "id_bank" : 1, * "bank_name" : "UBA", * "bank_address" : "Bonamoussadi", * "country": "Cameroon" * }}, * "error":null * } * ) * ) * ) */ //Banques d'un réseau pour la liaison public function getBanksInNetworkForLink($id_wallet_network) { $id_country = Network::findOrFail($id_wallet_network)->country->id; $banks = DB::select("SELECT oc.id as id_bank, o.nom as bank_name , oc.adresse as bank_address, c.name as country FROM networks_operators nop INNER JOIN operators_countries oc ON oc.id = nop.id_operator_country INNER JOIN operators o ON o.id = oc.id_operator INNER JOIN countries c ON oc.id_country = c.id INNER JOIN type_operators top ON o.type = top.code WHERE nop.id_network = :id_network AND o.type LIKE '%bank%' AND oc.id_country = :id_country ;", ['id_network' => $id_wallet_network, 'id_country' => $id_country]); return $this->successResponse($banks); } /** * @OA\Post( * path="/wallets/users/link_bank_account", * summary="Rattacher le compte bancaire d'un utilisateur à son wallet", * tags={"Rattacher un compte bancaire à un wallet utilisateur simple"}, * security={{"api_key":{}}}, * @OA\RequestBody( * description="Corps de la requete", * required=true, * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property(property="iban", * type="string", * description="Identifiant bancaire" * ), * @OA\Property(property="id_bank", * 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=101, * description="ID du réseau auquel appartient le wallet" * ), * @OA\Property(property="id_user", * type="integer", * example = 12, * description="ID de l'utilisateur enregistré dans la base de données" * ) * ) * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : "Votre requête de rattachement de votre compte bancaire a été prise en compte, vous recevrez un mail de confirmation dès lors que la banque aura validé votre code IBAN", * "error":null * } * ) * ) * ) */ // Rattacher le compte bancaire au wallet public function linkBankAccount(Request $request) { $this->validate($request, [ 'iban' => 'required', 'id_bank' => 'required|integer|min:0|not_in:0', 'id_wallet_network' => 'required|integer|min:0|not_in:0', 'id_user' => 'required|integer|exists:users,id', ]); $user = User::findOrFail($request->id_user); // 1. Vérifier si l'utilisateur est identifié $this->checkUserIdentification($user->id); // 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') { return $this->errorResponse(trans('errors.not_banking_operator')); } // Récupérer toutes les demandes pour cet utilisateur et cet opérateur $existingRequests = UsersBankingAccountVerification::where('user_code', $user->user_code) ->where('id_bank_country', $request->id_bank) ->get(); if ($existingRequests->isNotEmpty()) { // 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 = 0; $user_banking_account_verif->was_treated = 0; $user_banking_account_verif->id_network = $request->id_wallet_network; 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() { do { $code = $this->generateTransactionCode(); $result = collect(DB::select('SELECT * FROM users_banking_account_verification WHERE id_transaction = :code', ['code' => $code])); $codeCorrect = sizeof($result) < 0; } 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_countries,id', 'id_wallet_network' => 'required|integer|exists:networks,id', 'account_type' => 'required', 'lastname' => 'required|string', 'firstname' => 'required|string', 'nationality' => 'required|string', 'birth_date' => 'required|date', 'birth_country' => 'required|string|max:3', 'birth_city' => 'required|string', 'identification_number' => 'required|string', 'spouse_name' => 'nullable|string', 'phone_number' => 'required|string', 'marital_status' => 'nullable|string', 'profession' => 'required|string', 'niu' => 'nullable|string', 'employer_city' => 'nullable|string', 'employer_name' => 'nullable|string', 'employer_address' => 'nullable|string', ]); // 1. Initialisation et Vérifications de base $user = User::findOrFail($request->id_user); $this->checkUserIdentification($user->id); $network_bank = NetworksOperator::where('id_network', $request->id_wallet_network) ->where('id_operator_country', $request->id_operator) ->first(); if (!$network_bank || $network_bank->operators_country->operator->type != 'bank') { $errorKey = (!$network_bank) ? 'errors.bank_not_associated_with_network' : 'errors.not_banking_operator'; return $this->errorResponse(trans($errorKey)); } // Préparation des données communes $commonAccountData = [ 'id_user' => (int)$request->id_user, 'customer_account_type_id' => (int)$request->account_type, 'id_operator_country' => (int)$request->id_operator, 'firstname' => $request->firstname, 'lastname' => $request->lastname, 'nationality' => $request->nationality, 'birth_date' => $request->birth_date, 'birth_country' => $request->birth_country, 'birth_city' => $request->birth_city, 'marital_status' => $request->marital_status ?? 'celibataire', 'profession' => $request->profession, 'identification_number' => $request->identification_number, 'phone_number' => $request->phone_number ?? 'null', 'spouse_name' => $request->spouse_name, 'niu' => $request->niu ?? 'null', 'employer_city' => $request->employer_city ?? 'null', 'employer_name' => $request->employer_name ?? 'null', 'employer_address' => $request->employer_address ?? 'null', 'balance' => 0, ]; // Récupérer tous les comptes de l'user chez cet opérateur spécifique $userAccountsAtThisBank = UserBankAccount::where('id_user', $request->id_user) ->where('id_operator_country', $request->id_operator) ->get(); // 2. CAS A : Le même type de compte existe déjà (doublon strict) $sameTypeAccount = $userAccountsAtThisBank->where('customer_account_type_id', $request->account_type)->first(); if ($sameTypeAccount) { $statusMessages = [ 'actived' => trans('messages.user_already_has_bank_account_with_this_operator', ['user_lastname' => $user->lastname]), 'pending' => trans('errors.you_already_have_request_in_progress_for_this_product'), 'rejected' => trans('errors.your_previous_request_for_this_product_was_rejected'), 'closed' => trans('errors.your_previous_request_for_this_product_was_closed'), ]; return $this->errorResponse($statusMessages[$sameTypeAccount->status] ?? 'Error', 500); } // 3. CAS B : Un AUTRE type de compte existe chez le même opérateur $differentTypeAccount = $userAccountsAtThisBank->where('customer_account_type_id', '!=', $request->account_type) ->whereIn('status', ['actived', 'pending', 'rejected', 'closed']) ->first(); if ($differentTypeAccount) { // Sous-cas : Le compte existant est ACTIF -> On peut appeler l'API if ($differentTypeAccount->status == 'actived' && !empty($differentTypeAccount->customer_number)) { $customer_account_type = CustomerAccountType::find($request->account_type); if (!$customer_account_type) return $this->errorResponse(trans('errors.account_type_not_found')); try { $client = new Client(['connect_timeout' => 60]); $baseUrl = env('BANK_API_BASE_URL'); // Authentification $authResponse = $client->post($baseUrl . '/auth/authenticate', [ 'json' => ['login' => env('BANK_API_LOGIN'), 'password' => env('BANK_API_PASSWORD')] ]); $token = json_decode($authResponse->getBody(), true)['data']['token'] ?? null; if (!$token) { Log::error('Token introuvable pour user: ' . $request->id_user); return $this->errorResponse(trans('errors.token_not_found'), 404); } // Ouverture du compte lié via API $response = $client->post($baseUrl . '/clients/' . $differentTypeAccount->customer_number . '/account', [ 'headers' => ['Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json'], 'json' => ['productCode' => $customer_account_type->product] ]); $result = json_decode($response->getBody(), true); if ($response->getStatusCode() <= 301 && ($result['success'] ?? true) != false) { $newAccount = new UserBankAccount($commonAccountData); $newAccount->account_number = $result['accountNumber'] ?? null; $newAccount->customer_number = $result['clientMatricul'] ?? null; $newAccount->reason = trans('messages.user_bank_account_activated_successfully'); $newAccount->status = 'actived'; $newAccount->save(); $user->update([ 'id_bank_country' => $newAccount->id_operator_country, 'iban' => $result['accountNumber'] ?? null ]); $message = trans('messages.user_bank_account_activated_successfully', [ 'bank' => $network_bank->operators_country->operator->nom ?? 'votre banque', 'account_number' => $newAccount->account_number ]); // 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()); return $this->errorResponse($result['message'] ?? trans('errors.bank_api_exception'), 500); } catch (\Exception $e) { Log::error('Exception API Banque User: ' . $request->id_user . ' Error: ' . $e->getMessage()); return $this->errorResponse(trans('errors.bank_api_exception'), 500); } } // Sous-cas : Le compte existant est en PENDING -> Bloquer // (On ne peut pas appeler l'API si on n'a pas encore de matricule client du 1er compte) if (in_array($differentTypeAccount->status, ['pending', 'rejected', 'closed'])) { $statusMessages = [ 'actived' => trans('messages.user_already_has_bank_account_with_this_operator', ['user_lastname' => $user->lastname]), 'pending' => trans('errors.you_already_have_request_in_progress_unvalidated'), 'rejected' => trans('errors.your_previous_request_for_this_product_was_rejected'), 'closed' => trans('errors.your_previous_request_for_this_product_was_closed'), ]; return $this->errorResponse($statusMessages[$differentTypeAccount->status] ?? 'Error', 500); } } // 4. CAS STANDARD : Premier compte chez cet opérateur -> Création "Pending" $account_type = CustomerAccountType::find($request->account_type); if (!$account_type) return $this->errorResponse(trans('errors.account_type_not_found')); $bankAccount = new UserBankAccount($commonAccountData); $bankAccount->status = 'pending'; $bankAccount->save(); try { $bankAccount->update(['reason' => trans('messages.request_bank_account_pending_validation_by_administrator')]); return $this->successResponse(['message' => trans('messages.successful_bank_account_creation')]); } catch (\Exception $e) { $bankAccount->update(['status' => 'rejected', 'reason' => $e->getMessage()]); Log::error('Erreur Creation Compte: ' . $e->getMessage()); return $this->errorResponse(trans('errors.bank_api_exception')); } } public function activateUserBankAccount(Request $request) { $this->validate($request, [ 'id' => 'required|integer|exists:user_bank_accounts,id', 'doc_front' => 'required|url', 'doc_back' => 'required|url', ]); // 1. Récupération des données avec chargement des relations $bank_account = UserBankAccount::with('user')->find($request->id); if (!$bank_account) return $this->errorResponse(trans('errors.account_type_not_found')); $user = $bank_account->user; if (!$user) return $this->errorResponse(trans('errors.user_not_found')); $account_type = CustomerAccountType::find($bank_account->customer_account_type_id); if (!$account_type) return $this->errorResponse(trans('errors.account_type_not_found')); // 2. Préparation des variables API $baseUrl = env('BANK_API_BASE_URL'); $login = env('BANK_API_LOGIN'); $password = env('BANK_API_PASSWORD'); $name_of_account_type = $account_type->name; $payload = [ 'phoneNumber' => $bank_account->phone_number ?? $user->phone , 'email' => $user->email ?? '', 'fullname' => $bank_account->firstname . ' ' . $bank_account->lastname, 'branchCode' => env('BANK_API_BRANCH_CODE'), 'dateOfBirth' => $bank_account->birth_date, 'isMarried' => ($bank_account->marital_status === 'marie') ? 'Yes' : 'No', 'nameOfSpouse' => $bank_account->spouse_name ?? '', 'city' => $bank_account->birth_city ?? '', 'accountType' => $name_of_account_type, 'originalNationality' => $bank_account->nationality, 'countryOfResidence' => $bank_account->birth_country, 'employersName' => $bank_account->employer_name ?? '', 'employersAddress' => $bank_account->employer_address ?? '', 'employersCity' => $bank_account->employer_city ?? '', 'product' => $account_type->product ?? '', 'identificationNumber' => $bank_account->identification_number, 'paySlip' => $request->doc_front, 'signatureCard' => $request->doc_back, 'custRelCode' => env('BANK_API_CUSTOMER_REL_CODE','') ]; try { $client = new Client(['connect_timeout' => 60]); $authResponse = $client->post($baseUrl . '/auth/authenticate', [ 'json' => [ 'login' => $login, 'password' => $password ] ]); $authResult = json_decode($authResponse->getBody(), true); $token = $authResult['data']['token'] ?? null; if (!$token) { Log::error('Token introuvable (Activation) pour compte ID: ' . $bank_account->id); return $this->errorResponse(trans('errors.token_not_found'), 404); } $response = $client->post($baseUrl . '/clients/create-with-account', [ 'headers' => [ 'Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json', ], 'json' => $payload, ]); $result = json_decode($response->getBody(), true); if ($response->getStatusCode() == 200 || $response->getStatusCode() == 201) { $bank_account->update([ 'status' => 'actived', 'reason' => 'Compte activé avec succès !', 'account_number' => $result['accountNumber'] ?? null, 'customer_number' => $result['clientCode'] ?? null ]); $user->update([ 'id_bank_country' => $bank_account->id_operator_country, 'iban' => $result['accountNumber'] ?? null ]); LOG::info(' Compte activé avec succès ! Numero du compte bancaire du User : ' . $user->id . ' : ' . ($user->iban ?? 'N/A')); try { 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', ['bank' => 'SunEx','account_number' => $bank_account->account_number]), 200); } return $this->errorResponse('Erreur lors de l\'activation API', 500); } catch (RequestException $e) { $errorBody = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage(); $bank_account->update([ 'status' => 'rejected', 'reason' => 'Une Erreur est survenue lors de l\'activation de votre compte bancaire, veuillez réessayer plus tard ou contacter le support client.' ]); Log::error('Erreur Activation API pour ID ' . $bank_account->id . ' : ' . $errorBody); return $this->errorResponse('Error_occurred', 500); } } public function getCustomerAccountTypes() { $account_types = CustomerAccountType::all(['id', 'name']); return $this->successResponse($account_types); } public function validateLinkUserBankAccount(Request $request) { $this->validate($request, [ 'iban' => 'required', 'id_transaction' => 'required' ]); $user_bank_account_verfication = UsersBankingAccountVerification::where('id_transaction', $request->id_transaction)->first(); if (!$user_bank_account_verfication) { return $this->errorResponse(trans('errors.transaction_not_found'), 404); } $user = User::where('user_code', $user_bank_account_verfication->user_code)->firstOrFail();($user_bank_account_verfication->user_code); if (!$user) { return $this->errorResponse(trans('errors.user_not_found'), 404); } $baseUrl = env('BANK_API_BASE_URL',); $login = env('BANK_API_LOGIN'); $password = env('BANK_API_PASSWORD'); $authApi = $baseUrl . '/auth/authenticate'; $accountApi = $baseUrl . '/account/getOne/' . $request->iban; try { $client = new Client(); $authResponse = $client->post($authApi, [ 'json' => [ 'login' => $login, 'password' => $password ], 'connect_timeout' => 60, ]); $authResult = json_decode($authResponse->getBody(), true); $token = $authResult['data']['token'] ?? null; if (!$token) { Log::error('Token introuvable dans la réponse auth pour transaction: ' . $request->id_transaction); return $this->errorResponse(trans('errors.token_not_found'), 404); } $response = $client->get($accountApi, [ 'headers' => [ 'Authorization' => 'Bearer ' . $token, 'Accept' => 'application/json', ], 'connect_timeout' => 60, ]); $result = json_decode($response->getBody(), true); 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->account_number, 'id_bank_country' => $user_bank_account_verfication->id_bank_country ]); Log::info('Compte bancaire rattaché avec succès pour transaction: ' . $request->id_transaction); try { Mail::to($user->email)->send(new BankAccountLinked($user_bank_account_verfication)); } catch (\Exception $e) { 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); } } catch (RequestException $e) { $errorBody = $e->hasResponse() ? (string) $e->getResponse()->getBody() : $e->getMessage(); $decodedBody = json_decode($errorBody, true); $extractedMessage = $decodedBody['message'] ?? $errorBody; $user_bank_account_verfication->update([ 'is_verified' => 2, 'was_treated' => 0, ]); Log::error('Erreur API Bank Link pour transaction ' . $request->id_transaction . ' : ' . $extractedMessage); return $this->errorResponse('Account: '. $request->iban . ', ' . $extractedMessage ?? trans('errors.Error_occurred'), 500); } catch (\Exception $e) { Log::error('Erreur inattendue Bank Link : ' . $e->getMessage()); return $this->errorResponse(trans('errors.Error_occurred')); } } }