refactor: implement and utilize eloquent scopes for common model status queries across the application

This commit is contained in:
Yoga Pangestu 2026-06-22 12:15:08 +07:00
parent 5119dd7208
commit b88c2b4701
14 changed files with 90 additions and 47 deletions

View File

@ -3,7 +3,6 @@
namespace App\Console\Commands;
use App\Enums\EmployeeStatus;
use App\Enums\LeaveRequestStatus;
use App\Enums\PayrollAdjustmentType;
use App\Enums\PayrollPeriodStatus;
use App\Models\Attendance;
@ -50,9 +49,8 @@ public function handle(): int
$skippedDuplicate = 0;
foreach ($employees as $employee) {
$hasLeave = LeaveRequest::query()
$hasLeave = LeaveRequest::approved()
->where('employee_id', $employee->id)
->where('status', LeaveRequestStatus::APPROVED)
->whereDate('start_date', '<=', $date)
->whereDate('end_date', '>=', $date)
->exists();

View File

@ -2,7 +2,6 @@
namespace App\Http\Controllers\Admin\Hr;
use App\Enums\LeaveRequestStatus;
use App\Enums\Permission;
use App\Http\Controllers\Concerns\FlashesEntityMessage;
use App\Http\Controllers\Concerns\ParsesDataTableQuery;
@ -31,9 +30,8 @@ public function index(Request $request): Response
$hasPending = false;
if ($user?->employee !== null) {
$hasPending = LeaveRequest::query()
$hasPending = LeaveRequest::pending()
->where('employee_id', $user->employee->id)
->where('status', LeaveRequestStatus::PENDING)
->exists();
}

View File

@ -2,9 +2,6 @@
namespace App\Http\Middleware;
use App\Enums\CuttingStatus;
use App\Enums\EmployeeAdvanceStatus;
use App\Enums\LeaveRequestStatus;
use App\Models\Cutting;
use App\Models\EmployeeAdvance;
use App\Models\LeaveRequest;
@ -85,8 +82,7 @@ private function pendingLeaveRequests(Request $request): int
return 0;
}
return LeaveRequest::query()
->where('status', LeaveRequestStatus::PENDING)
return LeaveRequest::pending()
->count();
}
@ -98,8 +94,7 @@ private function pendingEmployeeAdvances(Request $request): int
return 0;
}
return EmployeeAdvance::query()
->where('status', EmployeeAdvanceStatus::PENDING)
return EmployeeAdvance::pending()
->count();
}
@ -111,8 +106,7 @@ private function pendingCuttings(Request $request): int
return 0;
}
return Cutting::query()
->where('status', CuttingStatus::COMPLETED)
return Cutting::completed()
->count();
}
@ -124,8 +118,7 @@ private function pendingOwnerVerifications(Request $request): int
return 0;
}
return Cutting::query()
->where('status', CuttingStatus::PENDING_VERIFICATION)
return Cutting::pendingVerification()
->count();
}
}

View File

@ -7,6 +7,8 @@
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -72,4 +74,28 @@ public function statusLabel(): Attribute
get: fn () => $this->status->label(),
);
}
#[Scope]
public function inProgress(Builder $query): void
{
$query->where('status', CuttingStatus::IN_PROGRESS);
}
#[Scope]
public function completed(Builder $query): void
{
$query->where('status', CuttingStatus::COMPLETED);
}
#[Scope]
public function pendingVerification(Builder $query): void
{
$query->where('status', CuttingStatus::PENDING_VERIFICATION);
}
#[Scope]
public function verified(Builder $query): void
{
$query->where('status', CuttingStatus::VERIFIED);
}
}

View File

@ -7,6 +7,8 @@
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -135,4 +137,22 @@ public function statusLabel(): Attribute
get: fn () => $this->status?->label(),
);
}
#[Scope]
public function pending(Builder $query): void
{
$query->where('status', EmployeeAdvanceStatus::PENDING);
}
#[Scope]
public function approved(Builder $query): void
{
$query->where('status', EmployeeAdvanceStatus::APPROVED);
}
#[Scope]
public function paid(Builder $query): void
{
$query->where('status', EmployeeAdvanceStatus::PAID);
}
}

View File

@ -7,6 +7,8 @@
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -120,4 +122,16 @@ public function statusLabel(): Attribute
get: fn () => $this->status?->label(),
);
}
#[Scope]
public function pending(Builder $query): void
{
$query->where('status', LeaveRequestStatus::PENDING);
}
#[Scope]
public function approved(Builder $query): void
{
$query->where('status', LeaveRequestStatus::APPROVED);
}
}

View File

@ -9,6 +9,8 @@
use App\Models\Concerns\InteractsWithActivityLog;
use Illuminate\Database\Eloquent\Attributes\Appends;
use Illuminate\Database\Eloquent\Attributes\Guarded;
use Illuminate\Database\Eloquent\Attributes\Scope;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Database\Eloquent\Casts\Attribute;
use Illuminate\Database\Eloquent\Factories\HasFactory;
use Illuminate\Database\Eloquent\Model;
@ -135,4 +137,10 @@ public function subtotalFormatted(): Attribute
get: fn () => 'Rp '.number_format($this->subtotal, 0, ',', '.'),
);
}
#[Scope]
public function completed(Builder $query): void
{
$query->where('status', OrderStatus::COMPLETED);
}
}

View File

@ -26,8 +26,7 @@ public function __construct(
*/
public function outstandingSummary(?User $user = null): array
{
$query = EmployeeAdvance::query()
->where('status', EmployeeAdvanceStatus::APPROVED)
$query = EmployeeAdvance::approved()
->when(! $user->hasAnyRole([Role::OWNER->value, Role::DEVELOPER->value, Role::DIREKTUR->value]), fn (Builder $query) => $query->where('employee_id', $user->employee?->id ?? -1));
$outstandingAmount = (int) $query->sum('amount');

View File

@ -2,7 +2,6 @@
namespace App\Services\Hr;
use App\Enums\LeaveRequestStatus;
use App\Models\Attendance;
use App\Models\Employee;
use App\Models\LeaveRequest;
@ -61,9 +60,8 @@ public function todayAttendanceForEmployee(Employee $employee): ?array
public function isOnLeaveToday(Employee $employee): bool
{
return LeaveRequest::query()
return LeaveRequest::approved()
->where('employee_id', $employee->id)
->where('status', LeaveRequestStatus::APPROVED)
->whereDate('start_date', '<=', today())
->whereDate('end_date', '>=', today())
->exists();

View File

@ -55,9 +55,8 @@ public function create(array $validated, User $user): void
{
$employee = $this->resolveAuthEmployee($user);
$hasPending = LeaveRequest::query()
$hasPending = LeaveRequest::pending()
->where('employee_id', $employee->id)
->where('status', LeaveRequestStatus::PENDING)
->exists();
if ($hasPending) {

View File

@ -2,7 +2,6 @@
namespace App\Services\Manage;
use App\Enums\CuttingStatus;
use App\Enums\PriceType;
use App\Models\CuttingResultPrice;
@ -13,7 +12,7 @@ public function resolve(int $productVariantId, PriceType $priceType): ?CuttingRe
return CuttingResultPrice::query()
->where('product_variant_id', $productVariantId)
->where('price_type', $priceType)
->whereHas('cutting', fn ($query) => $query->where('status', CuttingStatus::VERIFIED))
->whereHas('cutting', fn ($query) => $query->verified())
->join('cuttings', 'cutting_result_prices.cutting_id', '=', 'cuttings.id')
->orderByDesc('cuttings.created_at')
->select('cutting_result_prices.*')

View File

@ -87,7 +87,7 @@ public function getInProgressCuttings(User $user): Collection
'results.productVariant.product:id,name',
'results.productVariant:id,product_id,name',
])
->where('status', CuttingStatus::IN_PROGRESS)
->inProgress()
->latest()
->get()
->each(function (Cutting $cutting) use ($user): void {
@ -115,7 +115,7 @@ public function getCompletedCuttings(User $user): Collection
'results.productVariant.product:id,name',
'results.productVariant:id,product_id,name',
])
->where('status', CuttingStatus::COMPLETED)
->completed()
->latest()
->get()
->each(function (Cutting $cutting) use ($user): void {

View File

@ -34,7 +34,7 @@ public function getPendingVerificationCuttings(User $user): Collection
'results.productVariant.product:id,name',
'results.productVariant:id,product_id,name',
])
->where('status', CuttingStatus::COMPLETED)
->completed()
->latest()
->get()
->each(function (Cutting $cutting): void {
@ -58,7 +58,7 @@ public function getPendingApprovalCuttings(User $user): Collection
'results.productVariant:id,product_id,name',
'resultPrices.productVariant:id,product_id,name',
])
->where('status', CuttingStatus::PENDING_VERIFICATION)
->pendingVerification()
->latest()
->get()
->each(function (Cutting $cutting): void {

View File

@ -3,7 +3,6 @@
namespace App\Services\System;
use App\Enums\CuttingStatus;
use App\Enums\EmployeeAdvanceStatus;
use App\Enums\EmploymentStatus;
use App\Enums\OrderChannel;
use App\Enums\OrderStatus;
@ -134,8 +133,7 @@ public function getTopSuppliers(): array
public function getTopCustomers(): array
{
return Order::query()
->where('status', OrderStatus::COMPLETED)
return Order::completed()
->join('customers', 'orders.customer_id', '=', 'customers.id')
->selectRaw('customers.name, SUM(orders.total_amount) as total_amount, COUNT(orders.id) as order_count')
->groupBy('customers.id', 'customers.name')
@ -274,13 +272,11 @@ public function getOrderStats(): array
public function getRevenueSummary(): array
{
$data = Order::query()
->where('status', OrderStatus::COMPLETED)
$data = Order::completed()
->selectRaw('SUM(total_amount) as total_revenue, SUM(discount) as total_discount, SUM(shipping_cost) as total_shipping, COUNT(*) as total_orders, AVG(total_amount) as avg_order')
->first();
$totalMarketplaceFees = Order::query()
->where('status', OrderStatus::COMPLETED)
$totalMarketplaceFees = Order::completed()
->whereNotNull('marketplace_settings_snapshot')
->get()
->sum(fn ($order) => (int) ($order->marketplace_settings_snapshot['total_fee_amount'] ?? 0));
@ -298,8 +294,7 @@ public function getRevenueSummary(): array
public function getMarketplaceSummary(): array
{
$marketplaceOrders = Order::query()
->where('status', OrderStatus::COMPLETED)
$marketplaceOrders = Order::completed()
->whereIn('channel', [OrderChannel::SHOPEE, OrderChannel::TIKTOK])
->whereNotNull('marketplace_settings_snapshot')
->get();
@ -378,18 +373,15 @@ public function getMonthlyExpenses(Carbon $startOfMonth, Carbon $endOfMonth): ar
public function getKasbonSummary(): array
{
$pending = EmployeeAdvance::query()
->where('status', EmployeeAdvanceStatus::PENDING)
$pending = EmployeeAdvance::pending()
->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')
->first();
$approved = EmployeeAdvance::query()
->where('status', EmployeeAdvanceStatus::APPROVED)
$approved = EmployeeAdvance::approved()
->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')
->first();
$paid = EmployeeAdvance::query()
->where('status', EmployeeAdvanceStatus::PAID)
$paid = EmployeeAdvance::paid()
->selectRaw('COUNT(*) as count, COALESCE(SUM(amount), 0) as total')
->first();
@ -530,8 +522,7 @@ public function getMonthlyRevenueTrend(): array
$start = Carbon::create($month['year'], $month['month'], 1)->startOfMonth();
$end = $start->copy()->endOfMonth();
$data = Order::query()
->where('status', OrderStatus::COMPLETED)
$data = Order::completed()
->whereBetween('created_at', [$start, $end])
->selectRaw('COALESCE(SUM(total_amount), 0) as total, COUNT(*) as count')
->first();