135 lines
4.3 KiB
PHP
135 lines
4.3 KiB
PHP
<?php
|
|
|
|
namespace App\Http\Controllers\Api;
|
|
|
|
use App\Http\Controllers\Controller;
|
|
use App\Http\Resources\InvoiceResource;
|
|
use App\Models\Invoice;
|
|
use App\Models\Payment;
|
|
use App\Services\LedgerService;
|
|
use Illuminate\Http\Request;
|
|
use Illuminate\Validation\Rule;
|
|
|
|
class InvoiceController extends Controller
|
|
{
|
|
public function index(Request $request)
|
|
{
|
|
$query = Invoice::with(['patient', 'currency']);
|
|
|
|
if ($request->has('patient_id')) {
|
|
$query->where('patient_id', $request->patient_id);
|
|
}
|
|
|
|
if ($request->has('status')) {
|
|
$query->where('status', $request->status);
|
|
}
|
|
|
|
if ($request->has('date_from')) {
|
|
$query->whereDate('invoice_date', '>=', $request->date_from);
|
|
}
|
|
|
|
if ($request->has('date_to')) {
|
|
$query->whereDate('invoice_date', '<=', $request->date_to);
|
|
}
|
|
|
|
$invoices = $query->orderByDesc('invoice_date')->paginate($request->per_page ?? 20);
|
|
|
|
return InvoiceResource::collection($invoices);
|
|
}
|
|
|
|
public function store(Request $request)
|
|
{
|
|
$data = $request->validate([
|
|
'patient_id' => 'required|exists:patients,id',
|
|
'invoice_date' => 'required|date',
|
|
'due_date' => 'required|date|after_or_equal:invoice_date',
|
|
'subtotal' => 'required|numeric|min:0',
|
|
'tax_amount' => 'nullable|numeric|min:0',
|
|
'discount_amount' => 'nullable|numeric|min:0',
|
|
'currency_id' => 'required|exists:currencies,id',
|
|
'notes' => 'nullable|string',
|
|
]);
|
|
|
|
$data['created_by'] = auth()->id();
|
|
|
|
// Calculate total
|
|
$data['total_amount'] = $data['subtotal']
|
|
+ ($data['tax_amount'] ?? 0)
|
|
- ($data['discount_amount'] ?? 0);
|
|
$data['paid_amount'] = 0;
|
|
|
|
// Generate invoice number
|
|
$lastId = Invoice::max('id') ?? 0;
|
|
$data['invoice_number'] = 'INV-' . date('Y') . '-' . str_pad($lastId + 1, 6, '0', STR_PAD_LEFT);
|
|
|
|
$invoice = Invoice::create($data);
|
|
|
|
return new InvoiceResource($invoice);
|
|
}
|
|
|
|
public function show(Invoice $invoice)
|
|
{
|
|
return new InvoiceResource($invoice);
|
|
}
|
|
|
|
public function update(Request $request, Invoice $invoice)
|
|
{
|
|
if (in_array($invoice->status, ['paid', 'cancelled'])) {
|
|
return response()->json(['message' => 'Cannot update paid or cancelled invoice'], 422);
|
|
}
|
|
|
|
$data = $request->validate([
|
|
'invoice_date' => 'sometimes|date',
|
|
'due_date' => 'sometimes|date',
|
|
'subtotal' => 'sometimes|numeric|min:0',
|
|
'tax_amount' => 'nullable|numeric|min:0',
|
|
'discount_amount' => 'nullable|numeric|min:0',
|
|
'notes' => 'nullable|string',
|
|
'status' => ['sometimes', Rule::in(['draft', 'sent', 'paid', 'partial', 'overdue', 'cancelled'])],
|
|
]);
|
|
|
|
if (isset($data['subtotal'])) {
|
|
$data['total_amount'] = $data['subtotal']
|
|
+ ($data['tax_amount'] ?? $invoice->tax_amount)
|
|
- ($data['discount_amount'] ?? $invoice->discount_amount);
|
|
}
|
|
|
|
$invoice->update($data);
|
|
|
|
return new InvoiceResource($invoice);
|
|
}
|
|
|
|
public function destroy(Invoice $invoice)
|
|
{
|
|
if ($invoice->payments()->exists()) {
|
|
return response()->json(['message' => 'Cannot delete invoice with payments'], 422);
|
|
}
|
|
|
|
$invoice->delete();
|
|
return response()->json(['message' => 'Invoice deleted successfully']);
|
|
}
|
|
|
|
public function summary(Request $request)
|
|
{
|
|
$query = Invoice::query();
|
|
|
|
if ($request->has('date_from')) {
|
|
$query->whereDate('invoice_date', '>=', $request->date_from);
|
|
}
|
|
|
|
if ($request->has('date_to')) {
|
|
$query->whereDate('invoice_date', '<=', $request->date_to);
|
|
}
|
|
|
|
return response()->json([
|
|
'total_invoices' => $query->count(),
|
|
'total_amount' => $query->sum('total_amount'),
|
|
'total_paid' => $query->sum('paid_amount'),
|
|
'total_outstanding' => $query->sum('balance'),
|
|
'by_status' => $query->selectRaw('status, count(*) as count, sum(total_amount) as amount')
|
|
->groupBy('status')
|
|
->get(),
|
|
]);
|
|
}
|
|
}
|