validate($request,[ 'user_id' => 'required|integer|exists:users,id', 'network_id' => 'required|integer|exists:networks,id', 'customer_account_type_id' => 'required|integer|exists:customer_account_types,id', 'title' => 'required|string', 'lastname' => 'required|string', 'firstname' => 'nullable|string', 'spouse_name' => 'nullable|string', 'nationality' => 'required|string', 'birth_date' => 'required|date_format:Y-m-d|before:today', 'birth_country' => 'required|string', 'birth_city' => 'required|string', 'birth_locality' => 'nullable|string', 'father_lastname' => 'required|string', 'father_firstname' => 'nullable|string', 'mother_birth_lastname' => 'required|string', 'mother_firstname' => 'nullable|string', 'marital_status' => 'required|string', 'spouse_lastname' => 'nullable|string', 'spouse_firstname' => 'nullable|string', 'profession' => 'nullable|string', 'business_activity' => 'nullable|string', 'sub_sector_business_activity' => 'nullable|string', 'tax_number' => 'nullable|string', 'security_number' => 'nullable|string', 'employee_number' => 'nullable|string', 'function' => 'nullable|string', 'employee_name' => 'nullable|string', 'employee_address' => 'nullable|string', 'residential_status' => 'required|string', 'residential_country' => 'required|string', 'residence_permit_number' => 'nullable|string', 'residence_permit_issued_date' => 'nullable|date_format:Y-m-d|before:today', 'residence_permit_expiry_date' => 'nullable|date_format:Y-m-d|after:residence_permit_issued_date', 'address_justification_doc' => 'required|string', 'address' => 'required|string', 'po_box' => 'nullable|string', 'phone_number' => 'required|string', 'email_1' => 'required|string', 'email_2' => 'nullable|string', 'person_to_contact_in_case_of_needs_name' => 'required|string', 'person_to_contact_in_case_of_needs_phone_number' => 'required|string', 'identification_document_type' => 'required|string', 'identification_document_number' => 'required|string', 'identification_document_issued_date' => 'required|date_format:Y-m-d|before:today', 'identification_document_expiry_date' => 'required|date_format:Y-m-d|after:identification_document_issued_date', 'identification_document_issuance_city' => 'required|string', 'identification_document_issuance_country' => 'required|string', 'customer_under_guardianship' => 'required|bool', 'guardian_fullname' => 'nullable|string', 'guardian_phone_number' => 'nullable|string', 'how_did_you_know_company' => 'required|string', 'introducer_fullname' => 'nullable|string', 'introducer_address' => 'nullable|string', 'expected_service' => 'required|string', 'income_sources_and_frequency' => 'nullable|string', 'business_partners' => 'nullable|string', 'bank_references' => 'nullable|string', 'has_account_with_other_bank' => 'required|bool', 'has_operative_other_bank_account' => 'required|bool', 'has_engagement_with_other_banks' => 'required|bool', 'is_politically_exposed_person' => 'required|bool', 'is_politically_exposed_person_in_service' => 'required|bool', 'has_relationship_with_politically_exposed_person' => 'required|bool', 'relationship_with_politically_exposed_person' => 'nullable|string', 'email_alerts' => 'required|bool', 'e_statement_frequency' => 'required|string', 'e_package' => 'nullable|bool', 'debit_card_type' => 'required|string', ]); $accountType = CustomerAccountType::with('documents')->find($request->input('customer_account_type_id')); $documents = []; if(!empty($accountType->documents)){ $rules[] = []; foreach ($accountType->documents as $document){ $rules[$document->name] = 'required|image|mimes:jpeg,png,jpg,jpeg|max:1024'; } $this->validate($request, $rules); foreach ($accountType->documents as $document){ $doc = []; $doc['name'] = $document->name; $doc['description'] = $document->description; $doc['url'] = $this->uploadImage($request,$document->name, 'CRD', 'requests-docs'); $documents[] = $doc; } } if(CustomerAccountRequest::where('user_id', $request->input('user_id'))->where('network_id', $request->input('network_id')) ->where('status', CustomerAccountRequest::UNDER_VALIDATION)->exists()){ return $this->errorResponse(__('messages.customer_account_opening_request_pending')); } try{ DB::beginTransaction(); $accountRequest = CustomerAccountRequest::create(array_merge($request->all(),[ 'opening_amount' => $accountType->opening_amount, 'unique_id' => strtoupper(Str::random(12)) ])); $documents = array_map(function ($row) use ($accountRequest) { $row['request_id'] = $accountRequest->id; $row['created_at'] = Carbon::now(); $row['updated_at'] = Carbon::now(); return $row; }, $documents); CustomerAccountRequestDocument::insert($documents); DB::commit(); }catch (Throwable $exception){ Log::error($exception->getMessage()); DB::rollBack(); return $this->errorResponse(trans('errors.unexpected_error'), 500); } $mailParams = ['name' => $accountRequest->user->lastname, 'request_id' => $accountRequest->unique_id, 'gender' => $accountRequest->title, 'account_type' => $accountRequest->account_type->name, 'opening_amount' => $this->toMoneyWithNetwork($accountRequest->account_type->opening_amount, $accountRequest->network_id) ]; Event::dispatch(new CustomerAccountRequestEvent($accountRequest, __('messages.customer_account_opening_request'), __('messages.customer_account_opening_request_mail',$mailParams))); return $this->successResponse(__('messages.customer_account_opening_request_submitted')); } /** * @OA\Get( * path="/customers_accounts_requests", * summary="Recuperer les demandes d'ouvertures", * tags={"Agency Banking"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="user_id", * name="user_id", * description="ID de l'utilisateur", * @OA\Schema( * type="integer" * ), * in="query", * required=false * ), * @OA\Parameter( * parameter="network_id", * name="network_id", * description="ID du reseau", * @OA\Schema( * type="integer", * ), * in="query", * required=false * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {{"id":19,"unique_id":"X4UK8JDG1Z0I","user_id":382,"network_id":239,"customer_account_type_id":4,"opening_amount":"80 000 FCFA", * "opening_amount_payment_deadline":"2022-12-13","status":"EN COURS DE VALIDATION","reject_reason":null,"created_at":"2022-11-28T18:06:09.000000Z","account_type":{"id":4,"name":"Compte courant regulier salarie"}}}, * "error":null * } * ) * ) * ) */ public function getRequests(Request $request) { $this->validate($request,[ 'user_id' => 'nullable|integer|exists:users,id', 'network_id' => 'nullable|integer|exists:networks,id' ]); $user_id = $request->input('user_id'); $network_id = $request->input('network_id'); $query = CustomerAccountRequest::with(['account_type:id,name']); $query->when($user_id, function ($q , $user_id){ $q->where('user_id', $user_id); }); $query->when($network_id, function ($q , $network_id){ $q->where('network_id', $network_id); }); $data = $query->select(['id','unique_id','user_id','network_id','customer_account_type_id','opening_amount','opening_amount_payment_deadline','status','reject_reason','created_at']) ->get(); $data->map(function ($row){ $this->formatCustomerRequest($row); }); return $this->successResponse($data); } /** * @OA\Get( * path="/customers_accounts_requests/{id}", * summary="Recuperer les details sur une demande d'ouverture", * tags={"Agency Banking"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="id", * name="id", * description="ID de la demande", * @OA\Schema( * type="integer" * ), * in="path", * required=true * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : { "id": 19, "unique_id": "X4UK8JDG1Z0I", "user_id": 382, "network_id": 239, "customer_account_type_id": 4, "title": "M", "lastname": "Doe", "firstname": "John", "spouse_name": null, "nationality": "Cameroun", "birth_date": "1988-03-01", "birth_country": "Cameroun", * "birth_city": "Douala", "birth_locality": null, "father_lastname": "Gates", "father_firstname": "", "mother_birth_lastname": "Marthe", "mother_firstname": null, "marital_status": "SINGLE", "spouse_lastname": null, "spouse_firstname": null, "profession": null, "business_activity": null, * "sub_sector_business_activity": null, "tax_number": null, "security_number": null, "employee_number": null, "function": null, "employee_name": null, "employee_address": null, "residential_status": "RESIDENT", "residential_country": "Cameroun", "residence_permit_number": null, * "residence_permit_issued_date": null, "residence_permit_expiry_date": null, "address_justification_doc": "LOCALISATION_PLAN", "address": "Douala", "po_box": null, "phone_number": "+237690716639", "email_1": "ddietchi@ilink-app.com", "email_2": null, "person_to_contact_in_case_of_needs_name": "Mark", * "person_to_contact_in_case_of_needs_phone_number": "+237690716630", "identification_document_type": "CNI", "identification_document_number": "1232266", "identification_document_issued_date": "2019-03-10", "identification_document_expiry_date": "2039-03-10", "identification_document_issuance_city": "Douala", * "identification_document_issuance_country": "Cameroun", "customer_under_guardianship": 0, "guardian_fullname": null, "guardian_fullname_phone_number": null, "how_did_you_know_company": "medias", "introducer_fullname": null, "introducer_address": null, "expected_service": "banking", "income_sources_and_frequency": null, * "business_partners": null, "bank_references": null, "has_account_with_other_bank": 0, "has_operative_other_bank_account": 0, "has_engagement_with_other_banks": 1, "is_politically_exposed_person": 0, "is_politically_exposed_person_in_service": 0, "has_relationship_with_politically_exposed_person": 0, * "relationship_with_politically_exposed_person": null, "email_alerts": 1, "e_statement_frequency": "DAILY", "e_package": 0, "debit_card_type": "CLASSIC_GOLD", "opening_amount": "80 000 FCFA", "opening_amount_payment_deadline": "2022-12-13", "status": "EN COURS DE VALIDATION", "reject_reason": null, * "validating_agent_id": null, "created_at": "2022-11-28T18:06:09.000000Z", "updated_at": "2022-11-28T18:06:09.000000Z", "deleted_at": null, "account_type": { "id": 4, "name": "Compte courant regulier salarie" }, "documents": { { "request_id": 19, "name": "photo", "description": "photo", * "url": "http://127.0.0.1:8088/requests-docs/CRD-23ccdda9-d234-4c18-a8b8-d637295b89c3.png" } } }, * "error":null * } * ) * ) * ) */ public function getSingleRequest($id) { $accountRequest = CustomerAccountRequest::with(['account_type:id,name','documents:request_id,name,description,url'])->where('id', $id)->firstOrFail(); $this->formatCustomerRequest($accountRequest); return $this->successResponse($accountRequest); } public function treatRequest($id, Request $request) { $this->validate($request, [ 'nh_validating_agent_id' => 'required_without:agent_id|nullable|integer|exists:nh_validating_agents,id', 'agent_id' => 'required_without:nh_validating_agent_id|nullable|integer|exists:agents,id', 'type' => 'required|in:ACCEPT,REJECT,MORE_INFORMATION', 'reason' => 'nullable|string' ]); $accountRequest = CustomerAccountRequest::findOrFail($id); if(!in_array($accountRequest->status,[CustomerAccountRequest::UNDER_VALIDATION, CustomerAccountRequest::AWAITING_FURTHER_INFORMATION])){ return $this->errorResponse(__('errors.request_already_processed')); } try { DB::beginTransaction(); $datetime = $this->getCurrentTimeByCountryCode($accountRequest->user->network->country->code_country); $type = $request->input('type'); $mailParams = ['name' => $accountRequest->user->lastname, 'request_id' => $accountRequest->unique_id, 'reason' => $request->input('reason'), 'gender' => $accountRequest->title, 'account_type' => $accountRequest->account_type->name, ]; $notificationParams = ['request_id' => $accountRequest->unique_id]; switch ($type){ case 'REJECT': $accountRequest->status = CustomerAccountRequest::REJECTED; $mailTitle = trans('messages.customer_account_opening_request_rejected'); $mailMessage = trans('messages.customer_account_opening_request_rejected_mail', $mailParams); $notification = trans('messages.customer_account_opening_request_rejected_notification', $notificationParams); break; case 'ACCEPT': if(!empty($accountRequest->opening_amount)){ $mailParams['opening_amount'] = $this->toMoneyWithNetwork($accountRequest->opening_amount, $accountRequest->network_id); $accountRequest->status = CustomerAccountRequest::ACCEPTED_UNPAID; $accountRequest->opening_amount_payment_deadline = Carbon::now()->addDays($accountRequest->account_type->opening_amount_payment_period_days); $mailParams['deadline'] = $accountRequest->opening_amount_payment_deadline; $mailMessage = trans('messages.customer_account_opening_request_accepted_unpaid_mail', $mailParams); }else{ $accountRequest->status = CustomerAccountRequest::ACCEPTED; $mailMessage = trans('messages.customer_account_opening_request_accepted_mail', $mailParams); } $mailTitle = trans('messages.customer_account_opening_request_accepted'); $notification = trans('messages.customer_account_opening_request_accepted_notification', $notificationParams); break; default: $accountRequest->status = CustomerAccountRequest::AWAITING_FURTHER_INFORMATION; $mailTitle = trans('messages.customer_account_opening_request_awaiting_more_information'); $mailMessage = trans('messages.customer_account_opening_request_awaiting_more_information_mail', $mailParams); $notification = trans('messages.customer_account_opening_request_awaiting_more_information_notification', $notificationParams); } $accountRequest->validating_agent_id = $request->input('nh_validating_agent_id') ?? $request->input('agent_id'); $accountRequest->reject_reason = $request->input('reason'); $accountRequest->updated_at = $datetime; $accountRequest->save(); Event::dispatch(new CustomerAccountRequestEvent($accountRequest, $mailTitle, $mailMessage, $notification)); DB::commit(); return $this->successResponse(trans('messages.successful_transaction')); } catch (Throwable $e) { Log::error($e->getMessage() . '\n' . $e->getTraceAsString()); DB::rollBack(); return $this->errorResponse(trans('errors.unexpected_error'), 500); } } /** * @OA\Get( * path="/customers_accounts_requests/formData", * summary="Recuperer les informations necessaires avant la soumission du formulaire", * tags={"Agency Banking"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="user_id", * name="user_id", * description="ID de l'utilisateur", * @OA\Schema( * type="integer" * ), * in="query", * required=true * ), * @OA\Parameter( * parameter="network_id", * name="network_id", * description="ID du reseau", * @OA\Schema( * type="integer", * ), * in="query", * required=true * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {"identification": { "id": 15, "firstname": "", "lastname": " John doe", "birth_date": "2020-07-28T00:00:00.000000Z", "gender": "M", "town": "Libreville", "country": "Gabon", "identity_document": "Carte d'identité", * "id_identity_document": "1234567890", "expiry_date_document": "2020-07-28T00:00:00.000000Z", "id_user": 321, "status": 1, "createdAt": "2020-07-28T17:01:26.000000Z", "user_image": null, "document_image_front": null, "document_image_back": null, * "idNetwork": 239, "country_id": null }, "customer_account_types": {{ "id": 1, "name": "Compte courant", "description": null, "children": {{ "id": 4, "name": "Compte courant regulier salarie", "description": "Compte courant regulier", "parent_id": 1, * "documents": { { "name": "photo", "description": "photo", "account_type_id": 4 } } } } } }, "marital_status": { { "title": "Single", "value": "SINGLE" } }, "residential_status": { { "title": "Résident", "value": "RESIDENT" } }, * "address_justification_docs": { { "title": "Plan de localisation", "value": "LOCALISATION_PLAN" } }, "e_statement_frequencies": { { "title": "Daily", "value": "DAILY" } }, "debit_card_types": { { "title": "MASTER Card Classic", * "value": "MASTER_CARD_CLASSIC" } }}, * "error":null * } * ) * ) * ) */ // Fetch mandatory form data before submit request public function getFormData(Request $request) { $this->validate($request,[ 'user_id' => 'required|integer|exists:users,id', 'network_id' => 'required|integer|exists:networks,id', ]); if(CustomerAccountRequest::where('user_id', $request->input('user_id'))->where('network_id', $request->input('network_id')) ->where('status', CustomerAccountRequest::UNDER_VALIDATION)->exists()){ return $this->errorResponse(__('messages.customer_account_opening_request_pending')); } $data['identification'] = Identification::where('id_user',$request->input('user_id'))->first(); $data['customer_account_types'] = CustomerAccountType::has('children')->with(['children:id,name,description,parent_id','children.documents:name,description,account_type_id']) ->where('network_id',$request->input('network_id'))->select(['id','name','description'])->get(); foreach (MaritalStatus::all() as $key => $value){ $data['marital_status'][] = [ 'title' => $value, 'value' => $key ]; } foreach (ResidentialStatus::all() as $key => $value){ $data['residential_status'][] = [ 'title' => $value, 'value' => $key ]; } foreach (DocumentType::all() as $key => $value){ $data['address_justification_docs'][] = [ 'title' => $value, 'value' => $key ]; } foreach (Frequency::all() as $key => $value){ $data['e_statement_frequencies'][] = [ 'title' => $value, 'value' => $key ]; } foreach (CreditCardType::all() as $key => $value){ $data['debit_card_types'][] = [ 'title' => $value, 'value' => $key ]; } return $this->successResponse($data); } /** * @OA\Post( * path="/customers_accounts_requests/pay", * summary="Payer le montant requis pour la demande d'ouverture du compte", * tags={"Agency Banking"}, * security={{"api_key":{}}}, * @OA\RequestBody( * description="Corps de la requete", * required=true, * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property(property="user_id", * type="integer", * example = 10, * description="ID de l'utilisateur" * ), * @OA\Property( property="password", * type="string", * example = "1234", * description="Mot de passe de l'utilisateur" * ), * @OA\Property( property="request_id", * type="integer", * example = 39, * description="ID de la demande d'ouverture de compte" * ), * @OA\Property(property="payment_method", * type="string", * enum = {"wallet" ,"mobile_money","card"}, * example = "wallet", * description="Methode de paiement" * ), * @OA\Property(property="payment_phone", * type="string", * example = "+237690716639", * description="Numero de telephone avec lequel on souhaite payer de paiement" * ), * @OA\Property(property="payment_transaction_id", * type="string", * example = "ASMFOSDFFDODF", * description="ID de la transaction de paiement" * ), * @OA\Property(property="payment_token", * type="string", * example = "ASMFOSDFFDODF", * description="Token la transaction de paiement" * ) * ) * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : "Transaction réussie", * "error":null * } * ) * ) * ) */ public function payOpeningAmount(Request $request) { $this->validate($request, [ 'request_id' => 'required|integer|exists:customer_account_opening_requests,id', 'user_id' => 'required|integer|exists:users,id', 'password' => 'required', 'payment_method' => 'required|string', //wallet,MTN-Money,Orange-Money 'payment_phone' => 'required_unless:payment_method,wallet,cash|string', 'payment_transaction_id' => 'nullable|exists:payment_transactions,transaction_id', // A envoyer apres avoir effectuer le paiement 'payment_token' => 'required_with:payment_transaction_id|string', // A envoyer apres avoir effectuer le paiement, 'otp' => 'nullable|string' ]); $payment_method = $request->input('payment_method'); $transaction_id = $request->input('payment_transaction_id'); $accountRequest = InfosCustomerAccountOpeningRequest::findOrFail($request->input('request_id')); if($accountRequest->status != CustomerAccountRequest::ACCEPTED_UNPAID){ return $this->errorResponse(__('errors.request_already_processed')); } $user = User::findOrFail($request->input('user_id')); if (!$this->checkPassword($request->input('password'), $user->encrypted_password, $user->salt)) return $this->errorResponse(trans('messages.incorrect_user_password')); $county = $user->network->country; $amountToPaid = $accountRequest->opening_amount; if (empty($transaction_id)) { switch ($payment_method) { case 'wallet': $walletUser = WalletsUser::where('idUser', $user->id)->firstOrFail(); if ($walletUser->balance < $amountToPaid) { return $this->errorResponse(trans('errors.insufficient_balance', ['amount' => $this->toMoneyWithCurrencyCode($amountToPaid, $accountRequest->currency_code)])); } break; default : $aggregator = PaymentAggregator::where('status', 1)->first(); if (!$aggregator) { return $this->errorResponse(trans('errors.payment_not_available')); } } } else { $transaction = PaymentTransaction::where('transaction_id', $transaction_id)->where('payment_token', $request->input('payment_token'))->where('state', 'ACCEPTED')->first(); if (!$transaction) { return $this->errorResponse(trans('errors.payment_not_found'), 404); } if (!CustomerAccountRequest::where('payment_transaction_id', $transaction->id)->exists()) { return $this->errorResponse(trans('errors.payment_invalid'), 400); } } $hyperviseur = AgentPlus::where('category', 'hyper')->where('network_id', $accountRequest->network_id)->firstOrFail(); $walletHyperviseur = Wallet::where('id_networkAgent', $hyperviseur->network_agent_id)->firstOrFail(); $datetime = $this->getCurrentTimeByCountryCode($county->code_country); try { DB::beginTransaction(); if (empty($transaction_id)) { if ($payment_method == 'wallet') { $walletHyperviseur->balance_princ += $amountToPaid; $walletHyperviseur->save(); $walletUser->balance -= $amountToPaid; $walletUser->save(); } else { // Pay through payment service $client = new Client([ 'base_uri' => config('variables.payment_service_url'), 'headers' => [ 'Authorization' => config('variables.payment_service_key'), ] ]); $paymentResponse = $client->post('/pay', [ 'json' => [ 'aggregator_id' => $aggregator->id, 'amount' => config('variables.payment_test_amount', $amountToPaid), 'currency' => $accountRequest->currency_code, 'customer_id' => $user->id, 'customer_email' => $user->email, 'customer_name' => $user->lastname, 'customer_surname' => $user->lastname, 'customer_phone_number' => $request->input('payment_phone'), 'customer_address' => $user->adresse, 'customer_country' => $county->code_country ?? 'CM', 'customer_city' => $user->adresse, 'customer_state' => $county->code_country ?? 'CM', 'customer_zip_code' => '00237', 'payment_method' => $payment_method, 'reason' => 'N° '.__('messages.customer_account_opening_request').": ".$accountRequest->unique_id, 'otp' => $request->input('otp') ], 'http_errors' => false ]); $responseData = json_decode($paymentResponse->getBody()->getContents()); $responseCode = $paymentResponse->getStatusCode(); if ($responseCode == 200) { // $transaction_id = $responseData->response->transaction_id; return $this->successResponse($responseData->response); } else { return $this->errorResponse($responseData->error ?? trans('errors.unexpected_error'), $responseCode); } } } CustomerAccountRequest::where('id', $accountRequest->id)->update([ 'status' => CustomerAccountRequest::ACCEPTED_PAID, 'payment_transaction_id' => $transaction?->id, 'updated_at' => $datetime ]); DB::commit(); $mailParams = ['name' => $accountRequest->lastname, 'request_id' => $accountRequest->unique_id, 'gender' => $accountRequest->title, 'account_type' => $accountRequest->customer_account_type_name, 'opening_amount' => $this->toMoneyWithCurrencyCode($accountRequest->opening_amount, $accountRequest->currency_code) ]; $mailTitle = trans('messages.customer_account_opening_request_paid_mail_title'); $mailMessage = trans('messages.customer_account_opening_request_paid_mail_body', $mailParams); $notification = trans('messages.customer_account_opening_request_paid_notification'); Event::dispatch(new CustomerAccountRequestEvent($accountRequest, $mailTitle, $mailMessage, $notification)); } catch (Throwable $e) { DB::rollBack(); Log::error($e->getMessage()); return $this->errorResponse(trans('errors.unexpected_error')); } return $this->successResponse(trans('messages.successful_paid_receipt'),Response::HTTP_CREATED); } }