dstpabuaran.com/app/Services/Admin/Manage/InvoiceService.php
Yoga Pangestu 2a0b99c599 feat: implement invoice management features including index, create, update, delete, and print functionalities
- Added InvoiceIndex component for displaying a list of invoices with pagination and search capabilities.
- Created InvoiceShareButton component for sharing invoice details via WhatsApp.
- Developed InvoicePrint component for printing invoice details.
- Defined routes for invoice management including share and print functionalities.
- Implemented InvoiceTest to cover authentication, authorization, and CRUD operations for invoices.
2026-08-22 15:13:28 +07:00

202 lines
7.3 KiB
PHP

<?php
namespace App\Services\Admin\Manage;
use App\Models\Invoice;
use App\Services\Concerns\LogsFormHistory;
use App\Settings\SystemSettings;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Facades\DB;
class InvoiceService
{
use LogsFormHistory;
public function paginated(int $perPage = 25, string $search = '', string $sort = 'created_at', string $direction = 'desc', array $filters = []): LengthAwarePaginator
{
$itemsCountQuery = '(SELECT COUNT(*) FROM invoice_items WHERE invoice_items.invoice_id = invoices.id)';
return Invoice::query()
->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();
}
}