From 802c4e36c0abe5c24d50c38f92602b2a7349bfc1 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 21 Jun 2026 00:21:27 +0700 Subject: [PATCH] feat: implement cash transaction management with deposit and withdrawal requests, enhance UI components for better user experience --- .../Admin/Finance/CashController.php | 15 ++++--- .../DepositRequest.php} | 4 +- .../WithdrawRequest.php} | 4 +- app/Models/CashTransaction.php | 15 +++++++ app/Services/Finance/CashService.php | 9 +++- .../js/pages/admin/finance/cash/Index.vue | 44 +++++++++++++------ .../cash/form}/CashTransactionFormModal.vue | 5 +-- .../admin/finance/cash/table}/columns.ts | 16 +++---- .../cash/table}/data-table-actions.vue | 0 resources/js/types/cash.ts | 1 + 10 files changed, 76 insertions(+), 37 deletions(-) rename app/Http/Requests/Admin/Finance/{DepositCashRequest.php => Cash/DepositRequest.php} (90%) rename app/Http/Requests/Admin/Finance/{WithdrawCashRequest.php => Cash/WithdrawRequest.php} (90%) rename resources/js/{components/admin/finance/cash => pages/admin/finance/cash/form}/CashTransactionFormModal.vue (97%) rename resources/js/{components/admin/finance/cash => pages/admin/finance/cash/table}/columns.ts (86%) rename resources/js/{components/admin/finance/cash => pages/admin/finance/cash/table}/data-table-actions.vue (100%) diff --git a/app/Http/Controllers/Admin/Finance/CashController.php b/app/Http/Controllers/Admin/Finance/CashController.php index 722320c..a9806da 100644 --- a/app/Http/Controllers/Admin/Finance/CashController.php +++ b/app/Http/Controllers/Admin/Finance/CashController.php @@ -5,9 +5,9 @@ use App\Http\Controllers\Concerns\FlashesEntityMessage; use App\Http\Controllers\Concerns\ParsesDataTableQuery; use App\Http\Controllers\Controller; -use App\Http\Requests\Admin\Finance\DepositCashRequest; +use App\Http\Requests\Admin\Finance\Cash\DepositRequest; +use App\Http\Requests\Admin\Finance\Cash\WithdrawRequest; use App\Http\Requests\Admin\Finance\UpdateCashTransactionRequest; -use App\Http\Requests\Admin\Finance\WithdrawCashRequest; use App\Models\CashTransaction; use App\Services\Finance\CashService; use Illuminate\Http\RedirectResponse; @@ -26,16 +26,19 @@ public function __construct( public function index(Request $request): Response { $tableQuery = $this->parseDataTableQuery($request); + $referenceType = $request->string('reference_type')->toString(); $cashAccount = $this->cashService->getDefaultAccount(); return Inertia::render('admin/finance/cash/Index', [ 'cashAccount' => $cashAccount, - 'transactions' => $this->cashService->paginateForIndex($cashAccount, $tableQuery), - 'filters' => $this->dataTableFilters($tableQuery), + 'transactions' => $this->cashService->paginateForIndex($cashAccount, $tableQuery, $referenceType), + 'filters' => $this->dataTableFilters($tableQuery, [ + 'reference_type' => $referenceType, + ]), ]); } - public function deposit(DepositCashRequest $request): RedirectResponse + public function deposit(DepositRequest $request): RedirectResponse { $cashAccount = $this->cashService->getDefaultAccount(); @@ -46,7 +49,7 @@ public function deposit(DepositCashRequest $request): RedirectResponse return redirect()->route('admin.finance.cash.index'); } - public function withdraw(WithdrawCashRequest $request): RedirectResponse + public function withdraw(WithdrawRequest $request): RedirectResponse { $cashAccount = $this->cashService->getDefaultAccount(); diff --git a/app/Http/Requests/Admin/Finance/DepositCashRequest.php b/app/Http/Requests/Admin/Finance/Cash/DepositRequest.php similarity index 90% rename from app/Http/Requests/Admin/Finance/DepositCashRequest.php rename to app/Http/Requests/Admin/Finance/Cash/DepositRequest.php index 096909d..820bef0 100644 --- a/app/Http/Requests/Admin/Finance/DepositCashRequest.php +++ b/app/Http/Requests/Admin/Finance/Cash/DepositRequest.php @@ -1,12 +1,12 @@ match ($this->reference_type) { + null => 'bg-blue-100 text-blue-700 hover:bg-blue-100', + Expense::class => 'bg-red-100 text-red-700 hover:bg-red-100', + EmployeeAdvance::class => 'bg-amber-100 text-amber-700 hover:bg-amber-100', + Payroll::class => 'bg-green-100 text-green-700 hover:bg-green-100', + Order::class => 'bg-purple-100 text-purple-700 hover:bg-purple-100', + default => 'bg-gray-100 text-gray-700 hover:bg-gray-100', + }, + ); + } + public function referenceLabel(): Attribute { return Attribute::make( diff --git a/app/Services/Finance/CashService.php b/app/Services/Finance/CashService.php index 1790f14..3aa0354 100644 --- a/app/Services/Finance/CashService.php +++ b/app/Services/Finance/CashService.php @@ -32,7 +32,7 @@ public function getDefaultAccount(): CashAccount /** * @param array{search: string, sort: string, direction: 'asc'|'desc'} $tableQuery */ - public function paginateForIndex(CashAccount $cashAccount, array $tableQuery): LengthAwarePaginator + public function paginateForIndex(CashAccount $cashAccount, array $tableQuery, string $referenceType = ''): LengthAwarePaginator { $query = CashTransaction::query() ->with(['createdBy.profile', 'reference', 'media']) @@ -42,6 +42,13 @@ public function paginateForIndex(CashAccount $cashAccount, array $tableQuery): L $query->where(function (Builder $query) use ($search): void { $query->where('description', 'like', "%{$search}%"); }); + }) + ->when($referenceType !== '', function (Builder $query) use ($referenceType): void { + if ($referenceType === 'manual') { + $query->whereNull('reference_type'); + } else { + $query->where('reference_type', $referenceType); + } }); $this->applySorting($query, $tableQuery['sort'], $tableQuery['direction']); diff --git a/resources/js/pages/admin/finance/cash/Index.vue b/resources/js/pages/admin/finance/cash/Index.vue index 0841714..eb3cb20 100644 --- a/resources/js/pages/admin/finance/cash/Index.vue +++ b/resources/js/pages/admin/finance/cash/Index.vue @@ -2,8 +2,6 @@ import { Head } from '@inertiajs/vue3'; import { ArrowDownCircle, ArrowUpCircle, Wallet } from '@lucide/vue'; import { computed, ref, watch } from 'vue'; -import CashTransactionFormModal from '@/components/admin/finance/cash/CashTransactionFormModal.vue'; -import { createColumns } from '@/components/admin/finance/cash/columns'; import { DataTable } from '@/components/data-table'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; @@ -11,7 +9,9 @@ import { useCan } from '@/composables/useCan'; import { useDataTableQuery, useDataTableQuerySync } from '@/composables/useDataTableQuery'; import AdminLayout from '@/layouts/AdminLayout.vue'; import type { CashAccount, CashTransactionListItem, PaginatedCashTransactions } from '@/types/cash'; -import type { DataTableSort } from '@/types/data-table'; +import type { DataTableFilterDef, DataTableSort } from '@/types/data-table'; +import CashTransactionFormModal from './form/CashTransactionFormModal.vue'; +import { createColumns } from './table/columns'; const props = defineProps<{ cashAccount: CashAccount; @@ -20,6 +20,7 @@ const props = defineProps<{ search: string; sort?: string; direction?: 'asc' | 'desc'; + reference_type?: string; }; }>(); @@ -29,9 +30,10 @@ const formModalOpen = ref(false); const formModalMode = ref<'deposit' | 'withdrawal'>('deposit'); const editingTransaction = ref(null); -const { query, setSearch, setSort, resetFilters, syncFromServer } = useDataTableQuery({ +const { query, setSearch, setSort, setFilter, resetFilters, syncFromServer } = useDataTableQuery({ url: '/admin/finance/cash', initial: { ...props.filters }, + filterKeys: ['reference_type'], }); useDataTableQuerySync(() => props.filters, syncFromServer); @@ -49,6 +51,25 @@ const currentSort = computed(() => { }; }); +const filterDefs = computed(() => [ + { + key: 'reference_type', + label: 'Sumber', + type: 'select', + options: [ + { value: 'manual', label: 'Setor/Tarik Kas' }, + { value: 'App\\Models\\Expense', label: 'Pengeluaran' }, + { value: 'App\\Models\\EmployeeAdvance', label: 'Kasbon Pegawai' }, + { value: 'App\\Models\\Payroll', label: 'Gaji Pegawai' }, + { value: 'App\\Models\\Order', label: 'Pesanan' }, + ], + }, +]); + +const filterValues = computed(() => ({ + reference_type: query.value.reference_type ?? '', +})); + const pagination = computed(() => ({ currentPage: props.transactions.current_page, perPage: props.transactions.per_page, @@ -119,17 +140,14 @@ watch( - + - + diff --git a/resources/js/components/admin/finance/cash/CashTransactionFormModal.vue b/resources/js/pages/admin/finance/cash/form/CashTransactionFormModal.vue similarity index 97% rename from resources/js/components/admin/finance/cash/CashTransactionFormModal.vue rename to resources/js/pages/admin/finance/cash/form/CashTransactionFormModal.vue index d9d92d9..3c10c06 100644 --- a/resources/js/components/admin/finance/cash/CashTransactionFormModal.vue +++ b/resources/js/pages/admin/finance/cash/form/CashTransactionFormModal.vue @@ -168,9 +168,8 @@ const placeholder = computed(() => Keterangan -