user-service/app/Http/Controllers/CustomerAccountOpeningContr...

708 lines
33 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Enums\CreditCardType;
use App\Enums\DocumentType;
use App\Enums\Frequency;
use App\Enums\MaritalStatus;
use App\Enums\ResidentialStatus;
use App\Events\CustomerAccountRequestEvent;
use App\Exceptions\AppException;
use App\Models\CustomerAccountRequest;
use App\Models\CustomerAccountRequestDocument;
use App\Models\CustomerAccountType;
use App\Models\Identification;
use Illuminate\Http\Request;
use Illuminate\Support\Carbon;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Event;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
use Throwable;
class CustomerAccountOpeningController extends Controller
{
//
/**
* @OA\Post(
* path="/customers_accounts_requests",
* summary="Soumettre le formulaire d'ouverture de comptele",
* tags={"Agency Banking"},
* security={{"api_key":{}}},
* @OA\RequestBody(
* description="Corps de la requete",
* required=true,
* @OA\MediaType(
* mediaType="multipart/form-data",
* @OA\Schema(
* @OA\Property(property="user_id",
* type="integer",
* example=308,
* description="ID de l'utilisateur enregistré dans la base de données"
* ),
* @OA\Property(property="network_id",
* type="integer",
* example=4,
* description="ID du réseau auquel appartient il souhaitre faire sa demande"
* ),
* @OA\Property(property="customer_account_type_id",
* type="integer",
* example=101,
* description="ID du type de compte"
* ),
* @OA\Property(property="title",
* type="string",
* example = "Mr",
* description="Title"
* ),
* @OA\Property(property="lastname",
* type="string",
* example = "John",
* description="Noms"
* ),
* @OA\Property(property="firstname",
* type="string",
* example = "Doe",
* description="Prenoms"
* ),
* @OA\Property(property="spouse_name",
* type="string",
* example = "Bill",
* description="Nom Marital"
* ),
* @OA\Property(property="nationality",
* type="string",
* example = "Camerounaise",
* description="Nationalité"
* ),
* @OA\Property(property="birth_date",
* type="date",
* example = "1990-06-15",
* description=" Date de naissance"
* ),
* @OA\Property(property="birth_city",
* type="string",
* example = "Douala",
* description="Ville de naissance"
* ),
* @OA\Property(property="birth_country",
* type="string",
* example = "Cameroun",
* description="Pays de naissance"
* ),
* @OA\Property(property="birth_locality",
* type="string",
* example = "Akwa",
* description="Lieu exact de naissance"
* ),
* @OA\Property(property="father_lastname",
* type="string",
* example = "Doe",
* description="Nom du père"
* ),
* @OA\Property(property="father_firstname",
* type="string",
* example = "Doe",
* description="Prénom du père"
* ),
* @OA\Property(property="mother_birth_lastname",
* type="string",
* example = "Elize",
* description="Nom de naissance de la mère"
* ),
* @OA\Property(property="mother_firstname",
* type="string",
* example = "marie",
* description="Prénom de la mère"
* ),
* @OA\Property(property="marital_status",
* type="string",
* example = "SINGLE",
* description="Situation matrimoniale"
* ),
* @OA\Property(property="spouse_lastname",
* type="string",
* example = "",
* description="Nom du conjoint"
* ),
* @OA\Property(property="spouse_firstname",
* type="string",
* example = "",
* description="Prénom du conjoint"
* ),
* @OA\Property(property="profession",
* type="string",
* example = "Student",
* description="Profession"
* ),
* @OA\Property(property="business_activity",
* type="string",
* example = "",
* description="Secteur d'activité économique"
* ),
* @OA\Property(property="sub_sector_business_activity",
* type="string",
* example = "",
* description="Sous secteur d'activité"
* ),
* @OA\Property(property="tax_number",
* type="string",
* example = "",
* description="Numéro Fiscal"
* ),
* @OA\Property(property="security_number",
* type="string",
* example = "",
* description="Numéro de sécurité sociale"
* ),
* @OA\Property(property="employee_number",
* type="string",
* example = "",
* description="Numéro de l'employeur"
* ),
* @OA\Property(property="function",
* type="string",
* example = "",
* description="Fonction"
* ),
* @OA\Property(property="employee_name",
* type="string",
* example = "",
* description="Nom de l'employeur"
* ),
* @OA\Property(property="employee_address",
* type="string",
* example = "",
* description="Addresse de l'employeur"
* ),
* @OA\Property(property="residential_status",
* type="string",
* example = "RESIDENT",
* description="Status de résident"
* ),
* @OA\Property(property="residential_country",
* type="string",
* example = "Cameroun",
* description="Pays de résidence"
* ),
* @OA\Property(property="residence_permit_number",
* type="string",
* example = "",
* description="Numéro de permis de séjour"
* ),
* @OA\Property(property="residence_permit_issued_date",
* type="date",
* example = "",
* description="Date de délivrance du permis"
* ),
* @OA\Property(property="residence_permit_expiry_date",
* type="date",
* example = "",
* description="Date d'expiration du permis"
* ),
* @OA\Property(property="address_justification_doc",
* type="string",
* example = "LOCALISATION_PLAN",
* description="Justificatif d'adresse"
* ),
* @OA\Property(property="address",
* type="string",
* example = "Douala",
* description="Adresse géographique"
* ),
* @OA\Property(property="po_box",
* type="string",
* example = "",
* description="Adresse postale"
* ),
* @OA\Property(property="phone_number",
* type="string",
* example = "+237690716639",
* description="Numéro de téléphone"
* ),
* @OA\Property(property="email_1",
* type="string",
* example = "ddietchi@ilink-app.com",
* description="Email 1"
* ),
* @OA\Property(property="email_2",
* type="string",
* example = "",
* description="Email 2"
* ),
* @OA\Property(property="person_to_contact_in_case_of_needs_name",
* type="string",
* example = "Romeo Doe",
* description="Personne à contacter en cas de besoin"
* ),
* @OA\Property(property="person_to_contact_in_case_of_needs_phone_number",
* type="string",
* example = "+237699000102",
* description="Numéro de téléphone de la personne à contacter en cas de besoin"
* ),
* @OA\Property(property="identification_document_type",
* type="string",
* example = "CNI",
* description="Type de pièce"
* ),
* @OA\Property(property="identification_document_number",
* type="string",
* example = "0987654321",
* description="Numéro d'identification"
* ),
* @OA\Property(property="identification_document_issued_date",
* type="date",
* example = "2019-08-03",
* description="Date de délivrance du document"
* ),
* @OA\Property(property="identification_document_expiry_date",
* type="date",
* example = "2029-08-03",
* description="Date d'expiration du document"
* ),
* @OA\Property(property="identification_document_issuance_city",
* type="string",
* example = "Douala",
* description="Ville d'émission du document"
* ),
* @OA\Property(property="identification_document_issuance_country",
* type="string",
* example = "Cameroun",
* description="Pays d'émission du document"
* ),
* @OA\Property(property="customer_under_guardianship",
* type="boolean",
* example = "1",
* description="Client sous tutelle ?"
* ),
* @OA\Property(property="guardian_fullname",
* type="string",
* example = "",
* description="Nom(s) et Prénom(s) du tuteur"
* ),
* @OA\Property(property="guardian_phone_number",
* type="string",
* example = "",
* description="Numéro de téléphone du tuteur"
* ),
* @OA\Property(property="how_did_you_know_company",
* type="string",
* example = "",
* description="Comment avez vous connu l'entreprise ?"
* ),
* @OA\Property(property="introducer_fullname",
* type="string",
* example = "",
* description="Nom(s) et Prénom(s) de l'introducteur"
* ),
* @OA\Property(property="introducer_address",
* type="string",
* example = "",
* description="Adresse de l'introducteur"
* ),
* @OA\Property(property="expected_service",
* type="string",
* example = "Services bancaires",
* description="Service attendu"
* ),
* @OA\Property(property="income_sources_and_frequency",
* type="string",
* example = "",
* description="Fréquence de revenus et Plafond des transactions"
* ),
* @OA\Property(property="business_partners",
* type="string",
* example = "",
* description="Relation d'affaires"
* ),
* @OA\Property(property="bank_references",
* type="string",
* example = "",
* description="Référence bancaires"
* ),
* @OA\Property(property="has_account_with_other_bank",
* type="boolean",
* example = "1",
* description="Avez vous des comptes avec d'autres banques ?"
* ),
* @OA\Property(property="has_operative_other_bank_account",
* type="boolean",
* example = "1",
* description="Si oui, le compte est-il opérationnel ?"
* ),
* @OA\Property(property="has_engagement_with_other_banks",
* type="boolean",
* example = "0",
* description="Avez vous des engagements avec d'autres banques ?"
* ),
* @OA\Property(property="is_politically_exposed_person",
* type="boolean",
* example = "0",
* description="Le demandeur est-il une personne politiquement exposée ?"
* ),
* @OA\Property(property="is_politically_exposed_person_in_service",
* type="boolean",
* example = "0",
* description="En service ?"
* ),
* @OA\Property(property="has_relationship_with_politically_exposed_person",
* type="boolean",
* example = "0",
* description="Le demandeur est-il une relation avec des personnes politiquement exposées ?"
* ),
* @OA\Property(property="relationship_with_politically_exposed_person",
* type="string",
* example = "",
* description="Si oui, indiquez leurs noms et la nature de la relation"
* ),
* @OA\Property(property="email_alerts",
* type="boolean",
* example = "1",
* description="Alertes Email"
* ),
* @OA\Property(property="e_statement_frequency",
* type="string",
* example = "MONTHLY",
* description="Frequence Relevé bancaire"
* ),
* @OA\Property(property="e_package",
* type="boolean",
* example = "1",
* description="E Package"
* ),
* @OA\Property(property="debit_card_type",
* type="string",
* example = "VISA_CLASSIC",
* description="Type de carte de débit"
* ),
* @OA\Property(property="document1",
* type="file",
* description="Document 1"
* ),
* @OA\Property(property="document2",
* type="file",
* description="Document 2"
* ),
* )
* )
* ),
* @OA\Response(
* response=200,
* description="OK",
* @OA\JsonContent(
* ref="#/components/schemas/ApiResponse",
* example = {
* "status" : 200,
* "response" : "Demande d'ouverture de compte client soumise",
* "error":null
* }
* )
* )
* )
* @throws AppException
*/
public function submit(Request $request)
{
$this->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(),[
'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'));
}
public function getCustomerRequests($user_id)
{
$requests = CustomerAccountRequest::where('user_id', $user_id)->get();
return $this->successResponse($requests);
}
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,
'opening_amount' => $this->toMoneyWithNetwork($accountRequest->account_type->opening_amount, $accountRequest->network_id)
];
$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':
$accountRequest->status = CustomerAccountRequest::ACCEPTED;
$mailTitle = trans('messages.customer_account_opening_request_accepted');
$mailMessage = trans('messages.customer_account_opening_request_accepted_mail', $mailParams);
$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);
}
}