select(['id', 'invoice_number', 'customer_name', 'amount', 'date', 'due_date', 'status', 'description']) ->selectRaw("{$itemsCountQuery} as items_count") ->when($search, fn ($q) => $q->where(function ($query) use ($search) { $query->where('invoice_number', 'like', "%{$search}%") ->orWhere('customer_name', 'like', "%{$search}%"); })) ->orderBy($sort, $direction) ->paginate($perPage); } public function getForEdit(Invoice $invoice): array { $invoice->load('items'); return [ 'id' => $invoice->id, 'invoice_number' => $invoice->invoice_number, 'customer_name' => $invoice->customer_name, 'customer_phone' => $invoice->customer_phone, 'customer_address' => $invoice->customer_address, 'date' => $invoice->date->format('Y-m-d'), 'due_date' => $invoice->due_date?->format('Y-m-d'), 'status' => $invoice->status->value, 'description' => $invoice->description, 'items' => $invoice->items->map(fn ($item) => [ 'id' => $item->id, 'name' => $item->name, 'quantity' => $item->quantity, 'price' => $item->price, ]), ]; } public function getForPrint(Invoice $invoice): array { $invoice->load('items'); $settings = app(SystemSettings::class); return [ 'id' => $invoice->id, 'invoice_number' => $invoice->invoice_number, 'customer_name' => $invoice->customer_name, 'customer_phone' => $invoice->customer_phone, 'customer_address' => $invoice->customer_address, 'amount' => $invoice->amount, 'formatted_amount' => $invoice->formatted_amount, 'formatted_date' => $invoice->formatted_date, 'formatted_due_date' => $invoice->formatted_due_date, 'status' => $invoice->status->value, 'status_label' => $invoice->status_label, 'description' => $invoice->description, 'items' => $invoice->items->map(fn ($item) => [ 'id' => $item->id, 'name' => $item->name, 'quantity' => $item->quantity, 'price' => $item->price, 'subtotal' => $item->subtotal, ]), 'company' => [ 'name' => $settings->app_name, 'address' => $settings->address, 'email' => $settings->email, 'phone' => $settings->phone, ], ]; } public function store(array $data): Invoice { return DB::transaction(function () use ($data) { $now = now(); $amount = 0; $itemRows = $this->buildItemRows($data['items'], $now, $amount); $invoice = Invoice::create([ 'invoice_number' => $data['invoice_number'], 'customer_name' => $data['customer_name'], 'customer_phone' => $data['customer_phone'] ?? null, 'customer_address' => $data['customer_address'] ?? null, 'amount' => $amount, 'date' => $data['date'], 'due_date' => $data['due_date'] ?? null, 'status' => $data['status'], 'description' => $data['description'] ?? null, ]); foreach ($itemRows as &$row) { $row['invoice_id'] = $invoice->id; } DB::table('invoice_items')->insert($itemRows); $this->logCreated($invoice, 'Invoice', [ 'Nomor Invoice' => $invoice->invoice_number, 'Nama Pelanggan' => $invoice->customer_name, 'Jumlah' => $invoice->amount, 'Status' => $invoice->status->value, ]); return $invoice; }); } public function update(Invoice $invoice, array $data): Invoice { return DB::transaction(function () use ($invoice, $data) { $oldValues = [ 'Nomor Invoice' => $invoice->invoice_number, 'Nama Pelanggan' => $invoice->customer_name, 'Jumlah' => $invoice->amount, 'Status' => $invoice->status->value, ]; $invoice->items()->delete(); $now = now(); $amount = 0; $itemRows = $this->buildItemRows($data['items'], $now, $amount); foreach ($itemRows as &$row) { $row['invoice_id'] = $invoice->id; } DB::table('invoice_items')->insert($itemRows); $invoice->update([ 'invoice_number' => $data['invoice_number'], 'customer_name' => $data['customer_name'], 'customer_phone' => $data['customer_phone'] ?? null, 'customer_address' => $data['customer_address'] ?? null, 'amount' => $amount, 'date' => $data['date'], 'due_date' => $data['due_date'] ?? null, 'status' => $data['status'], 'description' => $data['description'] ?? null, ]); $this->logUpdated($invoice, 'Invoice', $oldValues, [ 'Nomor Invoice' => $invoice->invoice_number, 'Nama Pelanggan' => $invoice->customer_name, 'Jumlah' => $invoice->amount, 'Status' => $invoice->status->value, ]); return $invoice; }); } public function destroy(Invoice $invoice): bool { return DB::transaction(function () use ($invoice) { $this->logDeleted($invoice, 'Invoice', [ 'Nomor Invoice' => $invoice->invoice_number, 'Nama Pelanggan' => $invoice->customer_name, 'Jumlah' => $invoice->amount, 'Status' => $invoice->status->value, ]); $invoice->items()->delete(); return $invoice->delete(); }); } private function buildItemRows(array $items, $now, int &$amount): array { return collect($items)->map(function ($item) use ($now, &$amount) { $quantity = (int) $item['quantity']; $price = (int) $item['price']; $subtotal = $quantity * $price; $amount += $subtotal; return [ 'invoice_id' => null, 'name' => $item['name'], 'quantity' => $quantity, 'price' => $price, 'subtotal' => $subtotal, 'created_at' => $now, 'updated_at' => $now, ]; })->toArray(); } }