validate($request, [ 'network_agent_id' => 'required|integer|exists:networks_agents,id' ]); $network_agent_id = $request->input('network_agent_id'); $agent = AgentPlus::where('network_agent_id', $network_agent_id)->first(); $hyper = AgentPlus::where('network_id', $agent->network_id)->where('category', 'hyper')->first(); $config = NhNetworksConfig::where('network_id', $agent->network_id)->first(); if (!isset($config)) { return $this->errorResponse(__('errors.nano_health_not_activated')); } // executer le script chaque Dimanche a minuit $start_at = new DateTime(); switch ($config->provider_billing_period) { case BillingPeriodType::WEEKLY: $start_at->modify('-7 days'); break; case BillingPeriodType::BIMONTHLY: $start_at->modify('-14 days'); break; case BillingPeriodType::MONTHLY: $start_at->modify('-28 days'); break; default: $start_at = new DateTime(); } $end_at = new DateTime(); $invoice_id = $this->generateInvoiceID($agent->code_membre); $country = CountriesCurrency::findOrFail($agent->country_id); $datetime = $this->getCurrentTimeByCountryCode($country->code_country); $totalInsurerAmount = 0; $totalInsuredAmount = 0; $sheets = NhHealthCareSheet::with(['insurance'])->where('network_agent_id', $network_agent_id)->where('state', InsuranceSubscriptionState::ACCEPTED) ->where('created_at', '>=', $start_at)->where('created_at', '<=', $end_at)->orderBy('created_at', 'DESC')->get(); if (sizeof($sheets) == 0) { return $this->errorResponse(__('errors.no_sheet_available')); } foreach ($sheets as $sheet) { $totalInsuredAmount += $sheet->insured_amount; $totalInsurerAmount += $sheet->insurance_amount; $sheet->date = $sheet->created_at->format('d/m/Y'); } try { DB::beginTransaction(); $directoryName = '/invoices-docs/'; $filename = $start_at->format('dmY') . '_' . $end_at->format('dmY') . '_' . $agent->code_membre . '_' . time() . '.pdf'; $invoice = NhInvoice::create([ 'invoice_id' => $invoice_id, 'network_agent_id' => $agent->network_agent_id, 'amount' => $totalInsuredAmount + $totalInsurerAmount, 'insured_amount' => $totalInsuredAmount, 'insurer_amount' => $totalInsurerAmount, 'period_start_at' => $start_at, 'period_end_at' => $end_at, 'file_url' => config('services.app_url') . $directoryName . $filename, 'created_at' => $datetime, 'updated_at' => $datetime ]); $invoice->amount = $this->toMoneyWithCurrencyCode($invoice->amount, $country->currency_code); $invoice->insured_amount = $this->toMoneyWithCurrencyCode($invoice->insured_amount, $country->currency_code); $invoice->insurer_amount = $this->toMoneyWithCurrencyCode($invoice->insurer_amount, $country->currency_code); // $invoice->home_visit_fees = $this->toMoneyWithCurrencyCode($invoice->home_visit_fees, $country->currency_code); $ids = array_map(function ($r) { return $r['id']; }, $sheets->toArray()); DB::update("UPDATE nh_health_care_sheets SET state = :state_ , invoice_id = :id WHERE id IN (" . implode(',', $ids) . ")", ['id' => $invoice->id, 'state_' => InsuranceSubscriptionState::INVOICE_ISSUED]); $invoice->sheets = $sheets; $invoice->agent = $agent; $invoice->hyper = $hyper; $invoice->period = $start_at->format('d/m/Y') . ' ' . trans('messages.to') . ' ' . $end_at->format('d/m/Y'); //Check if the directory already exists. if (!is_dir(public_path($directoryName))) { //Directory does not exist, so lets create it. mkdir(public_path($directoryName), 0755); } $title = $agent->lastname . ' - ' . trans('messages.invoice') . ' ' . $invoice->invoice_id; $message = __('messages.generated_invoice_mail', ['agent' => $agent->lastname, 'period' => $invoice->period]); $file = PDF::loadView('emails.invoice', $invoice->toArray())->setPaper('a4', 'landscape')->setWarnings(false)->save(public_path($directoryName . $filename)); DB::commit(); $recipients = [preg_replace("/\s+/", "", $hyper->email)]; // Supprimer les espaces dans le mail Mail::mailer('smtp')->raw($message, function ($message) use ($recipients, $title, $file) { $message->subject($title) ->to($recipients) ->attachData($file->output(), str_replace(' ', '-', $title) . '.pdf'); }); } catch (\Throwable $t) { DB::rollBack(); Log::error('-------- Mail not sent -----------'); Log::error($t->getMessage() . " :\n" . $t->getTraceAsString()); } return $this->successResponse(__('messages.invoice_generated')); } /** * @OA\Get( * path="/invoices", * summary="Lister les factures", * tags={"Factures"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="network_id", * name="network_id", * description="ID du reseau", * @OA\Schema( * type="integer" * ), * in="query", * required=false * ), * @OA\Parameter( * parameter="network_agent_id", * name="network_agent_id", * description="ID de l'agent dans le reseau", * @OA\Schema( * type="integer" * ), * in="query", * required=false * ), * @OA\Parameter( * parameter="page", * name="page", * description="Page", * in="query", * required=false, * @OA\Schema( * type="integer" * ) * ), * @OA\Parameter( * parameter="perPage", * name="perPage", * description="Pas de pagination", * in="query", * required=false, * @OA\Schema( * type="integer" * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = { * "status" : 200, * "response" : {{"id":12,"invoice_id":"25\/01\/2022\/aon8K9BZOn","network_agent_id":43510,"amount":"110\u202f600 FCFA","insured_amount":"104\u202f320 FCFA", * "insurer_amount":"6\u202f280 FCFA","period_start_at":"2021-12-28T00:00:00.000000Z","period_end_at":"2022-01-25T00:00:00.000000Z","file_url":"http:\/\/localhost:8086\/invoices-docs\/28122021_25012022_aon8K9BZOn.pdf", * "created_at":"2022-01-25T19:54:44.000000Z","updated_at":"2022-01-25T19:54:44.000000Z","institution_name":"Agent 2 cnamgs fond 4","institution_code":"aon8K9BZOn","network_id":250,"currency_code":"XAF", * "health_care_sheets":{{"id":72,"invoice_id":12,"health_care_sheet_id":"LG83D7QFGM3X","type":"CONSULTATION","practitioner_lastname":"DIETCHI","practitioner_firstname":"Djery","practitioner_provider_class":"Chirugien", * "patient_lastname":"Zele","patient_firstname":"Brice","institution_name":"Agent 2 cnamgs fond 4","institution_code":"aon8K9BZOn","amount":"5\u202f000 FCFA","insurerAmount":"1\u202f000 FCFA","insuredAmount":"4\u202f000 FCFA"}}}}, * "error":null * } * ) * ) * ) */ public function getInvoices(Request $request) { $this->validate($request, [ 'network_id' => 'required_without:network_agent_id|integer|exists:networks,id', 'network_agent_id' => 'required_without:network_id|integer|exists:networks_agents,id' ]); $network_id = $request->input('network_id'); $network_agent_id = $request->input('network_agent_id'); $query = NhInfosInvoice::with(['health_care_sheets:id,invoice_id,health_care_sheet_id,type,practitioner_lastname,practitioner_firstname,practitioner_provider_class,patient_lastname,patient_firstname,institution_name,institution_code']); if (!empty($network_id)) { $query = $query->where('network_id', $network_id); } if (!empty($network_agent_id)) { $query = $query->where('network_agent_id', $network_agent_id); } $invoices = $query->orderBy('created_at', 'DESC')->paginate($request->input('perPage', 10)); foreach ($invoices->items() as $i) { $i->amount = $this->toMoneyWithCurrencyCode($i->amount, $i->currency_code); $i->insured_amount = $this->toMoneyWithCurrencyCode($i->insured_amount, $i->currency_code); $i->insurer_amount = $this->toMoneyWithCurrencyCode($i->insurer_amount, $i->currency_code); foreach ($i->health_care_sheets as $sheet) { $sheet->amount = $this->toMoneyWithCurrencyCode($sheet->insured_amount + $sheet->insurance_amount, $i->currency_code); $sheet->insurerAmount = $this->toMoneyWithCurrencyCode($sheet->insurance_amount, $i->currency_code); $sheet->insuredAmount = $this->toMoneyWithCurrencyCode($sheet->insured_amount, $i->currency_code); } } return $this->successResponse($invoices); } public function treatInvoice(Request $request, $id) { $this->validate($request, [ 'validating_agent_id' => 'required|integer|exists:nh_validating_agents,id', 'reason' => 'required_if:action,REJECT|string', 'action' => 'required|in:ACCEPT,REJECT,ACCEPT_AND_UPDATE', 'sheets' => 'required_if:action,ACCEPT_AND_UPDATE|array' ]); $action = $request->input('action'); $validating_agent_id = $request->input('validating_agent_id'); $reason = $request->input('reason'); $invoice = NhInvoice::find($id); if (!isset($invoice)) { return $this->errorResponse(trans('errors.invoice_not_found')); } $invoice->validating_agent_id = $validating_agent_id; $datetime = $this->getCurrentTime($invoice->institution->country_id); try { DB::beginTransaction(); if ($action == 'ACCEPT') { $invoice->state = InsuranceSubscriptionState::ACCEPTED; $message = trans('messages.invoice_accepted'); } else if ($action == 'REJECT') { $invoice->state = InsuranceSubscriptionState::REJECTED; $invoice->reason = $reason; $message = trans('messages.invoice_rejected'); } else { $agent = $invoice->institution; $network_id = $agent->network_id; $hyper = AgentPlus::where('network_id', $network_id)->where('category', 'hyper')->first(); $nhConfig = NhNetworksConfig::where('network_id', $network_id)->first(); if (!isset($nhConfig)) { return $this->errorResponse(trans('errors.nano_health_not_activated')); } $invoice->state = 'MODIFIED'; $invoiceClone = $invoice->replicate(); $invoiceClone->state = InsuranceSubscriptionState::ACCEPTED_MODIFIED; $invoiceClone->reason = $reason; $invoiceClone->created_at = $invoiceClone->updated_at = $datetime; $invoiceClone->push(); $currency_code = $this->getNetworkCurrency($network_id); $totalInsurerAmount = 0; $totalInsuredAmount = 0; $sheetsCloned = []; // Fusionner les ids des feuilles de soins existantes et celle modifiées $sheets = $request->input('sheets'); $sheetsIds = array_map(function ($r) { return $r['sheet_id']; }, $sheets); $invoiceSheetIds = $invoice->sheets()->pluck('id'); foreach ($invoiceSheetIds as $id) { if (!in_array($id, $sheetsIds)) { $sheets[] = ['sheet_id' => $id]; } } foreach ($sheets as $s) { $sheet = NhHealthCareSheet::findOrFail($s['sheet_id']); $parts = $this->getConfigInsuranceParts($nhConfig, $sheet->care_condition); $sheetClone = $sheet->replicate(); $sheetClone->health_care_sheet_id .= '/AM'; $sheetClone->invoice_id = $invoiceClone->id; $sheetClone->created_at = $sheetClone->updated_at = $datetime; $sheetClone->push(); $performances = $s['prestations'] ?? []; $exams = $s['exams'] ?? []; $prescriptions = $s['prescriptions'] ?? []; $performancesIds = array_map(function ($r) { return $r['id']; }, $performances); $prescriptionsIds = array_map(function ($r) { return $r['id']; }, $prescriptions); $examsIds = array_map(function ($r) { return $r['id']; }, $exams); #Clone relations $sheet->setRelations([]); $sheet->load('performances', 'prescriptions', 'exams'); foreach ($sheet->getRelations() as $relation => $items) { foreach ($items as $i) { $item = $i->replicate(); if ($sheetClone->type == HealthCareSheetType::CONSULTATION) { if ($relation == 'performances') { if (in_array($i->id, $performancesIds)) { $itemIndex = array_search($i->id, $performancesIds); $delete = $performances[$itemIndex]['to_delete'] ?? false; Log::error(json_encode([$i->id, $itemIndex, $delete])); if ($delete) { continue; } $fees = !empty($performances[$itemIndex]['home_visit_fees']) ? $performances[$itemIndex]['home_visit_fees'] : 0; $item->amount = $performances[$itemIndex]['amount']; $item->home_visit_fees = $fees != 0 ? $fees : null; $item->moderator_ticket = $parts->insured_part * ($item->amount + $fees); $item->insurance_amount = $parts->insurer_part * ($item->amount + $fees); } } } if ($relation == 'prescriptions') { if (in_array($i->id, $prescriptionsIds)) { $itemIndex = array_search($i->id, $prescriptionsIds); $delete = $prescriptions[$itemIndex]['to_delete'] ?? false; if ($delete) { continue; } if ($sheetClone->type == HealthCareSheetType::CONSULTATION) { $item->dosage = $prescriptions[$itemIndex]['dosage']; $item->quantity = $prescriptions[$itemIndex]['quantity']; } else { $item->unit_price = $prescriptions[$itemIndex]['unit_price']; $item->insured_paid_amount = $parts->insured_part * $item->unit_price * ($item->quantity ?? 1); $item->insurer_paid_amount = $parts->insurer_part * $item->unit_price * ($item->quantity ?? 1); } } } if ($relation == 'exams') { if (in_array($i->id, $examsIds)) { $itemIndex = array_search($i->id, $examsIds); $delete = $exams[$itemIndex]['to_delete'] ?? false; if ($delete) { continue; } if ($sheetClone->type == HealthCareSheetType::CONSULTATION) { $item->description = $exams[$itemIndex]['description']; $item->quantity = $exams[$itemIndex]['quantity']; } else { $item->unit_price = $exams[$itemIndex]['unit_price']; $item->insured_paid_amount = $parts->insured_part * $item->unit_price * ($item->quantity ?? 1); $item->insurer_paid_amount = $parts->insurer_part * $item->unit_price * ($item->quantity ?? 1); } } } unset($item->laravel_through_key); $item->created_at = $item->updated_at = $datetime; $item->push(); if ($relation == 'performances') { NhHealthCareSheetsPerformance::create([ 'sheet_id' => $sheetClone->id, 'performance_id' => $item->id, 'created_at' => $datetime, 'updated_at' => $datetime, ]); } if ($relation == 'prescriptions') { NhHealthCareSheetsPrescription::create([ 'sheet_id' => $sheetClone->id, 'prescription_id' => $item->id, 'created_at' => $datetime, 'updated_at' => $datetime, ]); } if ($relation == 'exams') { NhHealthCareSheetsExam::create([ 'sheet_id' => $sheetClone->id, 'exam_id' => $item->id, 'created_at' => $datetime, 'updated_at' => $datetime, ]); } } } // Calculer les parts de l'assurance et l'assuré pour cette feuille de soins $this->calculateInsuranceAmounts($sheetClone); // Retirer la couverture d'assurance précedement octroyée $beneficiary = $sheetClone->beneficiary; if ($beneficiary) { $beneficiary->insurance_coverage_amount -= $sheet->insurance_amount; $beneficiary->save(); } else { $sheetClone->insurance->insurance_coverage_amount -= $sheet->insurance_amount; $sheetClone->insurance->save(); } // Verification de la limite de couverture $this->verifyInsuranceCoverageAmount($nhConfig, $sheetClone->insurance, $sheetClone, $beneficiary ?? null, $currency_code); // Mettre à jour la couverture d'assurance de l'assuré $this->updateInsuranceCoverageAmount($sheetClone, $sheetClone->insurance, $datetime, $beneficiary ?? null); $totalInsuredAmount += $sheetClone->insured_amount; $totalInsurerAmount += $sheetClone->insurance_amount; $sheetClone->date = $sheetClone->created_at->format('d/m/Y'); $sheetsCloned[] = $sheetClone; } $directoryName = '/invoices-docs/'; $filename = $invoiceClone->period_start_at->format('dmY') . '_' . $invoiceClone->period_end_at->format('dmY') . '_' . $agent->code_membre . '_AM_' . time() . '.pdf'; $invoiceClone->invoice_id .= '/AM'; $invoiceClone->reason = null; $invoiceClone->old_invoice_id = $invoice->id; $invoiceClone->amount = $totalInsuredAmount + $totalInsurerAmount; $invoiceClone->insured_amount = $totalInsuredAmount; $invoiceClone->insurer_amount = $totalInsurerAmount; $invoiceClone->file_url = config('services.app_url') . $directoryName . $filename; $invoiceClone->save(); // Generer le PDF de la nouvelle facture $invoiceClone->amount = $this->toMoneyWithCurrencyCode($invoiceClone->amount, $currency_code); $invoiceClone->insured_amount = $this->toMoneyWithCurrencyCode($invoiceClone->insured_amount, $currency_code); $invoiceClone->insurer_amount = $this->toMoneyWithCurrencyCode($invoiceClone->insurer_amount, $currency_code); $invoiceClone->sheets = $sheetsCloned; $invoiceClone->agent = $agent; $invoiceClone->hyper = $hyper; $invoiceClone->period = $invoiceClone->period_start_at->format('d/m/Y') . ' ' . trans('messages.to') . ' ' . $invoiceClone->period_end_at->format('d/m/Y'); $title = $agent->lastname . ' - ' . trans('messages.invoice') . ' ' . $invoice->invoice_id; $message = __('messages.generated_invoice_mail', ['agent' => $agent->lastname, 'period' => $invoice->period]); $file = PDF::loadView('emails.invoice', $invoiceClone->toArray())->setPaper('a4', 'landscape')->setWarnings(false)->save(public_path($directoryName . $filename)); $message = trans('messages.invoice_accepted_updated'); } $invoice->updated_at = $datetime; $invoice->save(); DB::commit(); return $this->successResponse($message); } catch (Throwable $e) { Log::error($e->getMessage() . '\n' . $e->getTraceAsString()); DB::rollBack(); return $this->errorResponse(trans('errors.unexpected_error'), 500); } } }