diff --git a/app/Services/Admin/Finance/EmployeeAdvanceService.php b/app/Services/Admin/Finance/EmployeeAdvanceService.php index ca98c07..29db41c 100644 --- a/app/Services/Admin/Finance/EmployeeAdvanceService.php +++ b/app/Services/Admin/Finance/EmployeeAdvanceService.php @@ -48,7 +48,9 @@ public function create(array $data): EmployeeAdvance $employee = auth()->user()->employee; if (! $employee) { - throw new \Exception('Anda tidak terdaftar sebagai karyawan.'); + throw ValidationException::withMessages([ + 'amount' => 'Anda tidak terdaftar sebagai karyawan.', + ]); } $employeeAdvance = EmployeeAdvance::create([ @@ -74,6 +76,44 @@ public function create(array $data): EmployeeAdvance public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeAdvance { + if ($employeeAdvance->status === EmployeeAdvanceStatus::PAID) { + throw ValidationException::withMessages([ + 'amount' => 'Kasbon yang sudah dibayar tidak dapat diedit.', + ]); + } + + if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) { + $oldAmount = $employeeAdvance->amount; + $newAmount = $data['amount']; + + if ($oldAmount !== $newAmount) { + $employeeAdvance = DB::transaction(function () use ($employeeAdvance, $data, $oldAmount, $newAmount) { + $this->creditCash( + $oldAmount, + 'Pembatalan kasbon: '.$employeeAdvance->description, + CashTransactionType::DEPOSIT, + ); + + $cashTransaction = $this->debitCash( + $newAmount, + 'Kasbon: '.$data['description'], + CashTransactionType::EMPLOYEE_ADVANCE, + ); + + $employeeAdvance->update([ + 'amount' => $newAmount, + 'description' => $data['description'], + 'due_date' => $data['due_date'], + 'cash_transaction_id' => $cashTransaction->id, + ]); + + return $employeeAdvance; + }); + + return $employeeAdvance; + } + } + $employeeAdvance->update([ 'amount' => $data['amount'], 'description' => $data['description'], @@ -85,30 +125,60 @@ public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeA public function delete(EmployeeAdvance $employeeAdvance): bool { - if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) { - $cashAccount = $this->getCashAccount(); - $newBalance = $cashAccount->balance + $employeeAdvance->amount; - $cashAccount->update(['balance' => $newBalance]); - $employeeAdvance->cashTransaction()->delete(); - } + return DB::transaction(function () use ($employeeAdvance) { + if ($employeeAdvance->status === EmployeeAdvanceStatus::APPROVED && $employeeAdvance->cash_transaction_id) { + $this->creditCash( + $employeeAdvance->amount, + 'Pembatalan kasbon: '.$employeeAdvance->description, + CashTransactionType::DEPOSIT, + ); + $employeeAdvance->cashTransaction()->delete(); + } - return $employeeAdvance->delete(); + if ($employeeAdvance->status === EmployeeAdvanceStatus::PAID) { + $this->creditCash( + $employeeAdvance->amount, + 'Pembatalan kasbon: '.$employeeAdvance->description, + CashTransactionType::DEPOSIT, + ); + + $employeeAdvance->load('payments'); + foreach ($employeeAdvance->payments as $payment) { + if ($payment->cash_transaction_id) { + $this->debitCash( + $payment->amount, + 'Pembatalan pembayaran kasbon: '.$employeeAdvance->description, + CashTransactionType::EXPENSE, + ); + $payment->cashTransaction()->delete(); + } + } + + $employeeAdvance->payments()->delete(); + } + + return $employeeAdvance->delete(); + }); } public function approve(EmployeeAdvance $employeeAdvance): EmployeeAdvance { - $cashTransaction = $this->debitCash( - $employeeAdvance->amount, - 'Kasbon: '.$employeeAdvance->description, - CashTransactionType::EMPLOYEE_ADVANCE - ); + $employeeAdvance = DB::transaction(function () use ($employeeAdvance) { + $cashTransaction = $this->debitCash( + $employeeAdvance->amount, + 'Kasbon: '.$employeeAdvance->description, + CashTransactionType::EMPLOYEE_ADVANCE + ); - $employeeAdvance->update([ - 'cash_transaction_id' => $cashTransaction->id, - 'status' => EmployeeAdvanceStatus::APPROVED, - 'verified_by_id' => auth()->id(), - 'verified_at' => now(), - ]); + $employeeAdvance->update([ + 'cash_transaction_id' => $cashTransaction->id, + 'status' => EmployeeAdvanceStatus::APPROVED, + 'verified_by_id' => auth()->id(), + 'verified_at' => now(), + ]); + + return $employeeAdvance; + }); NotificationService::notify( roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'], @@ -135,7 +205,7 @@ public function pay(EmployeeAdvance $employeeAdvance, int $amount): EmployeeAdva $cashTransaction = $this->creditCash( $amount, 'Pembayaran kasbon: '.$employeeAdvance->description, - CashTransactionType::EMPLOYEE_ADVANCE + CashTransactionType::DEPOSIT ); EmployeeAdvancePayment::create([ diff --git a/app/Services/Admin/Finance/ExpenseService.php b/app/Services/Admin/Finance/ExpenseService.php index c0b86b9..a9f45fc 100644 --- a/app/Services/Admin/Finance/ExpenseService.php +++ b/app/Services/Admin/Finance/ExpenseService.php @@ -2,6 +2,7 @@ namespace App\Services\Admin\Finance; +use App\Enums\CashTransactionType; use App\Models\CashAccount; use App\Models\Expense; use App\Services\Concerns\HandlesCashTransactions; @@ -175,10 +176,11 @@ public function update(Expense $expense, array $data): Expense public function delete(Expense $expense): bool { return DB::transaction(function () use ($expense) { - $cashAccount = CashAccount::firstOrFail(); - - $newBalance = $cashAccount->balance + $expense->amount; - $cashAccount->update(['balance' => $newBalance]); + $this->creditCash( + amount: $expense->amount, + description: 'Pembatalan pengeluaran: '.$expense->description, + type: CashTransactionType::DEPOSIT, + ); // Invalidate receipt cache $media = $expense->getFirstMedia('receipts'); diff --git a/app/Services/Admin/Finance/PayrollPeriodService.php b/app/Services/Admin/Finance/PayrollPeriodService.php index 250a687..a229a57 100644 --- a/app/Services/Admin/Finance/PayrollPeriodService.php +++ b/app/Services/Admin/Finance/PayrollPeriodService.php @@ -2,10 +2,12 @@ namespace App\Services\Admin\Finance; +use App\Enums\CashTransactionType; use App\Enums\PayrollPeriodStatus; use App\Enums\PayrollStatus; use App\Models\Payroll; use App\Models\PayrollPeriod; +use App\Services\Concerns\HandlesCashTransactions; use App\Services\NotificationService; use Illuminate\Contracts\Pagination\LengthAwarePaginator; use Illuminate\Support\Collection; @@ -14,6 +16,8 @@ class PayrollPeriodService { + use HandlesCashTransactions; + private function canViewAll(): bool { return auth()->user()->hasAnyRole(['developer', 'owner', 'direktur', 'admin-toko']); @@ -138,9 +142,10 @@ public function pay(Payroll $payroll): Payroll } $payroll = DB::transaction(function () use ($payroll) { - $cashTransaction = $this->creditCash( + $cashTransaction = $this->debitCash( amount: $payroll->total_amount, description: 'Pembayaran gaji karyawan', + type: CashTransactionType::EXPENSE, ); $payroll->update([ diff --git a/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx b/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx index 8b0e660..142e14c 100644 --- a/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx +++ b/resources/js/pages/admin/finance/cash-account/transaction-columns.tsx @@ -1,7 +1,7 @@ -import type { ColumnDef } from '@tanstack/react-table'; -import { Pencil, Trash2 } from 'lucide-react'; import { ImagePreviewButton } from '@/components/image-preview-button'; import { RowActions } from '@/components/row-actions'; +import type { ColumnDef } from '@tanstack/react-table'; +import { Pencil, Trash2 } from 'lucide-react'; export type CashTransaction = { id: number; @@ -30,23 +30,12 @@ function getTypeLabel(type: string): string { deposit: 'Deposit', withdrawal: 'Withdrawal', expense: 'Pengeluaran', - transfer: 'Transfer', + employee_advance: 'Kasbon', }; return labels[type] ?? type; } -function getReferenceLabel(type: string): string { - const labels: Record = { - 'App\\Models\\Expense': 'Pengeluaran', - 'App\\Models\\Order': 'Penjualan Tunai', - 'App\\Models\\Purchase': 'Belanja', - 'App\\Models\\CashAccount': 'Transfer Kas', - }; - - return labels[type] ?? '-'; -} - type CreateColumnsParams = { handleEdit: (transaction: CashTransaction) => void; handleDeleteClick: (transaction: CashTransaction) => void; diff --git a/resources/js/pages/admin/finance/expense/columns.tsx b/resources/js/pages/admin/finance/expense/columns.tsx index 11b0b5c..b41a9ee 100644 --- a/resources/js/pages/admin/finance/expense/columns.tsx +++ b/resources/js/pages/admin/finance/expense/columns.tsx @@ -69,8 +69,8 @@ export function createExpenseColumns( accessorKey: 'formatted_amount', header: () => Jumlah, cell: ({ row }) => ( - - - {row.getValue('formatted_amount') as string} + + {row.getValue('formatted_amount') as string} ), },