Compare commits

...

3 Commits

Author SHA1 Message Date
Yoga Pangestu
5d11741f1d feat: enhance attendance retrieval by filtering employees based on roles with attendance view permissions
Some checks are pending
linter / quality (push) Waiting to run
tests / ci (8.3) (push) Waiting to run
tests / ci (8.4) (push) Waiting to run
tests / ci (8.5) (push) Waiting to run
2026-07-16 15:05:56 +07:00
Yoga Pangestu
735b7fa9ed feat: update attendance and cash overview methods to support date range filtering for improved analysis 2026-07-16 13:28:36 +07:00
Yoga Pangestu
b3f59708a6 refactor: remove 'direktur' role from push notifications in multiple services for clarity 2026-07-16 12:33:28 +07:00
7 changed files with 50 additions and 20 deletions

View File

@ -26,10 +26,10 @@ public function index(Request $request): Response
'start_date' => $request->query('start_date', ''), 'start_date' => $request->query('start_date', ''),
'end_date' => $request->query('end_date', ''), 'end_date' => $request->query('end_date', ''),
], ],
'attendance' => $this->analysisService->getAttendance(), 'attendance' => $this->analysisService->getAttendance($startDate, $endDate),
'myAttendance' => $user ? $this->analysisService->getMyAttendance($user, $startDate, $endDate) : null, 'myAttendance' => $user ? $this->analysisService->getMyAttendance($user, $startDate, $endDate) : null,
'isManager' => $this->analysisService->isManager($user), 'isManager' => $this->analysisService->isManager($user),
'cashOverview' => $this->analysisService->getCashOverview(), 'cashOverview' => $this->analysisService->getCashOverview($startDate, $endDate),
'rawMaterialStock' => $this->analysisService->getRawMaterialStock(), 'rawMaterialStock' => $this->analysisService->getRawMaterialStock(),
'productStock' => $this->analysisService->getProductStock(), 'productStock' => $this->analysisService->getProductStock(),
'revenueSummary' => $this->analysisService->getRevenueSummary($startDate, $endDate), 'revenueSummary' => $this->analysisService->getRevenueSummary($startDate, $endDate),

View File

@ -278,7 +278,7 @@ private function notifyOwner(string $typeLabel, string $body, string $url): void
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel}", "📦 {$typeLabel}",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$url, $url,
); );
} }

View File

@ -234,7 +234,7 @@ public function createVariantAndDraft(array $validated, User $user): array
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
'🆕 Varian Baru Ditambahkan', '🆕 Varian Baru Ditambahkan',
"{$user->name} menambahkan varian \"{$price->variant}\" ke bahan baku \"{$rawMaterial->name}\".", "{$user->name} menambahkan varian \"{$price->variant}\" ke bahan baku \"{$rawMaterial->name}\".",
['owner', 'developer', 'direktur'], ['owner', 'developer'],
route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]), route('admin.master.raw_materials.index', ['search_id' => $rawMaterial->id]),
); );
@ -694,7 +694,7 @@ private function notifyForPendingRequest(User $user, string $typeLabel, string $
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel} Menunggu Persetujuan Owner", "📦 {$typeLabel} Menunggu Persetujuan Owner",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$ownerUrl, $ownerUrl,
); );

View File

@ -551,7 +551,7 @@ private function notifyForPendingRequest(User $user, string $typeLabel, string $
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel} Menunggu Persetujuan Owner", "📦 {$typeLabel} Menunggu Persetujuan Owner",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$ownerUrl, $ownerUrl,
); );

View File

@ -619,7 +619,7 @@ private function notifyOwner(string $typeLabel, string $body, string $url): void
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel}", "📦 {$typeLabel}",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$url, $url,
); );
} }
@ -634,7 +634,7 @@ private function notifyForPendingRequest(User $user, string $typeLabel, string $
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel} Menunggu Persetujuan Owner", "📦 {$typeLabel} Menunggu Persetujuan Owner",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$ownerUrl, $ownerUrl,
); );

View File

@ -236,7 +236,7 @@ private function notifyOwner(string $typeLabel, string $body, string $url): void
$this->pushNotificationService->sendToRoles( $this->pushNotificationService->sendToRoles(
"📦 {$typeLabel}", "📦 {$typeLabel}",
$body, $body,
['owner', 'developer', 'direktur'], ['owner', 'developer'],
$url, $url,
); );
} }

View File

@ -4,6 +4,7 @@
use App\Enums\EmployeeAdvanceStatus; use App\Enums\EmployeeAdvanceStatus;
use App\Enums\OrderStatus; use App\Enums\OrderStatus;
use App\Enums\Permission;
use App\Enums\PriceType; use App\Enums\PriceType;
use App\Enums\ProductStockQuality; use App\Enums\ProductStockQuality;
use App\Enums\Role; use App\Enums\Role;
@ -21,22 +22,32 @@
use App\Models\RawMaterialPrice; use App\Models\RawMaterialPrice;
use App\Models\User; use App\Models\User;
use Carbon\Carbon; use Carbon\Carbon;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB; use Illuminate\Support\Facades\DB;
class AnalysisService class AnalysisService
{ {
public function getAttendance(): array public function getAttendance(?Carbon $startDate = null, ?Carbon $endDate = null): array
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$isSuper = $user?->hasAnyRole(['developer', 'owner', 'direktur']) ?? false; $isSuper = $user?->hasAnyRole(['developer', 'owner', 'direktur']) ?? false;
$attendanceRoles = collect(Role::cases())
->filter(fn (Role $role) => in_array(Permission::ATTENDANCES_VIEW, $role->permissions()))
->map(fn (Role $role) => $role->value)
->values()
->toArray();
$employeeQuery = Employee::query(); $employeeQuery = Employee::query();
$attendanceQuery = Attendance::query()->where('attendance_date', Carbon::today()); $attendanceQuery = Attendance::query();
$leaveRequestQuery = LeaveRequest::query() $leaveRequestQuery = LeaveRequest::query()->approved();
->approved()
->where('start_date', '<=', Carbon::today()) if ($startDate && $endDate) {
->where('end_date', '>=', Carbon::today()); $attendanceQuery->whereBetween('attendance_date', [$startDate, $endDate]);
$leaveRequestQuery->where('start_date', '<=', $endDate)->where('end_date', '>=', $startDate);
$employeeQuery->where('join_date', '<=', $endDate);
}
if (! $isSuper) { if (! $isSuper) {
$employeeId = $user?->employee?->id; $employeeId = $user?->employee?->id;
@ -45,6 +56,7 @@ public function getAttendance(): array
$leaveRequestQuery->where('employee_id', $employeeId); $leaveRequestQuery->where('employee_id', $employeeId);
} }
$employeeQuery->whereHas('user.roles', fn ($q) => $q->whereIn('name', $attendanceRoles));
$totalEmployees = $employeeQuery->count(); $totalEmployees = $employeeQuery->count();
$present = $attendanceQuery->distinct('employee_id')->count('employee_id'); $present = $attendanceQuery->distinct('employee_id')->count('employee_id');
$onLeave = $leaveRequestQuery->distinct('employee_id')->count('employee_id'); $onLeave = $leaveRequestQuery->distinct('employee_id')->count('employee_id');
@ -122,21 +134,39 @@ public function getMyAttendance(User $user, ?Carbon $startDate = null, ?Carbon $
]; ];
} }
public function getCashOverview(): array public function getCashOverview(?Carbon $startDate = null, ?Carbon $endDate = null): array
{ {
/** @var User|null $user */ /** @var User|null $user */
$user = auth()->user(); $user = auth()->user();
$isSuper = $user?->hasAnyRole(['developer', 'owner', 'direktur']) ?? false; $isSuper = $user?->hasAnyRole(['developer', 'owner', 'direktur']) ?? false;
$totalBalanceQuery = CashAccount::query(); /** @var Builder $transactionQuery */
$transactionQuery = CashTransaction::query()->whereDate('created_at', Carbon::today()); $transactionQuery = CashTransaction::query();
if ($startDate && $endDate) {
$transactionQuery->whereBetween('created_at', [$startDate, $endDate]);
}
if (! $isSuper) { if (! $isSuper) {
$transactionQuery->where('created_by_id', $user->id); $transactionQuery->where('created_by_id', $user->id);
$totalBalanceQuery->whereHas('transactions', fn ($q) => $q->where('created_by_id', $user->id));
} }
$totalBalance = $totalBalanceQuery->sum('balance'); $totalBalance = 0;
if ($startDate && $endDate) {
$balanceSummary = (clone $transactionQuery)
->selectRaw("
COALESCE(SUM(CASE WHEN type = 'deposit' THEN amount ELSE 0 END), 0) as total_deposit,
COALESCE(SUM(CASE WHEN type = 'withdrawal' THEN amount ELSE 0 END), 0) as total_withdrawal
")
->first();
$totalBalance = (int) (($balanceSummary->total_deposit ?? 0) - ($balanceSummary->total_withdrawal ?? 0));
} else {
$totalBalanceQuery = CashAccount::query();
if (! $isSuper) {
$totalBalanceQuery->whereHas('transactions', fn ($q) => $q->where('created_by_id', $user->id));
}
$totalBalance = (int) $totalBalanceQuery->sum('balance');
}
$summary = $transactionQuery $summary = $transactionQuery
->selectRaw(" ->selectRaw("
COUNT(*) as total_transactions, COUNT(*) as total_transactions,