instalasi-sim-rs/app/Http/Controllers/TransactionController.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');
});
}
}