instalasi-sim-rs/app/Http/Controllers/TransactionController.php
vchandra22 e8e7a1fce5
Some checks failed
linter / quality (push) Has been cancelled
tests / ci (push) Has been cancelled
feat: create dashboard page add the charts for report patient
2025-04-27 20:40:49 +07:00

434 lines
19 KiB
PHP

<?php
namespace App\Http\Controllers;
use App\Models\Employee;
use App\Models\Insurance;
use App\Models\Patient;
use App\Models\Procedure;
use App\Models\Registration;
use App\Models\Transaction;
use App\Models\TransactionDetail;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Inertia\Inertia;
class TransactionController extends Controller
{
/**
* Display a listing of the resource.
*/
public function index()
{
$transactions = Transaction::with([
'patient:id,name',
'registration:id,registration_number',
'insurance:id,name',
'cashier:id,name'
])
->orderBy('transaction_datetime', 'desc')
->select([
'id',
'invoice_number',
'registration_id',
'patient_id',
'insurance_id',
'cashier_id',
'transaction_datetime',
'payment_datetime',
'grand_total',
'paid_amount',
'insurance_covered_amount',
'patient_responsibility',
'payment_method',
'status',
'created_at'
])
->paginate(10)
->through(function ($transaction) {
return [
'id' => $transaction->id,
'invoice_number' => $transaction->invoice_number,
'registration_number' => $transaction->registration->registration_number,
'patient_name' => $transaction->patient->name,
'insurance_name' => $transaction->insurance?->name,
'cashier_name' => $transaction->cashier?->name,
'transaction_datetime' => $transaction->transaction_datetime->format('Y-m-d H:i'),
'payment_datetime' => $transaction->payment_datetime?->format('Y-m-d H:i'),
'grand_total' => number_format($transaction->grand_total, 2),
'paid_amount' => number_format($transaction->paid_amount, 2),
'insurance_covered_amount' => number_format($transaction->insurance_covered_amount, 2),
'patient_responsibility' => number_format($transaction->patient_responsibility, 2),
'payment_method' => $transaction->payment_method,
'status' => $transaction->status,
'created_at' => $transaction->created_at->format('Y-m-d H:i:s'),
];
});
return Inertia::render('transactions/index', [
'transactions' => $transactions,
'status' => session('status'),
]);
}
/**
* Show the form for creating a new resource.
*/
public function create()
{
$patients = Patient::select(['id', 'name'])->get();
$registrations = Registration::with(['patient:id,name'])
->whereDoesntHave('transaction')
->where('status', '!=', 'cancelled')
->select(['id', 'registration_number', 'patient_id'])
->get()
->map(function ($registration) {
return [
'id' => $registration->id,
'registration_number' => $registration->registration_number,
'patient_name' => $registration->patient->name,
];
});
$insurances = Insurance::select(['id', 'name'])->get();
$procedures = Procedure::select(['id', 'code', 'name', 'base_price', 'tax_percentage', 'is_taxable'])->get();
$employees = Employee::with('user:id,name')
->whereHas('user')
->get()
->map(function ($employee) {
return [
'id' => $employee->id,
'name' => $employee->user->name,
];
});
return Inertia::render('transactions/form', [
'mode' => 'create',
'patients' => $patients,
'registrations' => $registrations,
'insurances' => $insurances,
'procedures' => $procedures,
'employees' => $employees,
'paymentMethods' => [
'cash' => 'Tunai',
'debit_card' => 'Kartu Debit',
'credit_card' => 'Kartu Kredit',
'transfer' => 'Transfer Bank',
'insurance' => 'Asuransi',
'other' => 'Lainnya',
],
'statusOptions' => [
'pending' => 'Menunggu Pembayaran',
'paid' => 'Lunas',
'partially_paid' => 'Bayar Sebagian',
'cancelled' => 'Dibatalkan',
'refunded' => 'Dikembalikan',
],
]);
}
/**
* Store a newly created resource in storage.
*/
public function store(Request $request)
{
$validated = $request->validate([
'registration_id' => 'required|exists:t_registration,id',
'patient_id' => 'required|exists:m_patient,id',
'insurance_id' => 'nullable|exists:m_insurance,id',
'procedure_id' => 'required|exists:m_procedure,id',
'employee_id' => 'nullable|exists:m_employee,id',
'service_name' => 'required|string|max:100',
'transaction_datetime' => 'required|date',
'payment_datetime' => 'nullable|date',
'due_date' => 'nullable|date',
'subtotal' => 'required|numeric|min:0',
'tax_amount' => 'required|numeric|min:0',
'discount_amount' => 'nullable|numeric|min:0',
'grand_total' => 'required|numeric|min:0',
'paid_amount' => 'required|numeric|min:0',
'insurance_covered_amount' => 'nullable|numeric|min:0',
'payment_method' => 'required|in:cash,debit_card,credit_card,transfer,insurance,other',
'payment_reference' => 'nullable|string|max:100',
'status' => 'required|in:pending,paid,partially_paid,cancelled,refunded',
'notes' => 'nullable|string',
]);
return DB::transaction(function () use ($validated, $request) {
$invoiceNumber = Transaction::generateInvoiceNumber();
$procedure = Procedure::findOrFail($validated['procedure_id']);
$discountAmount = $validated['discount_amount'] ?? 0;
$insuranceCoveredAmount = $validated['insurance_covered_amount'] ?? 0;
$patientResponsibility = $validated['grand_total'] - $insuranceCoveredAmount;
$changeAmount = 0;
if ($validated['paid_amount'] > $patientResponsibility) {
$changeAmount = $validated['paid_amount'] - $patientResponsibility;
}
$transaction = Transaction::create([
'invoice_number' => $invoiceNumber,
'registration_id' => $validated['registration_id'],
'patient_id' => $validated['patient_id'],
'insurance_id' => $validated['insurance_id'],
'cashier_id' => auth()->id(),
'transaction_datetime' => $validated['transaction_datetime'],
'payment_datetime' => $validated['payment_datetime'],
'due_date' => $validated['due_date'] ?? null,
'subtotal' => $validated['subtotal'],
'tax_amount' => $validated['tax_amount'],
'discount_amount' => $discountAmount,
'grand_total' => $validated['grand_total'],
'paid_amount' => $validated['paid_amount'],
'change_amount' => $changeAmount,
'insurance_covered_amount' => $insuranceCoveredAmount,
'patient_responsibility' => $patientResponsibility,
'payment_method' => $validated['payment_method'],
'payment_reference' => $validated['payment_reference'] ?? null,
'status' => $validated['status'],
'notes' => $validated['notes'] ?? null,
]);
TransactionDetail::create([
'transaction_id' => $transaction->id,
'procedure_id' => $validated['procedure_id'],
'performed_by' => $validated['employee_id'],
'procedure_code' => $procedure->code,
'procedure_name' => $validated['service_name'],
'quantity' => 1, // Default quantity to 1
'unit_price' => $validated['subtotal'],
'discount_amount' => $discountAmount,
'tax_amount' => $validated['tax_amount'],
'subtotal' => $validated['subtotal'],
'notes' => $validated['notes'] ?? null,
]);
if ($validated['status'] === 'paid') {
$registration = Registration::findOrFail($validated['registration_id']);
$registration->update(['payment_status' => 'paid']);
} elseif ($validated['status'] === 'partially_paid') {
$registration = Registration::findOrFail($validated['registration_id']);
$registration->update(['payment_status' => 'partial']);
}
return redirect()->route('transactions.index')
->with('status', 'Transaksi berhasil dibuat');
});
}
/**
* Display the specified resource.
*/
public function show(Transaction $transaction)
{
//
}
/**
* Show the form for editing the specified resource.
*/
public function edit(Transaction $transaction)
{
$transaction->load([
'details',
'registration',
'patient',
'insurance',
]);
$patients = Patient::select(['id', 'name'])->get();
$registrations = Registration::with(['patient:id,name'])
->where(function ($query) use ($transaction) {
$query->where('status', '!=', 'cancelled')
->where('payment_status', '!=', 'paid')
->orWhere('id', $transaction->registration_id);
})
->select(['id', 'registration_number', 'patient_id'])
->get()
->map(function ($registration) {
return [
'id' => $registration->id,
'registration_number' => $registration->registration_number,
'patient_name' => $registration->patient->name,
];
});
$insurances = Insurance::select(['id', 'name'])->get();
$procedures = Procedure::select(['id', 'code', 'name'])->get();
$employees = Employee::with('user:id,name')
->whereHas('user')
->get()
->map(function ($employee) {
return [
'id' => $employee->id,
'name' => $employee->user->name,
];
});
$firstDetail = $transaction->details->first();
// Hitung ulang patient_responsibility jika diperlukan
$patientResponsibility = $transaction->patient_responsibility;
if ($transaction->payment_method === 'insurance') {
$patientResponsibility = $transaction->grand_total - $transaction->insurance_covered_amount;
}
return Inertia::render('transactions/form', [
'mode' => 'edit',
'transaction' => [
'id' => $transaction->id,
'invoice_number' => $transaction->invoice_number,
'registration_id' => $transaction->registration_id,
'patient_id' => $transaction->patient_id,
'insurance_id' => $transaction->insurance_id,
'procedure_id' => $firstDetail ? $firstDetail->procedure_id : null,
'employee_id' => $firstDetail ? $firstDetail->performed_by : null,
'service_name' => $firstDetail ? $firstDetail->procedure_name : '',
'transaction_datetime' => $transaction->transaction_datetime->format('Y-m-d\TH:i'),
'payment_datetime' => $transaction->payment_datetime?->format('Y-m-d\TH:i'),
'due_date' => $transaction->due_date?->format('Y-m-d'),
'subtotal' => (float) $transaction->subtotal,
'tax_amount' => (float) $transaction->tax_amount,
'discount_amount' => (float) $transaction->discount_amount,
'discount_reason' => $transaction->discount_reason,
'grand_total' => (float) $transaction->grand_total,
'paid_amount' => (float) $transaction->paid_amount,
'change_amount' => (float) $transaction->change_amount,
'insurance_covered_amount' => (float) $transaction->insurance_covered_amount,
'patient_responsibility' => (float) $patientResponsibility,
'payment_method' => $transaction->payment_method,
'payment_reference' => $transaction->payment_reference,
'status' => $transaction->status,
'notes' => $transaction->notes,
],
'patients' => $patients,
'registrations' => $registrations,
'insurances' => $insurances,
'procedures' => $procedures,
'employees' => $employees,
'paymentMethods' => [
'cash' => 'Tunai',
'debit_card' => 'Kartu Debit',
'credit_card' => 'Kartu Kredit',
'transfer' => 'Transfer Bank',
'insurance' => 'Asuransi',
'other' => 'Lainnya',
],
'statusOptions' => [
'pending' => 'Menunggu Pembayaran',
'paid' => 'Lunas',
'partially_paid' => 'Bayar Sebagian',
'cancelled' => 'Dibatalkan',
'refunded' => 'Dikembalikan',
],
]);
}
/**
* Update the specified resource in storage.
*/
public function update(Request $request, Transaction $transaction)
{
$validated = $request->validate([
'registration_id' => 'required|exists:t_registration,id',
'patient_id' => 'required|exists:m_patient,id',
'insurance_id' => 'nullable|exists:m_insurance,id',
'procedure_id' => 'required|exists:m_procedure,id',
'employee_id' => 'nullable|exists:m_employee,id',
'service_name' => 'required|string|max:100',
'transaction_datetime' => 'required|date',
'payment_datetime' => 'nullable|date',
'due_date' => 'nullable|date',
'subtotal' => 'required|numeric|min:0',
'tax_amount' => 'required|numeric|min:0',
'discount_amount' => 'nullable|numeric|min:0',
'grand_total' => 'required|numeric|min:0',
'paid_amount' => 'required|numeric|min:0',
'insurance_covered_amount' => 'nullable|numeric|min:0',
'payment_method' => 'required|in:cash,debit_card,credit_card,transfer,insurance,other',
'payment_reference' => 'nullable|string|max:100',
'status' => 'required|in:pending,paid,partially_paid,cancelled,refunded',
'notes' => 'nullable|string',
]);
return DB::transaction(function () use ($validated, $transaction) {
$procedure = Procedure::findOrFail($validated['procedure_id']);
$discountAmount = $validated['discount_amount'] ?? 0;
$insuranceCoveredAmount = $validated['insurance_covered_amount'] ?? 0;
$patientResponsibility = $validated['grand_total'] - $insuranceCoveredAmount;
$changeAmount = 0;
if ($validated['paid_amount'] > $patientResponsibility) {
$changeAmount = $validated['paid_amount'] - $patientResponsibility;
}
$transaction->update([
'registration_id' => $validated['registration_id'],
'patient_id' => $validated['patient_id'],
'insurance_id' => $validated['insurance_id'],
'transaction_datetime' => $validated['transaction_datetime'],
'payment_datetime' => $validated['payment_datetime'],
'due_date' => $validated['due_date'],
'subtotal' => $validated['subtotal'],
'tax_amount' => $validated['tax_amount'],
'discount_amount' => $discountAmount,
'grand_total' => $validated['grand_total'],
'paid_amount' => $validated['paid_amount'],
'change_amount' => $changeAmount,
'insurance_covered_amount' => $insuranceCoveredAmount,
'patient_responsibility' => $patientResponsibility,
'payment_method' => $validated['payment_method'],
'payment_reference' => $validated['payment_reference'],
'status' => $validated['status'],
'notes' => $validated['notes'],
]);
$detail = TransactionDetail::where('transaction_id', $transaction->id)->first();
$detailData = [
'transaction_id' => $transaction->id,
'procedure_id' => $validated['procedure_id'],
'performed_by' => $validated['employee_id'],
'procedure_code' => $procedure->code,
'procedure_name' => $validated['service_name'],
'quantity' => 1, // Default quantity to 1
'unit_price' => $validated['subtotal'],
'discount_amount' => $discountAmount,
'tax_amount' => $validated['tax_amount'],
'subtotal' => $validated['subtotal'],
'notes' => $validated['notes'],
];
if ($detail) {
$detail->update($detailData);
} else {
TransactionDetail::create($detailData);
}
$registration = Registration::findOrFail($validated['registration_id']);
if ($validated['status'] === 'paid') {
$registration->update(['payment_status' => 'paid']);
} elseif ($validated['status'] === 'partially_paid') {
$registration->update(['payment_status' => 'partial']);
}
return redirect()->route('transactions.index')
->with('status', 'Data transaksi berhasil diperbarui');
});
}
/**
* Remove the specified resource from storage.
*/
public function destroy(Transaction $transaction)
{
return DB::transaction(function () use ($transaction) {
TransactionDetail::where('transaction_id', $transaction->id)->delete();
$transaction->delete();
return redirect()->route('transactions.index')
->with('status', 'Data transaksi berhasil dihapus');
});
}
}