validate($request, [ 'user_id' => 'required|integer|exists:users,id', 'state' => 'nullable|in:PAID,UNPAID', 'pagination' => 'nullable|boolean' ]); $user_id = $request->input('user_id'); $user = User::findOrFail($user_id); $currency_code = $user->network->country->currency_code; $pagination = $request->input('pagination'); $state = $request->input('state'); // $datetime = $this->getCurrentTimeByCountryCode($user->network->country->code_country); $query = NhInsurancesInvoice::with(['insurance', 'subscription']) ->whereHas('insurance', function ($q) use ($user_id) { return $q->where('user_id', $user_id); }); if (!empty($state)) { // if ($state == 'TO_PAID') { // $query = $query->where('state', InsuranceInvoiceState::UNPAID) // ->where('next_payment_deadline', '>=', $datetime); // } else { $query = $query->where('state', $state); // } } else { $query = $query->with(['payments' => function ($q) { return $q->orderBy('created_at', 'DESC'); }]); } $query = $query->orderBy('created_at', 'DESC'); if ($pagination) { $invoices = $query->paginate($request->input('perPage', 10)); } else { $invoices = $query->get(); } $array = $pagination ? $invoices->items() : $invoices; foreach ($array as $i => $invoice) { if ($i == 0) { $invoice->insurance->state = trans('states.' . $invoice->insurance->state); } $paid_amount = floatval($invoice->paid_amount_non_formatted); $invoice->state = trans('states.' . $invoice->state); $invoice->reason = trans('states.' . $invoice->reason); $invoice->remaining_amount = $this->toMoneyWithCurrencyCode($invoice->amount - $paid_amount, $currency_code); $invoice->paid_amount = $this->toMoneyWithCurrencyCode($paid_amount, $currency_code); $invoice->amount = $this->toMoneyWithCurrencyCode($invoice->amount, $currency_code); if (empty($state)) { foreach ($invoice->payments as $payment) { $payment->amount = $this->toMoneyWithCurrencyCode($payment->amount, $currency_code); } } } return $this->successResponse($invoices); } /** * @OA\Put( * path="/insurances/invoices/{id}/pay", * summary="Payer la facture de l'assurance", * tags={"Factures de l'assurance"}, * security={{"api_key":{}}}, * @OA\Parameter( * parameter="id", * name="id", * description="ID de la facture", * in="path", * required=true, * @OA\Schema( * type="integer", * default=12 * ) * ), * @OA\RequestBody( * description="Corps de la requete", * required=true, * @OA\MediaType( * mediaType="application/json", * @OA\Schema( * @OA\Property(property="password", * type="string", * example = "addfdf21", * description="Mot de passe de l'utilisateur" * ), * @OA\Property(property="amount", * type="number", * example = 32450, * description="Montant à payer" * ), * @OA\Property(property="payment_method", * type="string", * enum = {"wallet" ,"mobile_money","card","ALL"}, * 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 = "133232669895665656", * description="Token la transaction de paiement" * ) * ), * example = {"password":"adbc1215448", "amount" : 50000 , "payment_method" : "wallet" } * ) * ), * @OA\Response( * response=200, * description="OK", * @OA\JsonContent( * ref="#/components/schemas/ApiResponse", * example = {"status":200,"response":"Transaction réussie","error":null} * ) * ) * ) * @throws \App\Exceptions\AppException */ public function payInvoice($id, Request $request) { $this->validate($request, [ 'password' => 'required|string', 'amount' => 'required|numeric|min:0', 'payment_method' => 'required|string', 'payment_phone' => 'required_unless:payment_method,wallet|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' ]); $transaction_id = $request->input('payment_transaction_id'); $amountToPaid = $request->input('amount'); $payment_method = $request->input('payment_method'); $invoice = NhInsurancesInvoice::findOrFail($id); $datetime = $this->getCurrentTimeByCountryCode($invoice->insurance->network->country->code_country); if ($invoice->state == InsuranceInvoiceState::PAID) { return $this->errorResponse(trans('errors.invoice_already_paid')); } $networkConfig = NhNetworksConfig::where('network_id', $invoice->insurance->network_id)->first(); if (!isset($networkConfig) || $networkConfig->configWallet->type != 'ilink_sante') { return $this->errorResponse(trans('errors.nano_health_not_activated')); } $user = $invoice->insurance->user; $this->userIdentificationVerification($user); // Validation du mot de passe dépendamment de la configuration du réseau // $this->validate($request, [ // 'password' => [new PasswordValidation($invoice->insurance->network_id, 'user', $user)] // ]); $currency = $this->getNetworkCurrency($invoice->insurance->network_id); $total_paid_amount = NhInsurancesPayment::where('invoice_id', $id)->sum('amount'); $total_remains_amount = $invoice->amount - $total_paid_amount; if ($amountToPaid > $total_remains_amount) { return $this->errorResponse("Le montant maximum à payer est de " . $this->toMoneyWithCurrencyCode($total_remains_amount, $currency)); } if ($amountToPaid < $invoice->amount_per_split && $amountToPaid < $total_remains_amount) { if ($total_remains_amount < $invoice->amount_per_split) { return $this->errorResponse(trans('errors.minimum amount_to_paid', ['amount' => $this->toMoneyWithCurrencyCode($total_remains_amount, $currency)])); } return $this->errorResponse(trans('errors.minimum amount_to_paid', ['amount' => $this->toMoneyWithCurrencyCode($invoice->amount_per_split, $currency)])); } if (empty($transaction_id)) { if ($payment_method == 'wallet') { if ($user->wallet->balance < $amountToPaid) { $remains_amount = $amountToPaid - $user->wallet->balance; return $this->errorResponse(trans('errors.insufficient_balance', ['amount' => $this->toMoneyWithCurrencyCode($remains_amount, $currency)])); } } else { $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); } $payment = NhInsurancesPayment::where('payment_id', $transaction_id)->first(); if ($payment) { return $this->errorResponse(trans('errors.payment_invalid'), 400); } $amountToPaid = $transaction->amount; } try { DB::beginTransaction(); $hyperviseur = AgentPlus::where('category', 'hyper')->where('network_id', $invoice->insurance->network_id)->firstOrFail(); $walletHyperviseur = Wallet::where('id_networkAgent', $hyperviseur->network_agent_id)->firstOrFail(); $walletHyperviseur->balance_princ += $amountToPaid; $walletHyperviseur->save(); $user->balance_nano_health += $amountToPaid; $user->save(); if (empty($transaction_id)) { if ($payment_method == 'wallet') { $user->wallet->balance -= $amountToPaid; $user->wallet->save(); } else { // Pay through payment service $client = new Client([ 'base_uri' => config('variable.payment_service_url'), 'headers' => [ 'Authorization' => config('variable.payment_service_key'), ] ]); $paymentResponse = $client->post('/pay', [ 'json' => [ 'aggregator_id' => $aggregator->id, 'amount' => $amountToPaid, 'currency' => $user->network->country->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' => $user->network->country->code_country, 'customer_city' => $user->adresse, 'customer_state' => $user->network->country->code_country, 'customer_zip_code' => '00237', 'payment_method' => $request->input('payment_method'), 'reason' => trans('messages.insurance_invoice'), '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); } } } $payment = NhInsurancesPayment::create([ 'payment_id' => empty($transaction_id) ? $this->generateID('nh_insurances_payments', 'payment_id', 10) : $transaction_id, 'invoice_id' => $invoice->id, 'amount' => $amountToPaid ]); // Calcul de l'équivalence en nombre d'échéance if (($total_remains_amount - $amountToPaid) == 0) { $invoice->paid_deadlines = $invoice->deadlines; $invoice->next_payment_deadlines_to_paid = 0; } else { $paid_deadlines = $amountToPaid < $invoice->amount_per_split ? 1 : intval($amountToPaid / $invoice->amount_per_split); $invoice->paid_deadlines += $paid_deadlines; $invoice->next_payment_deadlines_to_paid -= $paid_deadlines; } if ($invoice->next_payment_deadlines_to_paid < 0) { $invoice->next_payment_deadlines_to_paid = 0; } if ($invoice->paid_deadlines == $invoice->deadlines) { $invoice->insurance->state = InsuranceState::PAID; $invoice->state = InsuranceInvoiceState::PAID; $isPartialPayment = false; } else { if ($invoice->next_payment_deadlines_to_paid == 0) { $invoice->insurance->state = InsuranceState::PARTIALLY_PAID; } $deadline = $invoice->next_payment_deadline; $invoice->next_payment_deadline = $this->addDaysToDateTime($deadline, $networkConfig->reminder_delay_days + $networkConfig->suspension_delay_days_after_reminder); // 1 semaines + 3 jours $invoice->next_payment_reminder = $this->addDaysToDateTime($deadline, $networkConfig->reminder_delay_days); $isPartialPayment = true; } // Si c'est le 1er paiement $total_payments = NhInsurancesPayment::where('invoice_id', $id)->count(); if ($total_payments == 1) { if ($invoice->reason == InsuranceAction::ADDITION_OF_BENEFICIARY) { $invoice->insurance->bonus_amount = $invoice->subscription->bonus_amount; $invoice->insurance->total_bonus_amount += $invoice->subscription->total_bonus_amount; $invoice->insurance->number_of_beneficiaries += $invoice->subscription->number_of_beneficiaries; $invoice->insurance->updated_at = $datetime; $invoice->insurance->save(); foreach ($invoice->subscription->beneficiaries as $b) { NhInsurancesHavingRight::create([ 'insurance_id' => $invoice->insurance->id, 'having_right_id' => $b->id ]); } } if (in_array($invoice->reason, [InsuranceAction::ACTIVATION, InsuranceAction::RENEWAL])) { if (empty($invoice->insurance->monthsGrid->waiting_period_days)) { $start_at = $datetime; } else { $start_at = $this->addDaysToDateTime($datetime, $invoice->insurance->monthsGrid->waiting_period_days)->format('Y-m-d H:i:s'); } $end_at = $this->addMonthsToDateTime($start_at, $invoice->insurance->monthsGrid->number_of_months); $invoice->insurance->start_at = $start_at; $invoice->insurance->end_at = $end_at; } } $invoice->updated_at = $datetime; $invoice->insurance->updated_at = $datetime; $invoice->insurance->save(); $invoice->save(); Event::dispatch(new InsuranceEvent($invoice->insurance, $isPartialPayment ? trans('messages.insurance_partially_paid') : trans('messages.insurance_subscription_paid'), trans('messages.insurance_paid_mail', ['name' => $invoice->insurance->user->lastname, 'insured_id' => $invoice->insurance->insured_id, 'bonus_amount' => $this->toMoneyWithCurrencyCode($invoice->insurance->bonus_amount, $currency), 'total_bonus_amount' => $this->toMoneyWithCurrencyCode($invoice->insurance->total_bonus_amount, $currency), 'number_of_beneficiaries' => $invoice->insurance->number_of_beneficiaries, 'gender' => trans('states.' . $invoice->insurance->user->identification->gender), 'insurance_name' => $invoice->insurance->network->name, 'months' => $invoice->insurance->monthsGrid->number_of_months, 'invoice_id' => $invoice->invoice_id, 'amount' => $this->toMoneyWithCurrencyCode($amountToPaid, $currency), 'paid_amount' => $this->toMoneyWithCurrencyCode($total_paid_amount + $amountToPaid, $currency), 'remains_amount' => $this->toMoneyWithCurrencyCode($total_remains_amount - $amountToPaid, $currency), 'payment_period' => trans('states.' . $invoice->insurance->monthsGrid->payment_period), 'reason' => trans('states.' . $invoice->reason), 'title' => $isPartialPayment ? trans('messages.insurance_partially_paid_title') : trans('messages.insurance_fully_paid_title'), 'waiting_days' => empty($invoice->insurance->monthsGrid->waiting_period_days) ? trans('messages.none') : trans('messages.n_days', ['n' => $invoice->insurance->monthsGrid->waiting_period_days]), 'start_at' => $invoice->insurance->start_at, 'payment_id' => $payment->payment_id ]))); DB::commit(); return $this->successResponse(trans('messages.insurance_invoice_paid', ['amount' => $this->toMoneyWithCurrencyCode($amountToPaid, $currency)])); } catch (Throwable $e) { Log::error($e->getMessage() . '\n' . $e->getTraceAsString()); DB::rollBack(); return $this->errorResponse(trans('errors.unexpected_error'), 500); } } // public function generateInvoices() // { // try { // DB::beginTransaction(); // $this->generateInsurancesInvoices(); // DB::commit(); // return $this->successResponse("Success"); // } catch (\Throwable $t) { // DB::rollBack(); // Log::error('-------- Insurances Invoices expired insurance-----------'); // Log::error($t->getMessage() . " :\n" . $t->getTraceAsString()); // return $this->errorResponse("Error"); // } // } public function reminderInvoices() { try { $this->reminderInsurancesInvoices(); return $this->successResponse("Success"); } catch (\Throwable $t) { DB::rollBack(); Log::error('-------- Insurances Invoices expired insurance-----------'); Log::error($t->getMessage() . " :\n" . $t->getTraceAsString()); return $this->errorResponse("Error"); } } }