440 lines
18 KiB
PHP
440 lines
18 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'])
|
|
->where('status', '!=', 'cancelled')
|
|
->where('payment_status', '!=', 'paid')
|
|
->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,
|
|
];
|
|
});
|
|
|
|
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)
|
|
{
|
|
|
|
// Validasi input dari 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',
|
|
'transaction_datetime' => 'required|date',
|
|
'payment_datetime' => 'nullable|date',
|
|
'due_date' => 'nullable|date',
|
|
'procedure_id' => 'required|exists:m_procedure,id', // ID prosedur harus ada dan valid
|
|
'quantity' => 'required|integer|min:1', // Jumlah harus ada, berupa integer dan minimal 1
|
|
'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',
|
|
]);
|
|
|
|
// Mulai transaksi database
|
|
return DB::transaction(function () use ($validated) {
|
|
// Generate nomor invoice
|
|
$invoiceNumber = Transaction::generateInvoiceNumber();
|
|
|
|
// Ambil harga prosedur
|
|
$procedure = Procedure::findOrFail($validated['procedure_id']);
|
|
$unitPrice = $procedure->base_price;
|
|
|
|
// Hitung subtotal
|
|
$subtotal = $unitPrice * $validated['quantity'];
|
|
|
|
// Hitung pajak dan diskon jika ada
|
|
$taxAmount = $subtotal * ($procedure->tax_percentage / 100);
|
|
$discountAmount = 0; // Anda bisa menambahkan logika diskon jika diperlukan
|
|
|
|
// Hitung grand total
|
|
$grandTotal = $subtotal + $taxAmount - $discountAmount;
|
|
|
|
// Hitung tanggung jawab pasien
|
|
$patientResponsibility = $grandTotal - ($validated['insurance_id'] ? $validated['insurance_covered_amount'] : 0);
|
|
|
|
// Hitung jumlah kembalian jika pembayaran dilakukan
|
|
$changeAmount = 0;
|
|
if ($validated['paid_amount'] > $patientResponsibility) {
|
|
$changeAmount = $validated['paid_amount'] - $patientResponsibility;
|
|
}
|
|
|
|
// Buat transaksi
|
|
$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'],
|
|
'subtotal' => $subtotal,
|
|
'tax_amount' => $taxAmount,
|
|
'discount_amount' => $discountAmount,
|
|
'grand_total' => $grandTotal,
|
|
'paid_amount' => $validated['paid_amount'],
|
|
'change_amount' => $changeAmount,
|
|
'insurance_covered_amount' => $validated['insurance_covered_amount'] ?? 0,
|
|
'patient_responsibility' => $patientResponsibility,
|
|
'payment_method' => $validated['payment_method'],
|
|
'payment_reference' => $validated['payment_reference'],
|
|
'status' => $validated['status'],
|
|
'notes' => $validated['notes'],
|
|
]);
|
|
|
|
// Buat detail transaksi
|
|
TransactionDetail::create([
|
|
'transaction_id' => $transaction->id,
|
|
'procedure_id' => $validated['procedure_id'],
|
|
'quantity' => $validated['quantity'],
|
|
'unit_price' => $unitPrice,
|
|
'discount_amount' => $discountAmount,
|
|
'tax_amount' => $taxAmount,
|
|
'subtotal' => $subtotal,
|
|
]);
|
|
|
|
// Update status pembayaran registrasi jika diperlukan
|
|
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']);
|
|
}
|
|
|
|
// Redirect ke halaman transaksi dengan pesan sukses
|
|
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,
|
|
];
|
|
});
|
|
|
|
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,
|
|
'cashier_id' => $transaction->cashier_id,
|
|
'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' => $transaction->subtotal,
|
|
'tax_amount' => $transaction->tax_amount,
|
|
'discount_amount' => $transaction->discount_amount,
|
|
'discount_reason' => $transaction->discount_reason,
|
|
'grand_total' => $transaction->grand_total,
|
|
'paid_amount' => $transaction->paid_amount,
|
|
'change_amount' => $transaction->change_amount,
|
|
'insurance_covered_amount' => $transaction->insurance_covered_amount,
|
|
'patient_responsibility' => $transaction->patient_responsibility,
|
|
'payment_method' => $transaction->payment_method,
|
|
'payment_reference' => $transaction->payment_reference,
|
|
'status' => $transaction->status,
|
|
'notes' => $transaction->notes,
|
|
'details' => $transaction->details->map(function($detail) {
|
|
return [
|
|
'id' => $detail->id,
|
|
'procedure_id' => $detail->procedure_id,
|
|
'performed_by' => $detail->performed_by,
|
|
'code' => $detail->code,
|
|
'procedure_name' => $detail->procedure_name,
|
|
'quantity' => $detail->quantity,
|
|
'unit_price' => $detail->unit_price,
|
|
'discount_amount' => $detail->discount_amount,
|
|
'tax_amount' => $detail->tax_amount,
|
|
'subtotal' => $detail->subtotal,
|
|
'performed_datetime' => $detail->performed_datetime?->format('Y-m-d\TH:i'),
|
|
'notes' => $detail->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',
|
|
'transaction_datetime' => 'required|date',
|
|
'payment_datetime' => 'nullable|date',
|
|
'due_date' => 'nullable|date',
|
|
'details' => 'required|array|min:1',
|
|
'details.*.procedure_id' => 'required|exists:m_procedure,id',
|
|
'details.*.quantity' => 'required|integer|min:1',
|
|
'details.*.performed_by' => 'nullable|exists:m_employee,id',
|
|
'details.*.notes' => 'nullable|string',
|
|
]);
|
|
|
|
return DB::transaction(function () use ($validated, $transaction) {
|
|
// Hitung total baru
|
|
$subtotal = 0;
|
|
$taxAmount = 0;
|
|
$discountAmount = 0;
|
|
|
|
foreach ($validated['details'] as $detail) {
|
|
$procedure = Procedure::findOrFail($detail['procedure_id']);
|
|
$unitPrice = $procedure->base_price;
|
|
$detailSubtotal = $unitPrice * $detail['quantity'];
|
|
$detailTax = $detailSubtotal * ($procedure->tax_percentage / 100);
|
|
|
|
$subtotal += $detailSubtotal;
|
|
$taxAmount += $detailTax;
|
|
}
|
|
|
|
// Hitung grand total
|
|
$grandTotal = $subtotal + $taxAmount - $discountAmount;
|
|
|
|
// Hitung tanggung jawab pasien
|
|
$patientResponsibility = $grandTotal - ($validated['insurance_id'] ? $validated['insurance_covered_amount'] : 0);
|
|
|
|
// Update transaksi
|
|
$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' => $subtotal,
|
|
'tax_amount' => $taxAmount,
|
|
'discount_amount' => $discountAmount,
|
|
'grand_total' => $grandTotal,
|
|
'patient_responsibility' => $patientResponsibility,
|
|
'status' => $validated['status'],
|
|
'notes' => $validated['notes'],
|
|
]);
|
|
|
|
// Update detail transaksi
|
|
foreach ($validated['details'] as $detail) {
|
|
$detailData = [
|
|
'transaction_id' => $transaction->id,
|
|
'procedure_id' => $detail['procedure_id'],
|
|
'performed_by' => $detail['performed_by'],
|
|
'quantity' => $detail['quantity'],
|
|
'unit_price' => Procedure::findOrFail($detail['procedure_id'])->base_price,
|
|
'subtotal' => Procedure::findOrFail($detail['procedure_id'])->base_price * $detail['quantity'],
|
|
'notes' => $detail['notes'] ?? null,
|
|
];
|
|
|
|
if (isset($detail['id']) && $detail['id']) {
|
|
TransactionDetail::where('id', $detail['id'])->update($detailData);
|
|
} else {
|
|
TransactionDetail::create($detailData);
|
|
}
|
|
}
|
|
|
|
// Redirect ke halaman transaksi dengan pesan sukses
|
|
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');
|
|
});
|
|
}
|
|
}
|