feat: refactor transaction and leave request handling to use centralized action handler

This commit is contained in:
Yoga Pangestu 2026-07-30 10:29:52 +07:00
parent 9033aef5f7
commit 917588eecf
7 changed files with 144 additions and 248 deletions

View File

@ -7,7 +7,6 @@
use App\Models\CashTransaction;
use App\Services\Admin\Finance\CashAccountService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
@ -29,65 +28,37 @@ public function index(): Response
public function deposit(CashTransactionRequest $request): RedirectResponse
{
try {
$this->service->deposit($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Deposit berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.cash-accounts.index');
return $this->handleAction(
fn () => $this->service->deposit($request->validated()),
'Deposit berhasil ditambahkan.',
'admin.finance.cash-accounts.index'
);
}
public function withdrawal(CashTransactionRequest $request): RedirectResponse
{
try {
$this->service->withdrawal($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Withdrawal berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.cash-accounts.index');
return $this->handleAction(
fn () => $this->service->withdrawal($request->validated()),
'Withdrawal berhasil ditambahkan.',
'admin.finance.cash-accounts.index'
);
}
public function update(CashTransactionRequest $request, CashTransaction $transaction): RedirectResponse
{
try {
$this->service->updateTransaction($transaction, $request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Transaksi berhasil diperbarui.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.cash-accounts.index');
return $this->handleAction(
fn () => $this->service->updateTransaction($transaction, $request->validated()),
'Transaksi berhasil diperbarui.',
'admin.finance.cash-accounts.index'
);
}
public function destroy(CashTransaction $transaction): RedirectResponse
{
try {
$this->service->deleteTransaction($transaction);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Transaksi berhasil dihapus.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.cash-accounts.index');
return $this->handleAction(
fn () => $this->service->deleteTransaction($transaction),
'Transaksi berhasil dihapus.',
'admin.finance.cash-accounts.index'
);
}
}

View File

@ -7,7 +7,6 @@
use App\Models\EmployeeAdvance;
use App\Services\Admin\Finance\EmployeeAdvanceService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
@ -26,72 +25,46 @@ public function index(): Response
public function store(EmployeeAdvanceRequest $request): RedirectResponse
{
try {
$this->service->create($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kasbon berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.employee-advances.index');
return $this->handleAction(
fn () => $this->service->create($request->validated()),
'Kasbon berhasil ditambahkan.',
'admin.finance.employee-advances.index'
);
}
public function update(EmployeeAdvanceRequest $request, EmployeeAdvance $employeeAdvance): RedirectResponse
{
try {
$this->service->update($employeeAdvance, $request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kasbon berhasil diperbarui.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.employee-advances.index');
return $this->handleAction(
fn () => $this->service->update($employeeAdvance, $request->validated()),
'Kasbon berhasil diperbarui.',
'admin.finance.employee-advances.index'
);
}
public function destroy(EmployeeAdvance $employeeAdvance): RedirectResponse
{
try {
$this->service->delete($employeeAdvance);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kasbon berhasil dihapus.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.employee-advances.index');
return $this->handleAction(
fn () => $this->service->delete($employeeAdvance),
'Kasbon berhasil dihapus.',
'admin.finance.employee-advances.index'
);
}
public function approve(EmployeeAdvance $employeeAdvance): RedirectResponse
{
try {
$this->service->approve($employeeAdvance);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kasbon berhasil disetujui.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.employee-advances.index');
return $this->handleAction(
fn () => $this->service->approve($employeeAdvance),
'Kasbon berhasil disetujui.',
'admin.finance.employee-advances.index'
);
}
public function pay(EmployeeAdvance $employeeAdvance): RedirectResponse
{
try {
$this->service->pay($employeeAdvance);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kasbon berhasil dibayar.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.employee-advances.index');
return $this->handleAction(
fn () => $this->service->pay($employeeAdvance),
'Kasbon berhasil dibayar.',
'admin.finance.employee-advances.index'
);
}
}

View File

@ -7,7 +7,6 @@
use App\Models\Expense;
use App\Services\Admin\Finance\ExpenseService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
@ -26,46 +25,28 @@ public function index(): Response
public function store(ExpenseRequest $request): RedirectResponse
{
try {
$this->service->create($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengeluaran berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.expenses.index');
return $this->handleAction(
fn () => $this->service->create($request->validated()),
'Pengeluaran berhasil ditambahkan.',
'admin.finance.expenses.index'
);
}
public function update(ExpenseRequest $request, Expense $expense): RedirectResponse
{
try {
$this->service->update($expense, $request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengeluaran berhasil diperbarui.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.expenses.index');
return $this->handleAction(
fn () => $this->service->update($expense, $request->validated()),
'Pengeluaran berhasil diperbarui.',
'admin.finance.expenses.index'
);
}
public function destroy(Expense $expense): RedirectResponse
{
try {
$this->service->delete($expense);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pengeluaran berhasil dihapus.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.finance.expenses.index');
return $this->handleAction(
fn () => $this->service->delete($expense),
'Pengeluaran berhasil dihapus.',
'admin.finance.expenses.index'
);
}
}

View File

@ -7,7 +7,6 @@
use App\Models\User;
use App\Services\Admin\HR\EmployeeService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
@ -31,18 +30,11 @@ public function create(): Response
public function store(EmployeeRequest $request): RedirectResponse
{
try {
$this->service->create($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pegawai berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.employees.index');
return $this->handleAction(
fn () => $this->service->create($request->validated()),
'Pegawai berhasil ditambahkan.',
'admin.hr.employees.index'
);
}
public function edit(User $employee): Response
@ -54,66 +46,38 @@ public function edit(User $employee): Response
public function update(EmployeeRequest $request, User $employee): RedirectResponse
{
try {
$this->service->update($employee, $request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pegawai berhasil diperbarui.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.employees.index');
return $this->handleAction(
fn () => $this->service->update($employee, $request->validated()),
'Pegawai berhasil diperbarui.',
'admin.hr.employees.index'
);
}
public function destroy(User $employee): RedirectResponse
{
try {
$this->service->delete($employee);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Pegawai berhasil dihapus.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.employees.index');
return $this->handleAction(
fn () => $this->service->delete($employee),
'Pegawai berhasil dihapus.',
'admin.hr.employees.index'
);
}
public function toggleActive(User $employee): RedirectResponse
{
try {
$this->service->toggleActive($employee);
$this->service->toggleActive($employee);
$status = $employee->fresh()->is_active ? 'diaktifkan' : 'dinonaktifkan';
$status = $employee->fresh()->is_active ? 'diaktifkan' : 'dinonaktifkan';
Inertia::flash('toast', ['type' => 'success', 'message' => "Pegawai berhasil {$status}."]);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
Inertia::flash('toast', ['type' => 'success', 'message' => "Pegawai berhasil {$status}."]);
return to_route('admin.hr.employees.index');
}
public function resetPassword(User $employee): RedirectResponse
{
try {
$this->service->resetPassword($employee);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Kata sandi pegawai berhasil direset ke kata sandi default.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.employees.index');
return $this->handleAction(
fn () => $this->service->resetPassword($employee),
'Kata sandi pegawai berhasil direset ke kata sandi default.',
'admin.hr.employees.index'
);
}
}

View File

@ -7,7 +7,6 @@
use App\Models\LeaveRequest;
use App\Services\Admin\HR\LeaveRequestService;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
use Inertia\Response;
@ -26,72 +25,46 @@ public function index(): Response
public function store(LeaveRequestRequest $request): RedirectResponse
{
try {
$this->service->create($request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Permohonan cuti berhasil ditambahkan.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.leave-requests.index');
return $this->handleAction(
fn () => $this->service->create($request->validated()),
'Permohonan cuti berhasil ditambahkan.',
'admin.hr.leave-requests.index'
);
}
public function update(LeaveRequestRequest $request, LeaveRequest $leaveRequest): RedirectResponse
{
try {
$this->service->update($leaveRequest, $request->validated());
Inertia::flash('toast', ['type' => 'success', 'message' => 'Permohonan cuti berhasil diperbarui.']);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.leave-requests.index');
return $this->handleAction(
fn () => $this->service->update($leaveRequest, $request->validated()),
'Permohonan cuti berhasil diperbarui.',
'admin.hr.leave-requests.index'
);
}
public function destroy(LeaveRequest $leaveRequest): RedirectResponse
{
try {
$this->service->delete($leaveRequest);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Permohonan cuti berhasil dihapus.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.leave-requests.index');
return $this->handleAction(
fn () => $this->service->delete($leaveRequest),
'Permohonan cuti berhasil dihapus.',
'admin.hr.leave-requests.index'
);
}
public function approve(LeaveRequest $leaveRequest): RedirectResponse
{
try {
$this->service->approve($leaveRequest);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Permohonan cuti berhasil disetujui.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.leave-requests.index');
return $this->handleAction(
fn () => $this->service->approve($leaveRequest),
'Permohonan cuti berhasil disetujui.',
'admin.hr.leave-requests.index'
);
}
public function reject(LeaveRequest $leaveRequest): RedirectResponse
{
try {
$this->service->reject($leaveRequest);
Inertia::flash('toast', ['type' => 'success', 'message' => 'Permohonan cuti berhasil ditolak.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route('admin.hr.leave-requests.index');
return $this->handleAction(
fn () => $this->service->reject($leaveRequest),
'Permohonan cuti berhasil ditolak.',
'admin.hr.leave-requests.index'
);
}
}

View File

@ -2,7 +2,24 @@
namespace App\Http\Controllers;
use Illuminate\Http\RedirectResponse;
use Illuminate\Validation\ValidationException;
use Inertia\Inertia;
abstract class Controller
{
//
protected function handleAction(callable $action, string $successMessage, string $redirectRoute): RedirectResponse
{
try {
$action();
Inertia::flash('toast', ['type' => 'success', 'message' => $successMessage]);
} catch (ValidationException $e) {
$firstError = collect($e->errors())->flatten()->first();
Inertia::flash('toast', ['type' => 'error', 'message' => $firstError ?? 'Terjadi kesalahan.']);
} catch (\Exception $e) {
Inertia::flash('toast', ['type' => 'error', 'message' => $e->getMessage()]);
}
return to_route($redirectRoute);
}
}

View File

@ -8,6 +8,7 @@
use App\Models\Expense;
use App\Services\S3PresignedService;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\Cache;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Str;
use Illuminate\Validation\ValidationException;
@ -46,9 +47,14 @@ private function formatExpense(Expense $expense): array
$s3Key = $media->getPath();
}
$cacheKey = "expense_receipt_{$media->id}";
$receiptUrl = Cache::remember($cacheKey, now()->addMinutes(55), function () use ($s3Key) {
return $this->s3Service->getTemporaryUrl($s3Key);
});
return $expense->toArray() + [
'receipt_key' => $s3Key,
'receipt_url' => $this->s3Service->getTemporaryUrl($s3Key),
'receipt_url' => $receiptUrl,
];
}
@ -130,6 +136,11 @@ public function update(Expense $expense, array $data): Expense
}
if ($data['receipt_key'] !== $currentKey) {
// Invalidate old receipt cache
if ($currentMedia) {
Cache::forget("expense_receipt_{$currentMedia->id}");
}
$expense->clearMediaCollection('receipts');
if (! empty($data['receipt_key'])) {
@ -150,6 +161,12 @@ public function delete(Expense $expense): bool
$newBalance = $cashAccount->balance + $expense->amount;
$cashAccount->update(['balance' => $newBalance]);
// Invalidate receipt cache
$media = $expense->getFirstMedia('receipts');
if ($media) {
Cache::forget("expense_receipt_{$media->id}");
}
$expense->clearMediaCollection('receipts');
return $expense->delete();