dstpabuaran.com/app/Services/Admin/Finance/EmployeeAdvanceService.php
Yoga Pangestu 95be00c9d1 feat: add push notification functionality and service worker
- Implemented push notifications with a service worker (sw.ts) to handle caching and notifications.
- Added API routes for push subscription and notification management in routes/api.php.
- Created NotificationTest to validate notification service functionality and ensure correct notifications are sent based on user roles and actions.
- Updated Permissions component to manage notification permissions and subscriptions.
- Enhanced CategoryIndex component to highlight categories based on notifications.
- Excluded service worker from TypeScript compilation in tsconfig.json.
- Updated Vite configuration to include service worker in the build process.
2026-08-01 11:36:20 +07:00

194 lines
7.3 KiB
PHP

<?php
namespace App\Services\Admin\Finance;
use App\Enums\CashTransactionType;
use App\Enums\EmployeeAdvanceStatus;
use App\Models\CashAccount;
use App\Models\CashTransaction;
use App\Models\EmployeeAdvance;
use App\Services\NotificationService;
use Illuminate\Contracts\Pagination\LengthAwarePaginator;
use Illuminate\Support\Collection;
use Illuminate\Support\Facades\DB;
use Illuminate\Validation\ValidationException;
class EmployeeAdvanceService
{
public function getAll(): Collection
{
return EmployeeAdvance::select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
->with(['employee.user.userProfile'])
->latest()
->get();
}
public function paginated(int $perPage = 15, string $search = '', string $sort = 'created_at', string $direction = 'desc'): LengthAwarePaginator
{
return EmployeeAdvance::query()
->select('id', 'employee_id', 'amount', 'paid_amount', 'description', 'due_date', 'status', 'created_at')
->with(['employee.user.userProfile'])
->when($search, fn ($q) => $q->where('description', 'like', "%{$search}%"))
->orderBy($sort, $direction)
->paginate($perPage);
}
public function create(array $data): EmployeeAdvance
{
$employeeAdvance = DB::transaction(function () use ($data) {
$cashAccount = CashAccount::firstOrFail();
$employee = auth()->user()->employee;
if (! $employee) {
throw new \Exception('Anda tidak terdaftar sebagai karyawan.');
}
if ($cashAccount->balance < $data['amount']) {
throw ValidationException::withMessages([
'amount' => 'Saldo tidak mencukupi.',
]);
}
$newBalance = $cashAccount->balance - $data['amount'];
$cashAccount->update(['balance' => $newBalance]);
$cashTransaction = CashTransaction::create([
'cash_account_id' => $cashAccount->id,
'created_by_id' => auth()->id(),
'amount' => $data['amount'],
'balance_after' => $newBalance,
'type' => CashTransactionType::EXPENSE,
'description' => 'Kasbon: '.$data['description'],
]);
return EmployeeAdvance::create([
'cash_transaction_id' => $cashTransaction->id,
'employee_id' => $employee->id,
'amount' => $data['amount'],
'description' => $data['description'],
'due_date' => $data['due_date'],
'status' => EmployeeAdvanceStatus::PENDING,
]);
});
$employeeAdvance->load('employee.user');
NotificationService::notify(
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
title: 'Kasbon Baru',
body: 'Kasbon sebesar Rp '.number_format($data['amount'], 0, ',', '.')." dari {$employeeAdvance->employee->name} menunggu persetujuan".' oleh '.auth()->user()->full_name.'.',
url: route('admin.finance.employee-advances.index'),
additionalUser: $employeeAdvance->employee->user ?? null,
);
return $employeeAdvance;
}
public function update(EmployeeAdvance $employeeAdvance, array $data): EmployeeAdvance
{
return DB::transaction(function () use ($employeeAdvance, $data) {
$cashAccount = CashAccount::firstOrFail();
$cashTransaction = $employeeAdvance->cashTransaction;
$oldAmount = $employeeAdvance->amount;
$newAmount = $data['amount'];
$difference = $newAmount - $oldAmount;
if ($difference > 0 && $cashAccount->balance < $difference) {
throw ValidationException::withMessages([
'amount' => 'Saldo tidak mencukupi.',
]);
}
$newBalance = $cashAccount->balance - $difference;
$cashAccount->update(['balance' => $newBalance]);
$cashTransaction->update([
'amount' => $newAmount,
'balance_after' => $newBalance,
'description' => 'Kasbon: '.$data['description'],
]);
$employeeAdvance->update([
'amount' => $newAmount,
'description' => $data['description'],
'due_date' => $data['due_date'],
]);
return $employeeAdvance;
});
}
public function delete(EmployeeAdvance $employeeAdvance): bool
{
return DB::transaction(function () use ($employeeAdvance) {
$cashAccount = CashAccount::firstOrFail();
if ($employeeAdvance->status === EmployeeAdvanceStatus::PAID) {
$newBalance = $cashAccount->balance + $employeeAdvance->amount;
$cashAccount->update(['balance' => $newBalance]);
}
return $employeeAdvance->delete();
});
}
public function approve(EmployeeAdvance $employeeAdvance): EmployeeAdvance
{
$employeeAdvance->update([
'status' => EmployeeAdvanceStatus::APPROVED,
'verified_by_id' => auth()->id(),
'verified_at' => now(),
]);
NotificationService::notify(
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
title: 'Kasbon Disetujui',
body: 'Kasbon sebesar Rp '.number_format($employeeAdvance->amount, 0, ',', '.').' telah disetujui'.' oleh '.auth()->user()->full_name.'.',
url: route('admin.finance.employee-advances.index'),
additionalUser: $employeeAdvance->employee->user ?? null,
);
return $employeeAdvance;
}
public function pay(EmployeeAdvance $employeeAdvance): EmployeeAdvance
{
$employeeAdvance = DB::transaction(function () use ($employeeAdvance) {
$cashAccount = CashAccount::firstOrFail();
$newBalance = $cashAccount->balance + $employeeAdvance->amount;
$cashAccount->update(['balance' => $newBalance]);
$cashTransaction = CashTransaction::create([
'cash_account_id' => $cashAccount->id,
'created_by_id' => auth()->id(),
'amount' => $employeeAdvance->amount,
'balance_after' => $newBalance,
'type' => CashTransactionType::DEPOSIT,
'description' => 'Pembayaran kasbon: '.$employeeAdvance->description,
]);
$employeeAdvance->update([
'status' => EmployeeAdvanceStatus::PAID,
'paid_by_id' => auth()->id(),
'paid_amount' => $employeeAdvance->amount,
'paid_at' => now(),
'repayment_cash_transaction_id' => $cashTransaction->id,
]);
return $employeeAdvance;
});
NotificationService::notify(
roles: ['Owner', 'Developer', 'Direktur', 'Admin Toko'],
title: 'Kasbon Dibayar',
body: 'Kasbon sebesar Rp '.number_format($employeeAdvance->amount, 0, ',', '.').' telah dibayar lunas'.' oleh '.auth()->user()->full_name.'.',
url: route('admin.finance.employee-advances.index'),
additionalUser: $employeeAdvance->employee->user ?? null,
);
return $employeeAdvance;
}
}