validate($request, [ 'type_caution' => 'required|in:groupe,individuel', 'duree_mois' => 'required|integer|min:0|not_in:0', 'id_user' => 'required|integer|min:0|not_in:0', 'password' => 'required', 'montant' => 'required|numeric|min:0|not_in:0', ]); $user = User::findOrFail($request->id_user); if (!$this->checkPassword($request->password, $user->encrypted_password, $user->salt)) return $this->errorResponse(trans('messages.incorrect_user_password')); $identfication = $this->checkMyIdentification($request->id_user); if (!($identfication instanceof Identification)) return $identfication; $init_country = $user->network->country->id; $result = ConfigWallet::join('networks', 'networks.id', '=', 'configWallet.id_network') ->where('networks.country_id', $init_country)->where('configWallet.type', 'ilink') ->select('configWallet.id')->first(); if ($result) { $config = ConfigWallet::findOrFail($result->id); } else { return $this->errorResponse(trans('errors.no_ilink_network')); } if (!$config->has_nano_credit) return $this->errorResponse(trans('errors.nano_credit_not_available')); $taxes = array_values(array_filter($config->taxes->all(), function ($tax) { return $tax->categorie == 'nano_credit'; })); $paliers = array_values(array_filter($config->paliers_config_nano_credits->all(), function ($taux) { return $taux->type == 'nano_credit'; })); $demande_credit = new UsersDemandesCredit(); $demande_credit->fill($request->all()); $demande_credit->id_network = $config->id_network; // Derniere demande de nano credit $last_demand = UsersDemandesCredit::where('id_user', $request->id_user)->where('etat', 'VALIDE')->first(); if ($last_demand) return $this->errorResponse(trans('errors.last_nano_credit_not_refunded')); if ($request->type_caution == 'groupe') { $group = UsersGroup::find($user->group_id); if (!$group) return $this->errorResponse(trans('errors.not_belongs_to_any_group')); if (!$group->actif) return $this->errorResponse(trans('errors.your_group_not_active')); if ($group->nombre_utilisateurs < 10) return $this->errorResponse(trans('errors.your_group_not_valid')); if ($request->montant > $group->limite_credit || $request->montant < $config->limite_credit_min) return $this->errorResponse(trans('errors.nano_credit_amount_must_be_between_the_group_limit', ['min_limit' => $this->toMoney($config->limite_credit_min, $init_country), 'max_limit' => $this->toMoney($group->limite_credit, $init_country)])); //Verifier la capacité d'emprunt $CE = $this->capaciteEmprunt($group->id); if ($CE < 0) return $this->errorResponse(trans('errors.group_not_allow_to_borrow')); if ($request->montant > $CE) return $this->errorResponse(trans('errors.borrowing_capacity_exceeded')); //Verifier si le solde principal de l'hyperviseur est superieur au montant $walletHyper = WalletAgent::where('category', 'hyper')->where('network_id', $config->id_network)->firstOrFail(); $demande_credit->interet = $this->calculateFees($paliers, $request->montant, $request->duree_mois); $demande_credit->taxe = $this->calculateTax($taxes, $demande_credit->interet); $demande_credit->id_demande = $this->getNanoCreditDemandID(); if ($request->montant > $walletHyper->balance_princ) { $demande_credit->etat = 'EN_ATTENTE_DE_VALIDATION'; $demande_credit->save(); $demande = new UsersGroupsDemandesValidation(); $demande->id_group = $group->id; $demande->id_user = $user->id; $demande->id_demande = $demande_credit->id_demande; $demande->id_agent = $walletHyper->agent_id; $demande->date_creation = $this->getCurrentTime($init_country); $demande->type = 'nano_credit'; $demande->save(); $data = new \stdClass(); $data->screen = "notificationview"; $demande->statut = false; $data->data = new \stdClass(); $data->data->id = $demande->id; $this->sendPushNotificationToAgent($walletHyper->codeMembre, trans('notifications.group_nano_credit_request', ['name' => $group->nom]), $data, $demande->date_creation); return $this->successResponse(trans('messages.successful_nano_credit_sent_to_hypervisor')); } else { $walletHyper = Wallet::findOrFail($walletHyper->wallet_id); $walletUser = WalletsUser::where('idUser', $request->id_user)->firstOrFail(); $demande_credit->date_validation = $this->getCurrentTime($init_country); $demande_credit->date_creation = $demande_credit->date_validation; $demande_credit->date_remboursement_prevu = $demande_credit->date_validation->modify('+' . $request->duree_mois . ' month'); $demande_credit->etat = 'VALIDE'; $montant_total = $demande_credit->montant + $demande_credit->interet + $demande_credit->taxe; $user->balance_credit += $montant_total; $walletUser->balance += $demande_credit->montant; $walletHyper->balance_princ -= $demande_credit->montant; $user->save(); $walletUser->save(); $walletHyper->save(); $demande_credit->save(); $message = trans('messages.successful_user_group_nano_credit_demand', ['id_demand' => $demande_credit->id_demande, 'amount' => $this->toMoney($montant_total, $init_country), 'duration' => $demande_credit->duree_mois, 'net' => $this->toMoney($demande_credit->montant, $init_country), 'fees' => $this->toMoney($demande_credit->interet , $init_country), 'date' => $demande_credit->date_remboursement_prevu , 'tax' => $this->toMoney($demande_credit->taxe, $init_country)]); $this->sendMail($user->email, trans('messages.successful_nano_credit_demand'), $message); return $this->successResponse($message . trans('messages.sent_by_mail')); } } if ($request->type_caution == 'individuel') { $demande_credit->interet = $this->calculateFees($paliers, $request->montant, $request->duree_mois); $demande_credit->taxe = $this->calculateTax($taxes, $demande_credit->interet); $demande_credit->etat = 'EN_ATTENTE_DE_VALIDATION'; $montant_total = $demande_credit->montant + $demande_credit->interet + $demande_credit->taxe; $demande_credit->id_demande = $this->getNanoCreditDemandID(); $demande_credit->date_creation = $this->getCurrentTime($init_country); $demande_credit->save(); $message = trans('messages.successful_user_individual_nano_credit_demand', ['id_demand' => $demande_credit->id_demande, 'amount' => $this->toMoney($montant_total, $init_country), 'net' => $this->toMoney($demande_credit->montant, $init_country), 'duration' => $demande_credit->duree_mois, 'fees' => $this->toMoney($demande_credit->interet, $init_country), 'tax' => $this->toMoney($demande_credit->taxe, $init_country)]); $this->sendMail($user->email, trans('messages.successful_nano_credit_demand'), $message); return $this->successResponse($message . trans('messages.sent_by_mail')); } } // Demandes de nano credit et d'epargnes public function getAllNanoCreditsDemands($id_user, 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_user = :id ;", ['id' => $id_user]); $savings = DB::select("SELECT 'E' as type_historique , i.montant , i.user as destinataire, i.* FROM infos_users_epargnes i WHERE id_user = :id;", ['id' => $id_user]); // Supprimer les underscore sur les etats $merge = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, array_merge($demandes, $savings)); usort($merge, array($this, 'sortFunction')); // Trier le tout par date // return $this->successResponse($this->arrayPaginator($merge, $request)); return $this->successResponse($merge); } public function getNanoCreditsDemands($id_user) { $demandes = DB::select('SELECT i.montant , i.user as destinataire, i.* FROM infos_users_demandes_credits i WHERE i.id_user = :id ORDER BY i.date_creation DESC;', ['id' => $id_user]); $result = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, $demandes); return $this->successResponse($result); } // Demandes de credits en cours pour le remboursement public function getNanoCreditsDemandsInProgress($id_user) { $demandes = DB::select("SELECT type_caution , etat , montant , date_creation , id_demande , montant_rembourse ,partiellement_rembourse , duree_mois , interet , taxe , date_validation ,date_remboursement_prevu, retrait_cash , agent FROM infos_users_demandes_credits i WHERE i.id_user = :id AND i.etat = 'VALIDE' ORDER BY date_creation DESC;", ['id' => $id_user]); $result = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, $demandes); return $this->successResponse($result); } public function getGuaranteeNanoCreditsDemands($id_wallet_agent) { $demandes = DB::select('SELECT i.montant , i.user as destinataire, i.* FROM infos_users_demandes_credits i WHERE i.id_wallet_agent = :id ORDER BY i.date_creation DESC;' , ['id' => $id_wallet_agent]); $result = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, $demandes); return $this->successResponse($result); } public function getSavingsDemands($id_user) { $savings = DB::select('SELECT i.montant , i.user as destinataire, i.* FROM infos_users_epargnes i WHERE i.id_user = :id ORDER BY i.date_creation DESC;', ['id' => $id_user]); $result = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, $savings); return $this->successResponse($result); } // Demandes d'epargnes pour la cassation /** * @OA\Get( * path="/groups/nanoCredit/savings/demands_in_progress/{id_user}", * summary="Afficher la liste des épargnes en cours d'un utilisateur", * tags={"Historique des épargnes en cours"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="id_user", * name="id_user", * description="ID de l'utilisateur", * in="path", * required=true, * @OA\Schema( * type="integer", * default=12 * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {{ "type": "SIMPLE", "etat": "EN COURS", "montant": "5000.00", "date_creation": "2020-11-07 14:08:45", "id_epargne": "BVZ5NA3M", "duree_mois": null, "interet": "0.00", "taxe": "0.00", "date_fin": null * }}, * "error":null * } * ) * ) * ) */ public function getSavingsDemandsInProgress($id_user) { $savings = DB::select("SELECT i.type , etat, montant, date_creation , id_epargne , duree_mois , interet , taxe , date_fin FROM infos_users_epargnes i WHERE i.id_user = :id AND i.etat = 'EN_COURS' ORDER BY i.date_creation DESC;", ['id' => $id_user]); $result = array_map(function ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $demand; }, $savings); return $this->successResponse($result); } // Cautionner une demande de credit public function guaranteeCredit(Request $request) { $this->validate($request, [ 'id_demande' => 'required', 'id_wallet_agent' => 'required|integer|min:0|not_in:0', 'retrait_cash' => 'required|boolean', 'password' => 'required', ]); $walletAgent = Wallet::findOrFail($request->get('id_wallet_agent')); $network_agent = NetworksAgent::findOrFail($walletAgent->id_networkAgent); $agent_country = $network_agent->network->country->id; $agent = AgentPlus::findOrFail($network_agent->agent_id); if (!$this->checkPassword($request->password, $agent->encrypted_password, $agent->salt)) return $this->errorResponse(trans('messages.incorrect_user_password')); $demande_credit = UsersDemandesCredit::where('id_demande', $request->id_demande)->first(); $demande_credit->retrait_cash = $request->retrait_cash; if (!$demande_credit) return $this->errorResponse(trans('errors.nano_credit_not_found')); if ($demande_credit->type_caution != 'individuel') return $this->errorResponse(trans('errors.nano_credit_not_individual')); if ($demande_credit->etat == 'VALIDE') return $this->errorResponse(trans('messages.treated_demand')); $user = User::findOrFail($demande_credit->id_user); $user_country = $user->network->country->id; if ($user_country != $agent_country) return $this->errorResponse(trans('errors.operation_cannot_performed_in_country')); $montant_total = $demande_credit->montant + $demande_credit->interet + $demande_credit->taxe; if ($montant_total > $walletAgent->balance_princ) return $this->errorResponse(trans('errors.insufficient_balance')); $demande_credit->date_validation = $this->getCurrentTime($agent_country); $demande_credit->date_remboursement_prevu = $demande_credit->date_validation->modify('+' . $demande_credit->duree_mois . ' month'); $demande_credit->etat = 'VALIDE'; $demande_credit->id_wallet_agent = $walletAgent->id; $user->balance_credit += $montant_total; $walletAgent->balance_princ -= $montant_total; //Crediter le wallet de client s'il ne retire pas en cash if (!$request->retrait_cash) { $walletUser = WalletsUser::where('idUser', $demande_credit->id_user)->firstOrFail(); $walletUser->balance += $demande_credit->montant; $walletUser->save(); } $walletAgent->save(); $user->save(); $demande_credit->save(); $user_message = trans('messages.successful_guarantee_user_individual_nano_credit_demand', ['id_demand' => $demande_credit->id_demande, 'amount' => $this->toMoney($montant_total, $agent_country), 'duration' => $demande_credit->duree_mois, 'net' => $this->toMoney($demande_credit->montant, $agent_country), 'fees' => $this->toMoney($demande_credit->interet, $agent_country), 'tax' => $this->toMoney($demande_credit->taxe, $agent_country), 'date' => $demande_credit->date_remboursement_prevu, 'agent_name' => $agent->lastname . ' ' . $agent->firstname, 'code_agent' => $agent->code_membre]); $agent_message = trans('messages.successful_guarantee_agent_individual_nano_credit_demand', ['id_demand' => $demande_credit->id_demande, 'amount' => $this->toMoney($montant_total, $agent_country), 'duration' => $demande_credit->duree_mois, 'net' => $this->toMoney($demande_credit->montant, $agent_country), 'fees' => $this->toMoney($demande_credit->interet, $agent_country), 'tax' => $this->toMoney($demande_credit->taxe, $agent_country), 'date' => $demande_credit->date_remboursement_prevu, 'user_name' => $user->lastname . ' ' . $user->firstname, 'code_user' => $user->user_code]); $this->sendMail($user->email, trans('messages.successful_guarantee_nano_credit_demand'), $user_message); $this->sendMail($agent->email, trans('messages.successful_guarantee_nano_credit_demand'), $agent_message); return $this->successResponse($agent_message . trans('messages.sent_by_mail')); } public function refundCredit(Request $request) { $this->validate($request, [ 'id_demande' => 'required', 'id_user' => 'required|integer|min:0|not_in:0', 'password' => 'required', ]); $user = User::findOrFail($request->id_user); if (!$this->checkPassword($request->password, $user->encrypted_password, $user->salt)) return $this->errorResponse(trans('messages.incorrect_user_password')); $walletUser = WalletsUser::where('idUser', $request->id_user)->firstOrFail(); $demande_credit = UsersDemandesCredit::where('id_demande', $request->id_demande)->first(); if (!$demande_credit) return $this->errorResponse(trans('errors.nano_credit_not_found')); if ($demande_credit->etat == 'REMBOURSE') return $this->errorResponse(trans('errors.nano_credit_already_refunded')); $message = $this->refundNanoCredit($demande_credit, $user, $walletUser); return $this->successResponse($message . trans('messages.sent_by_mail')); } // Calculer la capacité d'emprunt private function capaciteEmprunt($id_group) { $users = User::where('group_id', $id_group)->get(); $sommeCredits = 0; $sommeEpargnes = 0; foreach ($users as $user) { $sommeCredits += $user->balance_credit; $sommeEpargnes += $user->balance_epargne; } return $sommeEpargnes - $sommeCredits; } // Recuperer les durees en mois public function getDurations(Request $request) { $this->validate($request , [ 'type' => 'required|in:nano_credit,epargne', 'id_user' => 'required|integer|min:0|not_in:0', ]); $user = User::findOrFail($request->id_user); $init_country = $user->network->country->id; $result = ConfigWallet::join('networks', 'networks.id', '=', 'configWallet.id_network') ->where('networks.country_id', $init_country)->where('configWallet.type', 'ilink') ->select('configWallet.id')->first(); if ($result) { $config = ConfigWallet::findOrFail($result->id); } else { return $this-> errorResponse(trans('errors.no_ilink_network')); } if (!$config->has_nano_credit) return $this->errorResponse(trans('errors.nano_credit_not_available')); $paliers = array_values(array_filter($config->paliers_config_nano_credits->all(), function ($taux) use ($request) { return $taux->type == $request->type; })); $mois = array_map(function ($palier) { return ['value' => $palier->duree_mois]; }, $paliers); return $this->successResponse($mois); } // Faire une epargne public function makeSavings(Request $request) { $this->validate($request, [ 'type' => 'required|in:simple,blocked', 'duree_mois' => 'required_if:type,blocked|integer|min:0|not_in:0', 'id_user' => 'required|integer|min:0|not_in:0', 'password' => 'required', 'montant' => 'required|numeric|min:0|not_in:0', ]); $user = User::findOrFail($request->id_user); if (!$this->checkPassword($request->password, $user->encrypted_password, $user->salt)) return $this->errorResponse(trans('messages.incorrect_user_password')); $init_country = $user->network->country->id; $result = ConfigWallet::join('networks', 'networks.id', '=', 'configWallet.id_network') ->where('networks.country_id', $init_country)->where('configWallet.type', 'ilink') ->select('configWallet.id')->first(); if ($result) { $config = ConfigWallet::findOrFail($result->id); } else { return $this->errorResponse(trans('errors.no_ilink_network')); } if (!$config->has_nano_credit) return $this->errorResponse(trans('errors.nano_credit_not_available')); $saving = new UsersEpargne(); $saving->fill($request->all()); $saving->id_network = $config->id_network; $sumFees = 0; $saving->date_creation = $this->getCurrentTime($init_country); if ($request->type == 'blocked') { $taxes = array_values(array_filter($config->taxes->all(), function ($tax) { return $tax->categorie == 'epargne'; })); $paliers = array_values(array_filter($config->paliers_config_nano_credits->all(), function ($taux) { return $taux->type == 'epargne'; })); $saving->interet = $this->calculateFees($paliers, $request->montant, $request->duree_mois); $saving->taxe = $this->calculateTax($taxes, $saving->interet); $saving->type = 'BLOQUE'; $saving->date_fin = $saving->date_creation->modify('+' . $request->duree_mois . ' month'); } else { $saving->interet = 0; $saving->taxe = 0; $saving->type = 'SIMPLE'; $saving->duree_mois = null; } $walletHyper = WalletAgent::where('category', 'hyper')->where('network_id', $config->id_network)->firstOrFail(); $walletHyper = Wallet::findOrFail($walletHyper->wallet_id); $walletUser = WalletsUser::where('idUser', $request->id_user)->firstOrFail(); $montant_total = $saving->montant + $saving->interet - $saving->taxe; if ($saving->montant > $walletUser->balance) return $this->errorResponse(trans('errors.insufficient_balance')); $saving->etat = 'EN_COURS'; $walletUser->balance -= $saving->montant; $user->balance_epargne += $montant_total; $walletHyper->balance_com -= ($saving->interet - $saving->taxe); $saving->id_epargne = $this->getSavingID(); $walletHyper->save(); $walletUser->save(); $user->save(); $saving->save(); $message = trans('messages.successful_saving') . trans($request->type == 'blocked' ? 'messages.successful_blocked_saving_details' : 'messages.successful_simple_saving_details', ['id_saving' => $saving->id_epargne, 'amount' => $this->toMoney($montant_total, $init_country), 'type' => $saving->type, 'net' => $this->toMoney($saving->montant, $init_country), 'fees' => $this->toMoney($saving->interet, $init_country), 'tax' => $this->toMoney($saving->taxe, $init_country), 'date' => $saving->date_fin, 'duration' => $saving->duree_mois]); $this->sendMail($user->email, trans('messages.successful_saving'), $message); return $this->successResponse($message . trans('messages.sent_by_mail')); } // Casser une epargne public function breakSavings(Request $request) { $this->validate($request, [ 'id_epargne' => 'required', 'id_user' => 'required|integer|min:0|not_in:0', ]); $saving = UsersEpargne::where('id_epargne', $request->id_epargne)->firstOrFail(); if ($saving->id_user != $request->id_user) return $this->errorResponse(trans('errors.not_authorized_to_process_request')); if ($saving->etat == 'CASSE') return $this->errorResponse(trans('errors.savings_already_broken')); $user = User::findOrFail($request->id_user); $init_country = $user->network->country->id; $walletUser = WalletsUser::where('idUser', $request->id_user)->firstOrFail(); if ($saving->type == 'BLOQUE') { $montant_total = $saving->montant + $saving->interet - $saving->taxe; } else { $montant_total = $saving->montant; } $user->balance_epargne -= $montant_total; $walletUser->balance += $montant_total; $saving->etat = 'CASSE'; $saving->date_cassation = $this->getCurrentTime($init_country); $user->save(); $walletUser->save(); $saving->save(); $message = trans('messages.successful_broken_saving') . trans($saving->type == 'BLOQUE' ? 'messages.successful_blocked_saving_details' : 'messages.successful_simple_saving_details', ['id_saving' => $saving->id_epargne, 'amount' => $this->toMoney($montant_total, $init_country), 'type' => $saving->type, 'net' => $this->toMoney($saving->montant, $init_country), 'fees' => $this->toMoney($saving->interet, $init_country), 'tax' => $this->toMoney($saving->taxe, $init_country), 'date' => $saving->date_fin, 'duration' => $saving->duree_mois]); $this->sendMail($user->email, trans('messages.successful_broken_saving'), $message); return $this->successResponse($message . trans('messages.sent_by_mail')); } public function getInfosNanoCredit($id_demand) { $demand = UsersDemandesCredit::where('id_demande', $id_demand)->first(); if ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $this->successResponse($demand); } else { return $this->errorResponse(trans('errors.nano_credit_not_found')); } } public function getInfosSavings($id_saving) { $demand = UsersEpargne::where('id_epargne', $id_saving)->first(); if ($demand) { $demand->etat = str_replace('_', ' ', $demand->etat); return $this->successResponse($demand); } else { return $this->errorResponse(trans('errors.savings_not_found')); } } public function getNanoCreditAccount($id_user){ $user = User::findOrFail($id_user); $data = new \stdClass(); $data->balance_credit = $user->balance_credit; $data->balance_epargne = $user->balance_epargne; return $this->successResponse($data); } // Calculer les interet private function calculateFees(array $paliers, $montant, $duree) { $size = sizeof($paliers); if ($size > 0) { $palier = null; foreach ($paliers as $p) { if ($p->duree_mois == $duree) { $palier = $p; break; } } if ($palier) { return $palier->taux * $montant / 100; } } return 0; } private function getNanoCreditDemandID() { do { $code = $this->generateGroupCode(); $result = collect(DB::select('SELECT * FROM users_demandes_credits WHERE id_demande = :code', ['code' => $code])); $codeCorrect = sizeof($result) < 0; } while ($codeCorrect); return $code; } private function getSavingID() { do { $code = $this->generateGroupCode(); $result = collect(DB::select('SELECT * FROM users_epargnes WHERE id_epargne = :code', ['code' => $code])); $codeCorrect = sizeof($result) < 0; } while ($codeCorrect); return $code; } }