- 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.
202 lines
7.3 KiB
PHP
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();
|
|
}
|
|
}
|