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'); }); } }